@sanity/client 6.28.4-beta.0 → 6.28.4-resources.4
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/dist/_chunks-cjs/config.cjs +27 -16
- package/dist/_chunks-cjs/config.cjs.map +1 -1
- package/dist/_chunks-es/config.js +27 -16
- package/dist/_chunks-es/config.js.map +1 -1
- package/dist/index.browser.cjs +95 -33
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.d.cts +20 -0
- package/dist/index.browser.d.ts +20 -0
- package/dist/index.browser.js +95 -33
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cjs +71 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +72 -19
- package/dist/index.js.map +1 -1
- package/dist/stega.browser.d.cts +20 -0
- package/dist/stega.browser.d.ts +20 -0
- package/dist/stega.d.cts +20 -0
- package/dist/stega.d.ts +20 -0
- package/package.json +20 -20
- package/src/assets/AssetsClient.ts +34 -3
- package/src/config.ts +12 -25
- package/src/data/dataMethods.ts +60 -6
- package/src/data/live.ts +2 -0
- package/src/datasets/DatasetsClient.ts +5 -0
- package/src/projects/ProjectsClient.ts +5 -0
- package/src/types.ts +21 -0
- package/src/validators.ts +31 -0
- package/umd/sanityClient.js +95 -33
- package/umd/sanityClient.min.js +2 -2
package/dist/stega.browser.d.cts
CHANGED
|
@@ -333,6 +333,8 @@ export declare interface ClientConfig {
|
|
|
333
333
|
/** @defaultValue true */
|
|
334
334
|
useCdn?: boolean
|
|
335
335
|
token?: string
|
|
336
|
+
/** @internal */
|
|
337
|
+
'~experimental_resource'?: ClientConfigResource
|
|
336
338
|
/**
|
|
337
339
|
* What perspective to use for the client. See {@link https://www.sanity.io/docs/perspectives|perspective documentation}
|
|
338
340
|
* @remarks
|
|
@@ -393,6 +395,24 @@ export declare interface ClientConfig {
|
|
|
393
395
|
stega?: StegaConfig | boolean
|
|
394
396
|
}
|
|
395
397
|
|
|
398
|
+
declare type ClientConfigResource =
|
|
399
|
+
| {
|
|
400
|
+
type: 'canvas'
|
|
401
|
+
id: string
|
|
402
|
+
}
|
|
403
|
+
| {
|
|
404
|
+
type: 'media-library'
|
|
405
|
+
id: string
|
|
406
|
+
}
|
|
407
|
+
| {
|
|
408
|
+
type: 'dataset'
|
|
409
|
+
id: string
|
|
410
|
+
}
|
|
411
|
+
| {
|
|
412
|
+
type: 'dashboard'
|
|
413
|
+
id: string
|
|
414
|
+
}
|
|
415
|
+
|
|
396
416
|
/** @public */
|
|
397
417
|
export declare class ClientError extends Error {
|
|
398
418
|
response: ErrorProps['response']
|
package/dist/stega.browser.d.ts
CHANGED
|
@@ -333,6 +333,8 @@ export declare interface ClientConfig {
|
|
|
333
333
|
/** @defaultValue true */
|
|
334
334
|
useCdn?: boolean
|
|
335
335
|
token?: string
|
|
336
|
+
/** @internal */
|
|
337
|
+
'~experimental_resource'?: ClientConfigResource
|
|
336
338
|
/**
|
|
337
339
|
* What perspective to use for the client. See {@link https://www.sanity.io/docs/perspectives|perspective documentation}
|
|
338
340
|
* @remarks
|
|
@@ -393,6 +395,24 @@ export declare interface ClientConfig {
|
|
|
393
395
|
stega?: StegaConfig | boolean
|
|
394
396
|
}
|
|
395
397
|
|
|
398
|
+
declare type ClientConfigResource =
|
|
399
|
+
| {
|
|
400
|
+
type: 'canvas'
|
|
401
|
+
id: string
|
|
402
|
+
}
|
|
403
|
+
| {
|
|
404
|
+
type: 'media-library'
|
|
405
|
+
id: string
|
|
406
|
+
}
|
|
407
|
+
| {
|
|
408
|
+
type: 'dataset'
|
|
409
|
+
id: string
|
|
410
|
+
}
|
|
411
|
+
| {
|
|
412
|
+
type: 'dashboard'
|
|
413
|
+
id: string
|
|
414
|
+
}
|
|
415
|
+
|
|
396
416
|
/** @public */
|
|
397
417
|
export declare class ClientError extends Error {
|
|
398
418
|
response: ErrorProps['response']
|
package/dist/stega.d.cts
CHANGED
|
@@ -333,6 +333,8 @@ export declare interface ClientConfig {
|
|
|
333
333
|
/** @defaultValue true */
|
|
334
334
|
useCdn?: boolean
|
|
335
335
|
token?: string
|
|
336
|
+
/** @internal */
|
|
337
|
+
'~experimental_resource'?: ClientConfigResource
|
|
336
338
|
/**
|
|
337
339
|
* What perspective to use for the client. See {@link https://www.sanity.io/docs/perspectives|perspective documentation}
|
|
338
340
|
* @remarks
|
|
@@ -393,6 +395,24 @@ export declare interface ClientConfig {
|
|
|
393
395
|
stega?: StegaConfig | boolean
|
|
394
396
|
}
|
|
395
397
|
|
|
398
|
+
declare type ClientConfigResource =
|
|
399
|
+
| {
|
|
400
|
+
type: 'canvas'
|
|
401
|
+
id: string
|
|
402
|
+
}
|
|
403
|
+
| {
|
|
404
|
+
type: 'media-library'
|
|
405
|
+
id: string
|
|
406
|
+
}
|
|
407
|
+
| {
|
|
408
|
+
type: 'dataset'
|
|
409
|
+
id: string
|
|
410
|
+
}
|
|
411
|
+
| {
|
|
412
|
+
type: 'dashboard'
|
|
413
|
+
id: string
|
|
414
|
+
}
|
|
415
|
+
|
|
396
416
|
/** @public */
|
|
397
417
|
export declare class ClientError extends Error {
|
|
398
418
|
response: ErrorProps['response']
|
package/dist/stega.d.ts
CHANGED
|
@@ -333,6 +333,8 @@ export declare interface ClientConfig {
|
|
|
333
333
|
/** @defaultValue true */
|
|
334
334
|
useCdn?: boolean
|
|
335
335
|
token?: string
|
|
336
|
+
/** @internal */
|
|
337
|
+
'~experimental_resource'?: ClientConfigResource
|
|
336
338
|
/**
|
|
337
339
|
* What perspective to use for the client. See {@link https://www.sanity.io/docs/perspectives|perspective documentation}
|
|
338
340
|
* @remarks
|
|
@@ -393,6 +395,24 @@ export declare interface ClientConfig {
|
|
|
393
395
|
stega?: StegaConfig | boolean
|
|
394
396
|
}
|
|
395
397
|
|
|
398
|
+
declare type ClientConfigResource =
|
|
399
|
+
| {
|
|
400
|
+
type: 'canvas'
|
|
401
|
+
id: string
|
|
402
|
+
}
|
|
403
|
+
| {
|
|
404
|
+
type: 'media-library'
|
|
405
|
+
id: string
|
|
406
|
+
}
|
|
407
|
+
| {
|
|
408
|
+
type: 'dataset'
|
|
409
|
+
id: string
|
|
410
|
+
}
|
|
411
|
+
| {
|
|
412
|
+
type: 'dashboard'
|
|
413
|
+
id: string
|
|
414
|
+
}
|
|
415
|
+
|
|
396
416
|
/** @public */
|
|
397
417
|
export declare class ClientError extends Error {
|
|
398
418
|
response: ErrorProps['response']
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/client",
|
|
3
|
-
"version": "6.28.4-
|
|
3
|
+
"version": "6.28.4-resources.4",
|
|
4
4
|
"description": "Client for retrieving, creating and patching data from Sanity.io",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -125,39 +125,39 @@
|
|
|
125
125
|
"devDependencies": {
|
|
126
126
|
"@edge-runtime/types": "^4.0.0",
|
|
127
127
|
"@edge-runtime/vm": "^5.0.0",
|
|
128
|
-
"@eslint/eslintrc": "^3.
|
|
129
|
-
"@eslint/js": "^9.
|
|
130
|
-
"@rollup/plugin-commonjs": "^28.0.
|
|
131
|
-
"@rollup/plugin-node-resolve": "^16.0.
|
|
128
|
+
"@eslint/eslintrc": "^3.3.0",
|
|
129
|
+
"@eslint/js": "^9.22.0",
|
|
130
|
+
"@rollup/plugin-commonjs": "^28.0.3",
|
|
131
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
132
132
|
"@sanity/client-latest": "npm:@sanity/client@latest",
|
|
133
|
-
"@sanity/pkg-utils": "^7.
|
|
133
|
+
"@sanity/pkg-utils": "^7.1.1",
|
|
134
134
|
"@types/json-diff": "^1.0.3",
|
|
135
135
|
"@types/node": "^22.9.0",
|
|
136
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
137
|
-
"@typescript-eslint/parser": "^8.
|
|
136
|
+
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
|
137
|
+
"@typescript-eslint/parser": "^8.26.1",
|
|
138
138
|
"@vercel/stega": "0.1.2",
|
|
139
|
-
"@vitest/coverage-v8": "3.0.
|
|
140
|
-
"eslint": "^9.
|
|
141
|
-
"eslint-config-prettier": "^10.
|
|
139
|
+
"@vitest/coverage-v8": "3.0.9",
|
|
140
|
+
"eslint": "^9.22.0",
|
|
141
|
+
"eslint-config-prettier": "^10.1.1",
|
|
142
142
|
"eslint-formatter-compact": "^8.40.0",
|
|
143
143
|
"eslint-plugin-prettier": "^5.2.3",
|
|
144
144
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
145
145
|
"faucet": "^0.0.4",
|
|
146
|
-
"globals": "^15.
|
|
146
|
+
"globals": "^15.15.0",
|
|
147
147
|
"happy-dom": "^12.10.3",
|
|
148
148
|
"json-diff": "^1.0.6",
|
|
149
149
|
"ls-engines": "^0.9.3",
|
|
150
|
-
"msw": "^2.7.
|
|
151
|
-
"next": "^15.
|
|
150
|
+
"msw": "^2.7.3",
|
|
151
|
+
"next": "^15.2.3",
|
|
152
152
|
"nock": "^13.5.6",
|
|
153
|
-
"prettier": "^3.5.
|
|
154
|
-
"prettier-plugin-packagejson": "^2.5.
|
|
153
|
+
"prettier": "^3.5.3",
|
|
154
|
+
"prettier-plugin-packagejson": "^2.5.10",
|
|
155
155
|
"rimraf": "^5.0.7",
|
|
156
|
-
"rollup": "^4.
|
|
156
|
+
"rollup": "^4.36.0",
|
|
157
157
|
"sse-channel": "^4.0.0",
|
|
158
|
-
"terser": "^5.
|
|
159
|
-
"typescript": "5.
|
|
160
|
-
"vitest": "3.0.
|
|
158
|
+
"terser": "^5.39.0",
|
|
159
|
+
"typescript": "5.8.2",
|
|
160
|
+
"vitest": "3.0.9"
|
|
161
161
|
},
|
|
162
162
|
"packageManager": "npm@11.0.0",
|
|
163
163
|
"engines": {
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
Any,
|
|
8
8
|
HttpRequest,
|
|
9
9
|
HttpRequestEvent,
|
|
10
|
+
InitializedClientConfig,
|
|
10
11
|
ResponseEvent,
|
|
11
12
|
SanityAssetDocument,
|
|
12
13
|
SanityImageAssetDocument,
|
|
@@ -149,8 +150,7 @@ function _upload(
|
|
|
149
150
|
meta = ['none']
|
|
150
151
|
}
|
|
151
152
|
|
|
152
|
-
const
|
|
153
|
-
const assetEndpoint = assetType === 'image' ? 'images' : 'files'
|
|
153
|
+
const config = client.config()
|
|
154
154
|
const options = optionsFromFile(opts, body)
|
|
155
155
|
const {tag, label, title, description, creditLine, filename, source} = options
|
|
156
156
|
const query: Any = {
|
|
@@ -166,17 +166,48 @@ function _upload(
|
|
|
166
166
|
query.sourceName = source.name
|
|
167
167
|
query.sourceUrl = source.url
|
|
168
168
|
}
|
|
169
|
+
|
|
169
170
|
return _requestObservable(client, httpRequest, {
|
|
170
171
|
tag,
|
|
171
172
|
method: 'POST',
|
|
172
173
|
timeout: options.timeout || 0,
|
|
173
|
-
uri:
|
|
174
|
+
uri: buildAssetUploadUrl(config, assetType),
|
|
174
175
|
headers: options.contentType ? {'Content-Type': options.contentType} : {},
|
|
175
176
|
query,
|
|
176
177
|
body,
|
|
177
178
|
})
|
|
178
179
|
}
|
|
179
180
|
|
|
181
|
+
function buildAssetUploadUrl(config: InitializedClientConfig, assetType: 'image' | 'file'): string {
|
|
182
|
+
const assetTypeEndpoint = assetType === 'image' ? 'images' : 'files'
|
|
183
|
+
|
|
184
|
+
if (config['~experimental_resource']) {
|
|
185
|
+
const {type, id} = config['~experimental_resource']
|
|
186
|
+
switch (type) {
|
|
187
|
+
case 'dataset': {
|
|
188
|
+
throw new Error(
|
|
189
|
+
'Assets are not supported for dataset resources, yet. Configure the client with `{projectId: <projectId>, dataset: <datasetId>}` instead.',
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
case 'canvas': {
|
|
193
|
+
return `/canvases/${id}/assets/${assetTypeEndpoint}`
|
|
194
|
+
}
|
|
195
|
+
case 'media-library': {
|
|
196
|
+
return `/media-libraries/${id}/upload`
|
|
197
|
+
}
|
|
198
|
+
case 'dashboard': {
|
|
199
|
+
return `/dashboards/${id}/assets/${assetTypeEndpoint}`
|
|
200
|
+
}
|
|
201
|
+
default:
|
|
202
|
+
// @ts-expect-error - handle all supported resource types
|
|
203
|
+
throw new Error(`Unsupported resource type: ${type.toString()}`)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const dataset = validators.hasDataset(config)
|
|
208
|
+
return `assets/${assetTypeEndpoint}/${dataset}`
|
|
209
|
+
}
|
|
210
|
+
|
|
180
211
|
function optionsFromFile(opts: Record<string, Any>, file: Any) {
|
|
181
212
|
if (typeof File === 'undefined' || !(file instanceof File)) {
|
|
182
213
|
return opts
|
package/src/config.ts
CHANGED
|
@@ -28,30 +28,15 @@ function validateApiVersion(apiVersion: string) {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const VALID_PERSPECTIVE = /^[a-z0-9_]+$/i
|
|
32
|
-
|
|
33
31
|
/**
|
|
34
32
|
* @internal - it may have breaking changes in any release
|
|
35
33
|
*/
|
|
36
34
|
export function validateApiPerspective(
|
|
37
35
|
perspective: unknown,
|
|
38
36
|
): asserts perspective is ClientPerspective {
|
|
39
|
-
if (Array.isArray(perspective)) {
|
|
40
|
-
if (perspective.includes('raw')) {
|
|
41
|
-
throw new TypeError(
|
|
42
|
-
`Invalid API perspective value: "raw". The raw-perspective can not be combined with other perspectives`,
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const invalid = (Array.isArray(perspective) ? perspective : [perspective]).filter(
|
|
48
|
-
(perspectiveName) =>
|
|
49
|
-
typeof perspectiveName !== 'string' || !VALID_PERSPECTIVE.test(perspectiveName),
|
|
50
|
-
)
|
|
51
|
-
if (invalid.length > 0) {
|
|
52
|
-
const formatted = invalid.map((v) => JSON.stringify(v))
|
|
37
|
+
if (Array.isArray(perspective) && perspective.length > 1 && perspective.includes('raw')) {
|
|
53
38
|
throw new TypeError(
|
|
54
|
-
`Invalid API perspective value
|
|
39
|
+
`Invalid API perspective value: "raw". The raw-perspective can not be combined with other perspectives`,
|
|
55
40
|
)
|
|
56
41
|
}
|
|
57
42
|
}
|
|
@@ -78,7 +63,7 @@ export const initConfig = (
|
|
|
78
63
|
...defaultConfig,
|
|
79
64
|
...specifiedConfig,
|
|
80
65
|
} as InitializedClientConfig
|
|
81
|
-
const projectBased = newConfig.useProjectHostname
|
|
66
|
+
const projectBased = newConfig.useProjectHostname && !newConfig['~experimental_resource']
|
|
82
67
|
|
|
83
68
|
if (typeof Promise === 'undefined') {
|
|
84
69
|
const helpUrl = generateHelpUrl('js-client-promise-polyfill')
|
|
@@ -89,6 +74,10 @@ export const initConfig = (
|
|
|
89
74
|
throw new Error('Configuration must contain `projectId`')
|
|
90
75
|
}
|
|
91
76
|
|
|
77
|
+
if (newConfig['~experimental_resource']) {
|
|
78
|
+
validate.resourceConfig(newConfig)
|
|
79
|
+
}
|
|
80
|
+
|
|
92
81
|
if (typeof newConfig.perspective !== 'undefined') {
|
|
93
82
|
validateApiPerspective(newConfig.perspective)
|
|
94
83
|
}
|
|
@@ -123,11 +112,9 @@ export const initConfig = (
|
|
|
123
112
|
const isLocalhost = isBrowser && isLocal(window.location.hostname)
|
|
124
113
|
|
|
125
114
|
const hasToken = Boolean(newConfig.token)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (withCredentials && hasToken) {
|
|
115
|
+
if (newConfig.withCredentials && hasToken) {
|
|
129
116
|
warnings.printCredentialedTokenWarning()
|
|
130
|
-
withCredentials = false
|
|
117
|
+
newConfig.withCredentials = false
|
|
131
118
|
}
|
|
132
119
|
|
|
133
120
|
if (isBrowser && isLocalhost && hasToken && newConfig.ignoreBrowserTokenWarning !== true) {
|
|
@@ -154,12 +141,12 @@ export const initConfig = (
|
|
|
154
141
|
newConfig.apiVersion = `${newConfig.apiVersion}`.replace(/^v/, '')
|
|
155
142
|
newConfig.isDefaultApi = newConfig.apiHost === defaultConfig.apiHost
|
|
156
143
|
|
|
157
|
-
if (newConfig.useCdn === true && withCredentials) {
|
|
144
|
+
if (newConfig.useCdn === true && newConfig.withCredentials) {
|
|
158
145
|
warnings.printCdnAndWithCredentialsWarning()
|
|
159
146
|
}
|
|
160
147
|
|
|
161
148
|
// If `useCdn` is undefined, we treat it as `true`
|
|
162
|
-
newConfig.useCdn = newConfig.useCdn !== false && !withCredentials
|
|
149
|
+
newConfig.useCdn = newConfig.useCdn !== false && !newConfig.withCredentials
|
|
163
150
|
|
|
164
151
|
validateApiVersion(newConfig.apiVersion)
|
|
165
152
|
|
|
@@ -168,7 +155,7 @@ export const initConfig = (
|
|
|
168
155
|
const host = hostParts[1]
|
|
169
156
|
const cdnHost = newConfig.isDefaultApi ? defaultCdnHost : host
|
|
170
157
|
|
|
171
|
-
if (
|
|
158
|
+
if (projectBased) {
|
|
172
159
|
newConfig.url = `${protocol}://${newConfig.projectId}.${host}/v${newConfig.apiVersion}`
|
|
173
160
|
newConfig.cdnUrl = `${protocol}://${newConfig.projectId}.${cdnHost}/v${newConfig.apiVersion}`
|
|
174
161
|
} else {
|
package/src/data/dataMethods.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
HttpRequest,
|
|
18
18
|
HttpRequestEvent,
|
|
19
19
|
IdentifiedSanityDocumentStub,
|
|
20
|
+
InitializedClientConfig,
|
|
20
21
|
InitializedStegaConfig,
|
|
21
22
|
MultipleActionResult,
|
|
22
23
|
MultipleMutationResult,
|
|
@@ -367,6 +368,27 @@ export function _create<R extends Record<string, Any>>(
|
|
|
367
368
|
return _dataRequest(client, httpRequest, 'mutate', {mutations: [mutation]}, opts)
|
|
368
369
|
}
|
|
369
370
|
|
|
371
|
+
const hasDataConfig = (client: SanityClient | ObservableSanityClient) =>
|
|
372
|
+
(client.config().dataset !== undefined && client.config().projectId !== undefined) ||
|
|
373
|
+
client.config()['~experimental_resource'] !== undefined
|
|
374
|
+
const isQuery = (client: SanityClient | ObservableSanityClient, uri: string) =>
|
|
375
|
+
hasDataConfig(client) && uri.startsWith(_getDataUrl(client, 'query'))
|
|
376
|
+
const isMutate = (client: SanityClient | ObservableSanityClient, uri: string) =>
|
|
377
|
+
hasDataConfig(client) && uri.startsWith(_getDataUrl(client, 'mutate'))
|
|
378
|
+
const isDoc = (client: SanityClient | ObservableSanityClient, uri: string) =>
|
|
379
|
+
hasDataConfig(client) && uri.startsWith(_getDataUrl(client, 'doc', ''))
|
|
380
|
+
const isListener = (client: SanityClient | ObservableSanityClient, uri: string) =>
|
|
381
|
+
hasDataConfig(client) && uri.startsWith(_getDataUrl(client, 'listen'))
|
|
382
|
+
const isHistory = (client: SanityClient | ObservableSanityClient, uri: string) =>
|
|
383
|
+
hasDataConfig(client) && uri.startsWith(_getDataUrl(client, 'history', ''))
|
|
384
|
+
const isData = (client: SanityClient | ObservableSanityClient, uri: string) =>
|
|
385
|
+
uri.startsWith('/data/') ||
|
|
386
|
+
isQuery(client, uri) ||
|
|
387
|
+
isMutate(client, uri) ||
|
|
388
|
+
isDoc(client, uri) ||
|
|
389
|
+
isListener(client, uri) ||
|
|
390
|
+
isHistory(client, uri)
|
|
391
|
+
|
|
370
392
|
/**
|
|
371
393
|
* @internal
|
|
372
394
|
*/
|
|
@@ -382,7 +404,7 @@ export function _requestObservable<R>(
|
|
|
382
404
|
// Only the /data endpoint is currently available through API-CDN.
|
|
383
405
|
const canUseCdn =
|
|
384
406
|
typeof options.canUseCdn === 'undefined'
|
|
385
|
-
? ['GET', 'HEAD'].indexOf(options.method || 'GET') >= 0 && uri
|
|
407
|
+
? ['GET', 'HEAD'].indexOf(options.method || 'GET') >= 0 && isData(client, uri)
|
|
386
408
|
: options.canUseCdn
|
|
387
409
|
|
|
388
410
|
let useCdn = (options.useCdn ?? config.useCdn) && canUseCdn
|
|
@@ -397,10 +419,7 @@ export function _requestObservable<R>(
|
|
|
397
419
|
}
|
|
398
420
|
|
|
399
421
|
// GROQ query-only parameters
|
|
400
|
-
if (
|
|
401
|
-
['GET', 'HEAD', 'POST'].indexOf(options.method || 'GET') >= 0 &&
|
|
402
|
-
uri.indexOf('/data/query/') === 0
|
|
403
|
-
) {
|
|
422
|
+
if (['GET', 'HEAD', 'POST'].indexOf(options.method || 'GET') >= 0 && isQuery(client, uri)) {
|
|
404
423
|
const resultSourceMap = options.resultSourceMap ?? config.resultSourceMap
|
|
405
424
|
if (resultSourceMap !== undefined && resultSourceMap !== false) {
|
|
406
425
|
options.query = {resultSourceMap, ...options.query}
|
|
@@ -482,9 +501,15 @@ export function _getDataUrl(
|
|
|
482
501
|
path?: string,
|
|
483
502
|
): string {
|
|
484
503
|
const config = client.config()
|
|
504
|
+
if (config['~experimental_resource']) {
|
|
505
|
+
validators.resourceConfig(config)
|
|
506
|
+
const resourceBase = resourceDataBase(config)
|
|
507
|
+
const uri = path !== undefined ? `${operation}/${path}` : operation
|
|
508
|
+
return `${resourceBase}/${uri}`.replace(/\/($|\?)/, '$1')
|
|
509
|
+
}
|
|
485
510
|
const catalog = validators.hasDataset(config)
|
|
486
511
|
const baseUri = `/${operation}/${catalog}`
|
|
487
|
-
const uri = path ? `${baseUri}/${path}` : baseUri
|
|
512
|
+
const uri = path !== undefined ? `${baseUri}/${path}` : baseUri
|
|
488
513
|
return `/data${uri}`.replace(/\/($|\?)/, '$1')
|
|
489
514
|
}
|
|
490
515
|
|
|
@@ -547,3 +572,32 @@ function _createAbortError(signal?: AbortSignal) {
|
|
|
547
572
|
|
|
548
573
|
return error
|
|
549
574
|
}
|
|
575
|
+
|
|
576
|
+
const resourceDataBase = (config: InitializedClientConfig): string => {
|
|
577
|
+
if (!config['~experimental_resource']) {
|
|
578
|
+
throw new Error('`resource` must be provided to perform resource queries')
|
|
579
|
+
}
|
|
580
|
+
const {type, id} = config['~experimental_resource']
|
|
581
|
+
|
|
582
|
+
switch (type) {
|
|
583
|
+
case 'dataset': {
|
|
584
|
+
const segments = id.split('.')
|
|
585
|
+
if (segments.length !== 2) {
|
|
586
|
+
throw new Error('Dataset ID must be in the format "project.dataset"')
|
|
587
|
+
}
|
|
588
|
+
return `/projects/${segments[0]}/datasets/${segments[1]}`
|
|
589
|
+
}
|
|
590
|
+
case 'canvas': {
|
|
591
|
+
return `/canvases/${id}`
|
|
592
|
+
}
|
|
593
|
+
case 'media-library': {
|
|
594
|
+
return `/media-libraries/${id}`
|
|
595
|
+
}
|
|
596
|
+
case 'dashboard': {
|
|
597
|
+
return `/dashboards/${id}`
|
|
598
|
+
}
|
|
599
|
+
default:
|
|
600
|
+
// @ts-expect-error - handle all supported resource types
|
|
601
|
+
throw new Error(`Unsupported resource type: ${type.toString()}`)
|
|
602
|
+
}
|
|
603
|
+
}
|
package/src/data/live.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
SyncTag,
|
|
13
13
|
} from '../types'
|
|
14
14
|
import {shareReplayLatest} from '../util/shareReplayLatest'
|
|
15
|
+
import * as validate from '../validators'
|
|
15
16
|
import {_getDataUrl} from './dataMethods'
|
|
16
17
|
import {connectEventSource} from './eventsource'
|
|
17
18
|
import {eventSourcePolyfill} from './eventsourcePolyfill'
|
|
@@ -43,6 +44,7 @@ export class LiveClient {
|
|
|
43
44
|
*/
|
|
44
45
|
tag?: string
|
|
45
46
|
} = {}): Observable<LiveEvent> {
|
|
47
|
+
validate.resourceGuard('live', this.#client.config())
|
|
46
48
|
const {
|
|
47
49
|
projectId,
|
|
48
50
|
apiVersion: _apiVersion,
|
|
@@ -70,6 +70,7 @@ export class DatasetsClient {
|
|
|
70
70
|
* @param options - Options for the dataset
|
|
71
71
|
*/
|
|
72
72
|
create(name: string, options?: {aclMode?: DatasetAclMode}): Promise<DatasetResponse> {
|
|
73
|
+
validate.resourceGuard('dataset', this.#client.config())
|
|
73
74
|
return lastValueFrom(
|
|
74
75
|
_modify<DatasetResponse>(this.#client, this.#httpRequest, 'PUT', name, options),
|
|
75
76
|
)
|
|
@@ -82,6 +83,7 @@ export class DatasetsClient {
|
|
|
82
83
|
* @param options - New options for the dataset
|
|
83
84
|
*/
|
|
84
85
|
edit(name: string, options?: {aclMode?: DatasetAclMode}): Promise<DatasetResponse> {
|
|
86
|
+
validate.resourceGuard('dataset', this.#client.config())
|
|
85
87
|
return lastValueFrom(
|
|
86
88
|
_modify<DatasetResponse>(this.#client, this.#httpRequest, 'PATCH', name, options),
|
|
87
89
|
)
|
|
@@ -93,6 +95,7 @@ export class DatasetsClient {
|
|
|
93
95
|
* @param name - Name of the dataset to delete
|
|
94
96
|
*/
|
|
95
97
|
delete(name: string): Promise<{deleted: true}> {
|
|
98
|
+
validate.resourceGuard('dataset', this.#client.config())
|
|
96
99
|
return lastValueFrom(_modify<{deleted: true}>(this.#client, this.#httpRequest, 'DELETE', name))
|
|
97
100
|
}
|
|
98
101
|
|
|
@@ -100,6 +103,7 @@ export class DatasetsClient {
|
|
|
100
103
|
* Fetch a list of datasets for the configured project
|
|
101
104
|
*/
|
|
102
105
|
list(): Promise<DatasetsResponse> {
|
|
106
|
+
validate.resourceGuard('dataset', this.#client.config())
|
|
103
107
|
return lastValueFrom(
|
|
104
108
|
_request<DatasetsResponse>(this.#client, this.#httpRequest, {uri: '/datasets', tag: null}),
|
|
105
109
|
)
|
|
@@ -113,6 +117,7 @@ function _modify<R = unknown>(
|
|
|
113
117
|
name: string,
|
|
114
118
|
options?: {aclMode?: DatasetAclMode},
|
|
115
119
|
) {
|
|
120
|
+
validate.resourceGuard('dataset', client.config())
|
|
116
121
|
validate.dataset(name)
|
|
117
122
|
return _request<R>(client, httpRequest, {
|
|
118
123
|
method,
|
|
@@ -3,6 +3,7 @@ import {lastValueFrom, type Observable} from 'rxjs'
|
|
|
3
3
|
import {_request} from '../data/dataMethods'
|
|
4
4
|
import type {ObservableSanityClient, SanityClient} from '../SanityClient'
|
|
5
5
|
import type {HttpRequest, SanityProject} from '../types'
|
|
6
|
+
import * as validate from '../validators'
|
|
6
7
|
|
|
7
8
|
/** @internal */
|
|
8
9
|
export class ObservableProjectsClient {
|
|
@@ -24,6 +25,7 @@ export class ObservableProjectsClient {
|
|
|
24
25
|
list(options?: {
|
|
25
26
|
includeMembers?: boolean
|
|
26
27
|
}): Observable<SanityProject[] | Omit<SanityProject, 'members'>[]> {
|
|
28
|
+
validate.resourceGuard('projects', this.#client.config())
|
|
27
29
|
const uri = options?.includeMembers === false ? '/projects?includeMembers=false' : '/projects'
|
|
28
30
|
return _request<SanityProject[]>(this.#client, this.#httpRequest, {uri})
|
|
29
31
|
}
|
|
@@ -34,6 +36,7 @@ export class ObservableProjectsClient {
|
|
|
34
36
|
* @param projectId - ID of the project to fetch
|
|
35
37
|
*/
|
|
36
38
|
getById(projectId: string): Observable<SanityProject> {
|
|
39
|
+
validate.resourceGuard('projects', this.#client.config())
|
|
37
40
|
return _request<SanityProject>(this.#client, this.#httpRequest, {uri: `/projects/${projectId}`})
|
|
38
41
|
}
|
|
39
42
|
}
|
|
@@ -56,6 +59,7 @@ export class ProjectsClient {
|
|
|
56
59
|
list(options?: {includeMembers?: true}): Promise<SanityProject[]>
|
|
57
60
|
list(options?: {includeMembers?: false}): Promise<Omit<SanityProject, 'members'>[]>
|
|
58
61
|
list(options?: {includeMembers?: boolean}): Promise<SanityProject[]> {
|
|
62
|
+
validate.resourceGuard('projects', this.#client.config())
|
|
59
63
|
const uri = options?.includeMembers === false ? '/projects?includeMembers=false' : '/projects'
|
|
60
64
|
return lastValueFrom(_request<SanityProject[]>(this.#client, this.#httpRequest, {uri}))
|
|
61
65
|
}
|
|
@@ -66,6 +70,7 @@ export class ProjectsClient {
|
|
|
66
70
|
* @param projectId - ID of the project to fetch
|
|
67
71
|
*/
|
|
68
72
|
getById(projectId: string): Promise<SanityProject> {
|
|
73
|
+
validate.resourceGuard('projects', this.#client.config())
|
|
69
74
|
return lastValueFrom(
|
|
70
75
|
_request<SanityProject>(this.#client, this.#httpRequest, {uri: `/projects/${projectId}`}),
|
|
71
76
|
)
|
package/src/types.ts
CHANGED
|
@@ -53,6 +53,24 @@ export type ClientPerspective =
|
|
|
53
53
|
| 'raw'
|
|
54
54
|
| StackablePerspective[]
|
|
55
55
|
|
|
56
|
+
type ClientConfigResource =
|
|
57
|
+
| {
|
|
58
|
+
type: 'canvas'
|
|
59
|
+
id: string
|
|
60
|
+
}
|
|
61
|
+
| {
|
|
62
|
+
type: 'media-library'
|
|
63
|
+
id: string
|
|
64
|
+
}
|
|
65
|
+
| {
|
|
66
|
+
type: 'dataset'
|
|
67
|
+
id: string
|
|
68
|
+
}
|
|
69
|
+
| {
|
|
70
|
+
type: 'dashboard'
|
|
71
|
+
id: string
|
|
72
|
+
}
|
|
73
|
+
|
|
56
74
|
/** @public */
|
|
57
75
|
export interface ClientConfig {
|
|
58
76
|
projectId?: string
|
|
@@ -61,6 +79,9 @@ export interface ClientConfig {
|
|
|
61
79
|
useCdn?: boolean
|
|
62
80
|
token?: string
|
|
63
81
|
|
|
82
|
+
/** @internal */
|
|
83
|
+
'~experimental_resource'?: ClientConfigResource
|
|
84
|
+
|
|
64
85
|
/**
|
|
65
86
|
* What perspective to use for the client. See {@link https://www.sanity.io/docs/perspectives|perspective documentation}
|
|
66
87
|
* @remarks
|
package/src/validators.ts
CHANGED
|
@@ -76,3 +76,34 @@ export const requestTag = (tag: string) => {
|
|
|
76
76
|
|
|
77
77
|
return tag
|
|
78
78
|
}
|
|
79
|
+
|
|
80
|
+
export const resourceConfig = (config: InitializedClientConfig): void => {
|
|
81
|
+
if (!config['~experimental_resource']) {
|
|
82
|
+
throw new Error('`resource` must be provided to perform resource queries')
|
|
83
|
+
}
|
|
84
|
+
const {type, id} = config['~experimental_resource']
|
|
85
|
+
|
|
86
|
+
switch (type) {
|
|
87
|
+
case 'dataset': {
|
|
88
|
+
const segments = id.split('.')
|
|
89
|
+
if (segments.length !== 2) {
|
|
90
|
+
throw new Error('Dataset resource ID must be in the format "project.dataset"')
|
|
91
|
+
}
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
case 'dashboard':
|
|
95
|
+
case 'media-library':
|
|
96
|
+
case 'canvas': {
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
default:
|
|
100
|
+
// @ts-expect-error - handle all supported resource types
|
|
101
|
+
throw new Error(`Unsupported resource type: ${type.toString()}`)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const resourceGuard = (service: string, config: InitializedClientConfig): void => {
|
|
106
|
+
if (config['~experimental_resource']) {
|
|
107
|
+
throw new Error(`\`${service}\` does not support resource-based operations`)
|
|
108
|
+
}
|
|
109
|
+
}
|