@sanity/client 7.1.0-views.0 → 7.1.0-views.1
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 +668 -40
- package/dist/_chunks-cjs/config.cjs +14 -0
- package/dist/_chunks-cjs/config.cjs.map +1 -1
- package/dist/_chunks-cjs/dataMethods.cjs +197 -32
- package/dist/_chunks-cjs/dataMethods.cjs.map +1 -1
- package/dist/_chunks-cjs/isRecord.cjs +6 -0
- package/dist/_chunks-cjs/isRecord.cjs.map +1 -0
- package/dist/_chunks-cjs/resolveEditInfo.cjs +3 -5
- package/dist/_chunks-cjs/resolveEditInfo.cjs.map +1 -1
- package/dist/_chunks-cjs/stegaClean.cjs +4 -0
- package/dist/_chunks-cjs/stegaClean.cjs.map +1 -1
- package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs +2 -5
- package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs.map +1 -1
- package/dist/_chunks-es/config.js +15 -1
- package/dist/_chunks-es/config.js.map +1 -1
- package/dist/_chunks-es/dataMethods.js +200 -33
- package/dist/_chunks-es/dataMethods.js.map +1 -1
- package/dist/_chunks-es/isRecord.js +7 -0
- package/dist/_chunks-es/isRecord.js.map +1 -0
- package/dist/_chunks-es/resolveEditInfo.js +1 -3
- package/dist/_chunks-es/resolveEditInfo.js.map +1 -1
- package/dist/_chunks-es/stegaClean.js +4 -0
- package/dist/_chunks-es/stegaClean.js.map +1 -1
- package/dist/_chunks-es/stegaEncodeSourceMap.js +1 -4
- package/dist/_chunks-es/stegaEncodeSourceMap.js.map +1 -1
- package/dist/index.browser.cjs +1019 -59
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.d.cts +1948 -149
- package/dist/index.browser.d.ts +1948 -149
- package/dist/index.browser.js +1021 -60
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cjs +825 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1948 -149
- package/dist/index.d.ts +1948 -149
- package/dist/index.js +826 -31
- package/dist/index.js.map +1 -1
- package/dist/stega.browser.d.cts +1948 -149
- package/dist/stega.browser.d.ts +1948 -149
- package/dist/stega.d.cts +1948 -149
- package/dist/stega.d.ts +1948 -149
- package/dist/views.cjs +13 -5
- package/dist/views.cjs.map +1 -1
- package/dist/views.d.cts +51 -36
- package/dist/views.d.ts +51 -36
- package/dist/views.js +14 -5
- package/dist/views.js.map +1 -1
- package/package.json +2 -1
- package/src/SanityClient.ts +652 -12
- package/src/agent/actions/AgentActionsClient.ts +29 -2
- package/src/agent/actions/commonTypes.ts +57 -17
- package/src/agent/actions/generate.ts +36 -2
- package/src/agent/actions/patch.ts +136 -0
- package/src/agent/actions/prompt.ts +145 -0
- package/src/agent/actions/transform.ts +105 -7
- package/src/agent/actions/translate.ts +5 -2
- package/src/config.ts +3 -1
- package/src/csm/walkMap.ts +1 -1
- package/src/data/dataMethods.ts +170 -12
- package/src/data/encodeQueryString.ts +1 -1
- package/src/data/eventsource.ts +16 -7
- package/src/data/listen.ts +10 -4
- package/src/data/live.ts +13 -5
- package/src/datasets/DatasetsClient.ts +4 -1
- package/src/defineCreateClient.ts +7 -1
- package/src/http/errors.ts +92 -27
- package/src/http/request.ts +3 -3
- package/src/http/requestOptions.ts +4 -0
- package/src/projects/ProjectsClient.ts +6 -2
- package/src/releases/ReleasesClient.ts +693 -0
- package/src/releases/createRelease.ts +53 -0
- package/src/types.ts +291 -10
- package/src/users/UsersClient.ts +7 -3
- package/src/util/codeFrame.ts +174 -0
- package/src/util/createVersionId.ts +79 -0
- package/src/{csm → util}/isRecord.ts +1 -1
- package/src/validators.ts +23 -1
- package/src/views/index.ts +51 -15
- package/umd/sanityClient.js +1067 -61
- package/umd/sanityClient.min.js +2 -2
|
@@ -2,7 +2,13 @@ import {type Observable} from 'rxjs'
|
|
|
2
2
|
|
|
3
3
|
import {_request} from '../../data/dataMethods'
|
|
4
4
|
import type {ObservableSanityClient, SanityClient} from '../../SanityClient'
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
AgentActionParams,
|
|
7
|
+
AgentActionPath,
|
|
8
|
+
Any,
|
|
9
|
+
HttpRequest,
|
|
10
|
+
IdentifiedSanityDocumentStub,
|
|
11
|
+
} from '../../types'
|
|
6
12
|
import {hasDataset} from '../../validators'
|
|
7
13
|
import type {
|
|
8
14
|
AgentActionAsync,
|
|
@@ -20,6 +26,8 @@ export interface TransformRequestBase extends AgentActionRequestBase {
|
|
|
20
26
|
|
|
21
27
|
/**
|
|
22
28
|
* The source document the transformation will use as input.
|
|
29
|
+
*
|
|
30
|
+
* @see #AgentActionSchema.forcePublishedWrite
|
|
23
31
|
*/
|
|
24
32
|
documentId: string
|
|
25
33
|
|
|
@@ -28,13 +36,15 @@ export interface TransformRequestBase extends AgentActionRequestBase {
|
|
|
28
36
|
* then it is transformed according to the instruction.
|
|
29
37
|
*
|
|
30
38
|
* When omitted, the source document (documentId) is also the target document.
|
|
39
|
+
*
|
|
40
|
+
* @see #AgentActionSchema.forcePublishedWrite
|
|
31
41
|
*/
|
|
32
42
|
targetDocument?: TransformTargetDocument
|
|
33
43
|
|
|
34
44
|
/**
|
|
35
45
|
* Instruct the LLM how to transform the input to th output.
|
|
36
46
|
*
|
|
37
|
-
* String template
|
|
47
|
+
* String template with support for $variable from `instructionParams`.
|
|
38
48
|
*
|
|
39
49
|
* Capped to 2000 characters, after variables has been injected.
|
|
40
50
|
* */
|
|
@@ -134,24 +144,97 @@ export interface TransformRequestBase extends AgentActionRequestBase {
|
|
|
134
144
|
* It is therefor an error to provide conflicting include/exclude across targets (ie, include title in one, and exclude it in another)
|
|
135
145
|
*
|
|
136
146
|
* Default max depth for transform: 12
|
|
147
|
+
*
|
|
148
|
+
* ## Transforming images
|
|
149
|
+
*
|
|
150
|
+
* To transform an existing image, directly target an image asset path.
|
|
151
|
+
*
|
|
152
|
+
* For example, all the following will transform the image into the provided asset:
|
|
153
|
+
* * `target: {path: ['image', 'asset'] }`
|
|
154
|
+
* * `target: {path: 'image', include: ['asset'] }`
|
|
155
|
+
*
|
|
156
|
+
* Image transform can be combined with regular content targets:
|
|
157
|
+
* * `target: [{path: ['image', 'asset'] }, {include: ['title', 'description']}]`
|
|
158
|
+
*
|
|
159
|
+
* Image transform can have per-path instructions, just like any other target paths:
|
|
160
|
+
* * `target: [{path: ['image', 'asset'], instruction: 'Make the sky blue' }`
|
|
161
|
+
*
|
|
137
162
|
* @see AgentActionRequestBase#conditionalPaths
|
|
138
163
|
*/
|
|
139
164
|
target?: TransformTarget | TransformTarget[]
|
|
140
165
|
}
|
|
141
166
|
|
|
142
|
-
/**
|
|
167
|
+
/**
|
|
168
|
+
* @see #AgentActionSchema.forcePublishedWrite
|
|
169
|
+
*
|
|
170
|
+
* @beta
|
|
171
|
+
*/
|
|
143
172
|
export type TransformTargetDocument =
|
|
144
173
|
| {operation: 'edit'; _id: string}
|
|
145
174
|
| {operation: 'create'; _id?: string}
|
|
146
175
|
| {operation: 'createIfNotExists'; _id: string}
|
|
147
176
|
| {operation: 'createOrReplace'; _id: string}
|
|
148
177
|
|
|
149
|
-
/**
|
|
178
|
+
/**
|
|
179
|
+
*
|
|
180
|
+
* @see #TransformOperation
|
|
181
|
+
* @beta
|
|
182
|
+
*/
|
|
183
|
+
export interface ImageDescriptionOperation {
|
|
184
|
+
type: 'image-description'
|
|
185
|
+
/**
|
|
186
|
+
* When omitted, parent image value will be inferred from the arget path.
|
|
187
|
+
*
|
|
188
|
+
* When specified, the `sourcePath` should be a path to an image (or image asset) field:
|
|
189
|
+
* - `['image']`
|
|
190
|
+
* - `['wrapper', 'mainImage']`
|
|
191
|
+
* - `['heroImage', 'asset'] // the asset segment is optional, but supported`
|
|
192
|
+
*/
|
|
193
|
+
sourcePath?: AgentActionPath
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
*
|
|
198
|
+
* ## `set` by default
|
|
199
|
+
* By default, Transform will change the value of every target field in place using a set operation.
|
|
200
|
+
*
|
|
201
|
+
* ## Image description
|
|
202
|
+
*
|
|
203
|
+
* ### Targeting image fields
|
|
204
|
+
* Images can be transformed to a textual description by targeting a `string`, `text` or Portable Text field (`array` with `block`)
|
|
205
|
+
* with `operation: {type: 'image-description'}`.
|
|
206
|
+
*
|
|
207
|
+
* Custom instructions for image description targets will be used to generate the description.
|
|
208
|
+
*
|
|
209
|
+
* Such targets must be a descendant field of an image object.
|
|
210
|
+
*
|
|
211
|
+
* For example:
|
|
212
|
+
* - `target: {path: ['image', 'description'], operation: {type: 'image-description'} }`
|
|
213
|
+
* - `target: {path: ['array', {_key: 'abc'}, 'alt'], operation: {type: 'image-description'} } //assuming the item in the array on the key-ed path is an image`
|
|
214
|
+
* - `target: {path: ['image'], include: ['portableTextField'], operation: {type: 'image-description'}, instruction: 'Use formatting and headings to describe the image in great detail' }`
|
|
215
|
+
*
|
|
216
|
+
* ### Targeting non-image fields
|
|
217
|
+
* If the target image description lives outside an image object, use the `sourcePath` option to specify the path to the image field.
|
|
218
|
+
* `sourcePath` must be an image or image asset field.
|
|
219
|
+
*
|
|
220
|
+
* For example:
|
|
221
|
+
* - `target: {path: ['description'], operation: operation: {type: 'image-description', sourcePath: ['image', 'asset'] }`
|
|
222
|
+
* - `target: {path: ['wrapper', 'title'], operation: {type: 'image-description', sourcePath: ['array', {_key: 'abc'}, 'image'] }`
|
|
223
|
+
* - `target: {path: ['wrapper'], include: ['portableTextField'], operation: {type: 'image-description', sourcePath: ['image', 'asset'] }, instruction: 'Use formatting and headings to describe the image in great detail' }`
|
|
224
|
+
*
|
|
225
|
+
* @beta
|
|
226
|
+
*/
|
|
227
|
+
export type TransformOperation = 'set' | ImageDescriptionOperation
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* @see #TransformOperation
|
|
231
|
+
* @beta
|
|
232
|
+
* */
|
|
150
233
|
export interface TransformTargetInclude extends AgentActionTargetInclude {
|
|
151
234
|
/**
|
|
152
235
|
* Specifies a tailored instruction of this target.
|
|
153
236
|
*
|
|
154
|
-
*
|
|
237
|
+
* String template with support for $variable from `instructionParams`. */
|
|
155
238
|
instruction?: string
|
|
156
239
|
|
|
157
240
|
/**
|
|
@@ -162,14 +245,23 @@ export interface TransformTargetInclude extends AgentActionTargetInclude {
|
|
|
162
245
|
* Fields or array items not on the include list, are implicitly excluded.
|
|
163
246
|
*/
|
|
164
247
|
include?: (AgentActionPathSegment | TransformTargetInclude)[]
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Default: `set`
|
|
251
|
+
* @see #TransformOperation
|
|
252
|
+
*/
|
|
253
|
+
operation?: TransformOperation
|
|
165
254
|
}
|
|
166
255
|
|
|
167
|
-
/**
|
|
256
|
+
/**
|
|
257
|
+
* @see #TransformOperation
|
|
258
|
+
* @beta
|
|
259
|
+
* */
|
|
168
260
|
export interface TransformTarget extends AgentActionTarget {
|
|
169
261
|
/**
|
|
170
262
|
* Specifies a tailored instruction of this target.
|
|
171
263
|
*
|
|
172
|
-
*
|
|
264
|
+
* String template with support for $variable from `instructionParams`.
|
|
173
265
|
* */
|
|
174
266
|
instruction?: string
|
|
175
267
|
|
|
@@ -181,6 +273,12 @@ export interface TransformTarget extends AgentActionTarget {
|
|
|
181
273
|
* Fields or array items not on the include list, are implicitly excluded.
|
|
182
274
|
*/
|
|
183
275
|
include?: (AgentActionPathSegment | TransformTargetInclude)[]
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Default: `set`
|
|
279
|
+
* @see #TransformOperation
|
|
280
|
+
*/
|
|
281
|
+
operation?: TransformOperation
|
|
184
282
|
}
|
|
185
283
|
|
|
186
284
|
/** @beta */
|
|
@@ -27,6 +27,7 @@ export interface TranslateRequestBase extends AgentActionRequestBase {
|
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* The source document the transformation will use as input.
|
|
30
|
+
* @see #AgentActionSchema.forcePublishedWrite
|
|
30
31
|
*/
|
|
31
32
|
documentId: string
|
|
32
33
|
|
|
@@ -35,6 +36,8 @@ export interface TranslateRequestBase extends AgentActionRequestBase {
|
|
|
35
36
|
* then it is translated according to the instruction.
|
|
36
37
|
*
|
|
37
38
|
* When omitted, the source document (documentId) is also the target document.
|
|
39
|
+
*
|
|
40
|
+
* @see #AgentActionSchema.forcePublishedWrite
|
|
38
41
|
*/
|
|
39
42
|
targetDocument?: TransformTargetDocument
|
|
40
43
|
|
|
@@ -105,7 +108,7 @@ export interface TranslateLanguage {
|
|
|
105
108
|
|
|
106
109
|
/** @beta */
|
|
107
110
|
export interface TranslateTargetInclude extends AgentActionTargetInclude {
|
|
108
|
-
/**
|
|
111
|
+
/** String template using $variable from styleGuideParams. */
|
|
109
112
|
styleGuide?: string
|
|
110
113
|
|
|
111
114
|
/**
|
|
@@ -120,7 +123,7 @@ export interface TranslateTargetInclude extends AgentActionTargetInclude {
|
|
|
120
123
|
|
|
121
124
|
/** @beta */
|
|
122
125
|
export interface TranslateTarget extends AgentActionTarget {
|
|
123
|
-
/**
|
|
126
|
+
/** String template using $variable from styleGuideParams. */
|
|
124
127
|
styleGuide?: string
|
|
125
128
|
|
|
126
129
|
/**
|
package/src/config.ts
CHANGED
|
@@ -154,7 +154,9 @@ export const initConfig = (
|
|
|
154
154
|
const protocol = hostParts[0]
|
|
155
155
|
const host = hostParts[1]
|
|
156
156
|
|
|
157
|
-
const cdnURL = newConfig.isDefaultApi
|
|
157
|
+
const cdnURL = newConfig.isDefaultApi
|
|
158
|
+
? `https://${defaultCdnHost}`
|
|
159
|
+
: newConfig.apiCdnHost || newConfig.apiHost
|
|
158
160
|
const cdnURLParts = cdnURL.split('://', 2)
|
|
159
161
|
const cdnProtocol = cdnURLParts[0]
|
|
160
162
|
const cdnHost = cdnURLParts[1]
|
package/src/csm/walkMap.ts
CHANGED
package/src/data/dataMethods.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {getVersionFromId, getVersionId, isDraftId} from '@sanity/client/csm'
|
|
1
2
|
import {from, type MonoTypeOperatorFunction, Observable} from 'rxjs'
|
|
2
3
|
import {combineLatestWith, filter, map} from 'rxjs/operators'
|
|
3
4
|
|
|
@@ -11,6 +12,8 @@ import type {
|
|
|
11
12
|
Any,
|
|
12
13
|
BaseActionOptions,
|
|
13
14
|
BaseMutationOptions,
|
|
15
|
+
CreateVersionAction,
|
|
16
|
+
DiscardVersionAction,
|
|
14
17
|
FirstDocumentIdMutationOptions,
|
|
15
18
|
FirstDocumentMutationOptions,
|
|
16
19
|
HttpRequest,
|
|
@@ -24,11 +27,13 @@ import type {
|
|
|
24
27
|
MutationSelection,
|
|
25
28
|
QueryOptions,
|
|
26
29
|
RawQueryResponse,
|
|
30
|
+
ReplaceVersionAction,
|
|
27
31
|
RequestObservableOptions,
|
|
28
32
|
RequestOptions,
|
|
29
33
|
SanityDocument,
|
|
30
34
|
SingleActionResult,
|
|
31
35
|
SingleMutationResult,
|
|
36
|
+
UnpublishVersionAction,
|
|
32
37
|
} from '../types'
|
|
33
38
|
import {getSelection} from '../util/getSelection'
|
|
34
39
|
import * as validate from '../validators'
|
|
@@ -85,12 +90,19 @@ export function _fetch<R, Q>(
|
|
|
85
90
|
const mapResponse =
|
|
86
91
|
options.filterResponse === false ? (res: Any) => res : (res: Any) => res.result
|
|
87
92
|
|
|
88
|
-
const {cache, next, ...opts} = {
|
|
93
|
+
const {cache, next, useEmulate, connections, ...opts} = {
|
|
89
94
|
// Opt out of setting a `signal` on an internal `fetch` if one isn't provided.
|
|
90
95
|
// This is necessary in React Server Components to avoid opting out of Request Memoization.
|
|
91
96
|
useAbortSignal: typeof options.signal !== 'undefined',
|
|
92
97
|
// Set `resultSourceMap' when stega is enabled, as it's required for encoding.
|
|
93
98
|
resultSourceMap: stega.enabled ? 'withKeyArraySelector' : options.resultSourceMap,
|
|
99
|
+
|
|
100
|
+
// Only use emulate if explicitly asked for
|
|
101
|
+
useEmulate: false,
|
|
102
|
+
|
|
103
|
+
// Having connections is a special case for views
|
|
104
|
+
connections: undefined,
|
|
105
|
+
|
|
94
106
|
...options,
|
|
95
107
|
// Default to not returning the query, unless `filterResponse` is `false`,
|
|
96
108
|
// or `returnQuery` is explicitly set. `true` is the default in Content Lake, so skip if truthy
|
|
@@ -101,7 +113,17 @@ export function _fetch<R, Q>(
|
|
|
101
113
|
? {...opts, fetch: {cache, next}}
|
|
102
114
|
: opts
|
|
103
115
|
|
|
104
|
-
|
|
116
|
+
// Use 'emulate' endpoint for view emulation, otherwise use 'query'
|
|
117
|
+
const endpoint = useEmulate ? 'emulate' : 'query'
|
|
118
|
+
const requestBody = useEmulate
|
|
119
|
+
? {
|
|
120
|
+
query,
|
|
121
|
+
params,
|
|
122
|
+
connections: connections,
|
|
123
|
+
}
|
|
124
|
+
: {query, params}
|
|
125
|
+
|
|
126
|
+
const $request = _dataRequest(config, httpRequest, endpoint, requestBody, reqOpts)
|
|
105
127
|
return stega.enabled
|
|
106
128
|
? $request.pipe(
|
|
107
129
|
combineLatestWith(
|
|
@@ -129,10 +151,36 @@ export function _getDocument<R extends Record<string, Any>>(
|
|
|
129
151
|
config: InitializedClientConfig,
|
|
130
152
|
httpRequest: HttpRequest,
|
|
131
153
|
id: string,
|
|
132
|
-
opts: {signal?: AbortSignal; tag?: string} = {},
|
|
154
|
+
opts: {signal?: AbortSignal; tag?: string; releaseId?: string} = {},
|
|
133
155
|
): Observable<SanityDocument<R> | undefined> {
|
|
156
|
+
const getDocId = () => {
|
|
157
|
+
if (!opts.releaseId) {
|
|
158
|
+
return id
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const versionId = getVersionFromId(id)
|
|
162
|
+
if (!versionId) {
|
|
163
|
+
if (isDraftId(id)) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
`The document ID (\`${id}\`) is a draft, but \`options.releaseId\` is set as \`${opts.releaseId}\``,
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return getVersionId(id, opts.releaseId)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (versionId !== opts.releaseId) {
|
|
173
|
+
throw new Error(
|
|
174
|
+
`The document ID (\`${id}\`) is already a version of \`${versionId}\` release, but this does not match the provided \`options.releaseId\` (\`${opts.releaseId}\`)`,
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return id
|
|
179
|
+
}
|
|
180
|
+
const docId = getDocId()
|
|
181
|
+
|
|
134
182
|
const options = {
|
|
135
|
-
uri: _getDataUrl(config, 'doc',
|
|
183
|
+
uri: _getDataUrl(config, 'doc', docId),
|
|
136
184
|
json: true,
|
|
137
185
|
tag: opts.tag,
|
|
138
186
|
signal: opts.signal,
|
|
@@ -165,6 +213,27 @@ export function _getDocuments<R extends Record<string, Any>>(
|
|
|
165
213
|
)
|
|
166
214
|
}
|
|
167
215
|
|
|
216
|
+
/** @internal */
|
|
217
|
+
export function _getReleaseDocuments<R extends Record<string, Any>>(
|
|
218
|
+
config: InitializedClientConfig,
|
|
219
|
+
httpRequest: HttpRequest,
|
|
220
|
+
releaseId: string,
|
|
221
|
+
opts: BaseMutationOptions = {},
|
|
222
|
+
): Observable<RawQueryResponse<SanityDocument<R>[]>> {
|
|
223
|
+
return _dataRequest(
|
|
224
|
+
config,
|
|
225
|
+
httpRequest,
|
|
226
|
+
'query',
|
|
227
|
+
{
|
|
228
|
+
query: '*[sanity::partOfRelease($releaseId)]',
|
|
229
|
+
params: {
|
|
230
|
+
releaseId,
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
opts,
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
|
|
168
237
|
/** @internal */
|
|
169
238
|
export function _createIfNotExists<R extends Record<string, Any>>(
|
|
170
239
|
config: InitializedClientConfig,
|
|
@@ -201,6 +270,26 @@ export function _createOrReplace<R extends Record<string, Any>>(
|
|
|
201
270
|
return _create<R>(config, httpRequest, doc, 'createOrReplace', options)
|
|
202
271
|
}
|
|
203
272
|
|
|
273
|
+
/** @internal */
|
|
274
|
+
export function _createVersion<R extends Record<string, Any>>(
|
|
275
|
+
config: InitializedClientConfig,
|
|
276
|
+
httpRequest: HttpRequest,
|
|
277
|
+
doc: IdentifiedSanityDocumentStub<R>,
|
|
278
|
+
publishedId: string,
|
|
279
|
+
options?: BaseActionOptions,
|
|
280
|
+
): Observable<SingleActionResult> {
|
|
281
|
+
validators.requireDocumentId('createVersion', doc)
|
|
282
|
+
validators.requireDocumentType('createVersion', doc)
|
|
283
|
+
|
|
284
|
+
const createVersionAction: CreateVersionAction = {
|
|
285
|
+
actionType: 'sanity.action.document.version.create',
|
|
286
|
+
publishedId,
|
|
287
|
+
document: doc,
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return _action(config, httpRequest, createVersionAction, options)
|
|
291
|
+
}
|
|
292
|
+
|
|
204
293
|
/** @internal */
|
|
205
294
|
export function _delete<R extends Record<string, Any>>(
|
|
206
295
|
config: InitializedClientConfig,
|
|
@@ -224,6 +313,58 @@ export function _delete<R extends Record<string, Any>>(
|
|
|
224
313
|
)
|
|
225
314
|
}
|
|
226
315
|
|
|
316
|
+
/** @internal */
|
|
317
|
+
export function _discardVersion(
|
|
318
|
+
config: InitializedClientConfig,
|
|
319
|
+
httpRequest: HttpRequest,
|
|
320
|
+
versionId: string,
|
|
321
|
+
purge: boolean = false,
|
|
322
|
+
options?: BaseActionOptions,
|
|
323
|
+
): Observable<SingleActionResult> {
|
|
324
|
+
const discardVersionAction: DiscardVersionAction = {
|
|
325
|
+
actionType: 'sanity.action.document.version.discard',
|
|
326
|
+
versionId,
|
|
327
|
+
purge,
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return _action(config, httpRequest, discardVersionAction, options)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** @internal */
|
|
334
|
+
export function _replaceVersion<R extends Record<string, Any>>(
|
|
335
|
+
config: InitializedClientConfig,
|
|
336
|
+
httpRequest: HttpRequest,
|
|
337
|
+
doc: IdentifiedSanityDocumentStub<R>,
|
|
338
|
+
options?: BaseActionOptions,
|
|
339
|
+
): Observable<SingleActionResult> {
|
|
340
|
+
validators.requireDocumentId('replaceVersion', doc)
|
|
341
|
+
validators.requireDocumentType('replaceVersion', doc)
|
|
342
|
+
|
|
343
|
+
const replaceVersionAction: ReplaceVersionAction = {
|
|
344
|
+
actionType: 'sanity.action.document.version.replace',
|
|
345
|
+
document: doc,
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return _action(config, httpRequest, replaceVersionAction, options)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** @internal */
|
|
352
|
+
export function _unpublishVersion(
|
|
353
|
+
config: InitializedClientConfig,
|
|
354
|
+
httpRequest: HttpRequest,
|
|
355
|
+
versionId: string,
|
|
356
|
+
publishedId: string,
|
|
357
|
+
options?: BaseActionOptions,
|
|
358
|
+
): Observable<SingleActionResult> {
|
|
359
|
+
const unpublishVersionAction: UnpublishVersionAction = {
|
|
360
|
+
actionType: 'sanity.action.document.version.unpublish',
|
|
361
|
+
versionId,
|
|
362
|
+
publishedId,
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return _action(config, httpRequest, unpublishVersionAction, options)
|
|
366
|
+
}
|
|
367
|
+
|
|
227
368
|
/** @internal */
|
|
228
369
|
export function _mutate<R extends Record<string, Any>>(
|
|
229
370
|
config: InitializedClientConfig,
|
|
@@ -289,11 +430,13 @@ export function _dataRequest(
|
|
|
289
430
|
const isMutation = endpoint === 'mutate'
|
|
290
431
|
const isAction = endpoint === 'actions'
|
|
291
432
|
const isQuery = endpoint === 'query'
|
|
433
|
+
const isEmulate = endpoint === 'emulate'
|
|
292
434
|
|
|
293
435
|
// Check if the query string is within a configured threshold,
|
|
294
436
|
// in which case we can use GET. Otherwise, use POST.
|
|
295
|
-
|
|
296
|
-
const
|
|
437
|
+
// Emulate endpoint always uses POST
|
|
438
|
+
const strQuery = isMutation || isAction || isEmulate ? '' : encodeQueryString(body)
|
|
439
|
+
const useGet = !isMutation && !isAction && !isEmulate && strQuery.length < getQuerySizeLimit
|
|
297
440
|
const stringQuery = useGet ? strQuery : ''
|
|
298
441
|
const returnFirst = options.returnFirst
|
|
299
442
|
const {timeout, token, tag, headers, returnQuery, lastLiveEventId, cacheMode} = options
|
|
@@ -377,6 +520,9 @@ const isQuery = (config: InitializedClientConfig, uri: string) =>
|
|
|
377
520
|
const isViewQuery = (config: InitializedClientConfig, uri: string) =>
|
|
378
521
|
hasDataConfig(config) && uri.startsWith(_getDataUrl(config, 'views'))
|
|
379
522
|
|
|
523
|
+
const isEmulate = (config: InitializedClientConfig, uri: string) =>
|
|
524
|
+
hasDataConfig(config) && uri.startsWith(_getDataUrl(config, 'emulate'))
|
|
525
|
+
|
|
380
526
|
const isMutate = (config: InitializedClientConfig, uri: string) =>
|
|
381
527
|
hasDataConfig(config) && uri.startsWith(_getDataUrl(config, 'mutate'))
|
|
382
528
|
|
|
@@ -396,7 +542,8 @@ const isData = (config: InitializedClientConfig, uri: string) =>
|
|
|
396
542
|
isDoc(config, uri) ||
|
|
397
543
|
isListener(config, uri) ||
|
|
398
544
|
isHistory(config, uri) ||
|
|
399
|
-
isViewQuery(config, uri)
|
|
545
|
+
isViewQuery(config, uri) ||
|
|
546
|
+
isEmulate(config, uri)
|
|
400
547
|
|
|
401
548
|
/**
|
|
402
549
|
* @internal
|
|
@@ -425,8 +572,11 @@ export function _requestObservable<R>(
|
|
|
425
572
|
options.query = {tag: validate.requestTag(tag), ...options.query}
|
|
426
573
|
}
|
|
427
574
|
|
|
428
|
-
// GROQ query-only parameters
|
|
429
|
-
if (
|
|
575
|
+
// GROQ query-only parameters (applies to both query and emulate endpoints)
|
|
576
|
+
if (
|
|
577
|
+
['GET', 'HEAD', 'POST'].indexOf(options.method || 'GET') >= 0 &&
|
|
578
|
+
(isQuery(config, uri) || isEmulate(config, uri))
|
|
579
|
+
) {
|
|
430
580
|
const resultSourceMap = options.resultSourceMap ?? config.resultSourceMap
|
|
431
581
|
if (resultSourceMap !== undefined && resultSourceMap !== false) {
|
|
432
582
|
options.query = {resultSourceMap, ...options.query}
|
|
@@ -486,7 +636,11 @@ export function _requestObservable<R>(
|
|
|
486
636
|
/**
|
|
487
637
|
* @internal
|
|
488
638
|
*/
|
|
489
|
-
export function _request<R>(
|
|
639
|
+
export function _request<R>(
|
|
640
|
+
config: InitializedClientConfig,
|
|
641
|
+
httpRequest: HttpRequest,
|
|
642
|
+
options: Any,
|
|
643
|
+
): Observable<R> {
|
|
490
644
|
const observable = _requestObservable<R>(config, httpRequest, options).pipe(
|
|
491
645
|
filter((event: Any) => event.type === 'response'),
|
|
492
646
|
map((event: Any) => event.body),
|
|
@@ -498,7 +652,11 @@ export function _request<R>(config: InitializedClientConfig, httpRequest: HttpRe
|
|
|
498
652
|
/**
|
|
499
653
|
* @internal
|
|
500
654
|
*/
|
|
501
|
-
export function _getDataUrl(
|
|
655
|
+
export function _getDataUrl(
|
|
656
|
+
config: InitializedClientConfig,
|
|
657
|
+
operation: string,
|
|
658
|
+
path?: string,
|
|
659
|
+
): string {
|
|
502
660
|
if (config['~experimental_resource']) {
|
|
503
661
|
validators.resourceConfig(config)
|
|
504
662
|
const resourceBase = resourceDataBase(config)
|
|
@@ -514,7 +672,7 @@ export function _getDataUrl(config: InitializedClientConfig, operation: string,
|
|
|
514
672
|
/**
|
|
515
673
|
* @internal
|
|
516
674
|
*/
|
|
517
|
-
export function _getUrl(config: InitializedClientConfig, uri: string, canUseCdn = false
|
|
675
|
+
export function _getUrl(config: InitializedClientConfig, uri: string, canUseCdn = false): string {
|
|
518
676
|
const {url, cdnUrl} = config
|
|
519
677
|
const base = canUseCdn ? cdnUrl : url
|
|
520
678
|
return `${base}/${uri.replace(/^\//, '')}`
|
|
@@ -18,7 +18,7 @@ export const encodeQueryString = ({
|
|
|
18
18
|
|
|
19
19
|
// Iterate params, the keys are prefixed with `$` and their values JSON stringified
|
|
20
20
|
for (const [key, value] of Object.entries(params)) {
|
|
21
|
-
searchParams.append(`$${key}`, JSON.stringify(value))
|
|
21
|
+
if (value !== undefined) searchParams.append(`$${key}`, JSON.stringify(value))
|
|
22
22
|
}
|
|
23
23
|
// Options are passed as-is
|
|
24
24
|
for (const [key, value] of Object.entries(opts)) {
|
package/src/data/eventsource.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {defer, isObservable, mergeMap, Observable, of} from 'rxjs'
|
|
2
2
|
|
|
3
|
+
import {formatQueryParseError, isQueryParseError} from '../http/errors'
|
|
3
4
|
import {type Any} from '../types'
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -169,8 +170,10 @@ function connectWithESInstance<EventTypeName extends string>(
|
|
|
169
170
|
}
|
|
170
171
|
if (message.type === 'channelError') {
|
|
171
172
|
// An error occurred. This is different from a network-level error (which will be emitted as 'error').
|
|
172
|
-
// Possible causes are things such as malformed filters, non-existant datasets
|
|
173
|
-
|
|
173
|
+
// Possible causes are things such as malformed filters, non-existant datasets
|
|
174
|
+
// or similar.
|
|
175
|
+
const tag = new URL(es.url).searchParams.get('tag')
|
|
176
|
+
observer.error(new ChannelError(extractErrorMessage(event?.data, tag), event.data))
|
|
174
177
|
return
|
|
175
178
|
}
|
|
176
179
|
if (message.type === 'disconnect') {
|
|
@@ -235,16 +238,22 @@ function parseEvent(
|
|
|
235
238
|
}
|
|
236
239
|
}
|
|
237
240
|
|
|
238
|
-
function extractErrorMessage(err: Any) {
|
|
239
|
-
|
|
241
|
+
function extractErrorMessage(err: Any, tag?: string | null) {
|
|
242
|
+
const error = err.error
|
|
243
|
+
|
|
244
|
+
if (!error) {
|
|
240
245
|
return err.message || 'Unknown listener error'
|
|
241
246
|
}
|
|
242
247
|
|
|
243
|
-
if (
|
|
244
|
-
return
|
|
248
|
+
if (isQueryParseError(error)) {
|
|
249
|
+
return formatQueryParseError(error, tag)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (error.description) {
|
|
253
|
+
return error.description
|
|
245
254
|
}
|
|
246
255
|
|
|
247
|
-
return typeof
|
|
256
|
+
return typeof error === 'string' ? error : JSON.stringify(error, null, 2)
|
|
248
257
|
}
|
|
249
258
|
|
|
250
259
|
function isEmptyObject(data: object) {
|
package/src/data/listen.ts
CHANGED
|
@@ -70,7 +70,7 @@ export function _listen<R extends Record<string, Any> = Record<string, Any>>(
|
|
|
70
70
|
params?: ListenParams,
|
|
71
71
|
opts: ListenOptions = {},
|
|
72
72
|
): Observable<MutationEvent<R> | ListenEvent<R>> {
|
|
73
|
-
const {url, token, withCredentials, requestTagPrefix} = this.config()
|
|
73
|
+
const {url, token, withCredentials, requestTagPrefix, headers: configHeaders} = this.config()
|
|
74
74
|
const tag = opts.tag && requestTagPrefix ? [requestTagPrefix, opts.tag].join('.') : opts.tag
|
|
75
75
|
const options = {...defaults(opts, defaultOptions), tag}
|
|
76
76
|
const listenOpts = pick(options, possibleOptions)
|
|
@@ -88,9 +88,15 @@ export function _listen<R extends Record<string, Any> = Record<string, Any>>(
|
|
|
88
88
|
esOptions.withCredentials = true
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
if (token) {
|
|
92
|
-
esOptions.headers = {
|
|
93
|
-
|
|
91
|
+
if (token || configHeaders) {
|
|
92
|
+
esOptions.headers = {}
|
|
93
|
+
|
|
94
|
+
if (token) {
|
|
95
|
+
esOptions.headers.Authorization = `Bearer ${token}`
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (configHeaders) {
|
|
99
|
+
Object.assign(esOptions.headers, configHeaders)
|
|
94
100
|
}
|
|
95
101
|
}
|
|
96
102
|
|
package/src/data/live.ts
CHANGED
|
@@ -52,6 +52,7 @@ export class LiveClient {
|
|
|
52
52
|
token,
|
|
53
53
|
withCredentials,
|
|
54
54
|
requestTagPrefix,
|
|
55
|
+
headers: configHeaders,
|
|
55
56
|
} = this.#client.config()
|
|
56
57
|
const apiVersion = _apiVersion.replace(/^v/, '')
|
|
57
58
|
if (apiVersion !== 'X' && apiVersion < requiredApiVersion) {
|
|
@@ -76,15 +77,22 @@ export class LiveClient {
|
|
|
76
77
|
url.searchParams.set('includeDrafts', 'true')
|
|
77
78
|
}
|
|
78
79
|
const esOptions: EventSourceInit & {headers?: Record<string, string>} = {}
|
|
79
|
-
if (includeDrafts && token) {
|
|
80
|
-
esOptions.headers = {
|
|
81
|
-
Authorization: `Bearer ${token}`,
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
80
|
if (includeDrafts && withCredentials) {
|
|
85
81
|
esOptions.withCredentials = true
|
|
86
82
|
}
|
|
87
83
|
|
|
84
|
+
if ((includeDrafts && token) || configHeaders) {
|
|
85
|
+
esOptions.headers = {}
|
|
86
|
+
|
|
87
|
+
if (includeDrafts && token) {
|
|
88
|
+
esOptions.headers.Authorization = `Bearer ${token}`
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (configHeaders) {
|
|
92
|
+
Object.assign(esOptions.headers, configHeaders)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
88
96
|
const key = `${url.href}::${JSON.stringify(esOptions)}`
|
|
89
97
|
const existing = eventsCache.get(key)
|
|
90
98
|
|
|
@@ -105,7 +105,10 @@ export class DatasetsClient {
|
|
|
105
105
|
list(): Promise<DatasetsResponse> {
|
|
106
106
|
validate.resourceGuard('dataset', this.#client.config())
|
|
107
107
|
return lastValueFrom(
|
|
108
|
-
_request<DatasetsResponse>(this.#client.config(), this.#httpRequest, {
|
|
108
|
+
_request<DatasetsResponse>(this.#client.config(), this.#httpRequest, {
|
|
109
|
+
uri: '/datasets',
|
|
110
|
+
tag: null,
|
|
111
|
+
}),
|
|
109
112
|
)
|
|
110
113
|
}
|
|
111
114
|
}
|
|
@@ -17,7 +17,13 @@ export {
|
|
|
17
17
|
} from './data/eventsource'
|
|
18
18
|
export * from './data/patch'
|
|
19
19
|
export * from './data/transaction'
|
|
20
|
-
export {
|
|
20
|
+
export {
|
|
21
|
+
ClientError,
|
|
22
|
+
CorsOriginError,
|
|
23
|
+
formatQueryParseError,
|
|
24
|
+
isQueryParseError,
|
|
25
|
+
ServerError,
|
|
26
|
+
} from './http/errors'
|
|
21
27
|
export * from './SanityClient'
|
|
22
28
|
export * from './types'
|
|
23
29
|
|