@sanity/client 7.26.2 → 8.1.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 +63 -341
- package/dist/browserUpload-2tz6Sdqp.js +87 -0
- package/dist/browserUpload-2tz6Sdqp.js.map +1 -0
- package/dist/browserUpload-CwpNx7Vl.js +87 -0
- package/dist/browserUpload-CwpNx7Vl.js.map +1 -0
- package/dist/config-3wiPP-sZ.js +126 -0
- package/dist/config-3wiPP-sZ.js.map +1 -0
- package/dist/csm.d.ts +122 -335
- package/dist/csm.js +79 -91
- package/dist/csm.js.map +1 -1
- package/dist/dist-C9ExSk2R.js +73 -0
- package/dist/dist-C9ExSk2R.js.map +1 -0
- package/dist/dist-Z8cIRxoB.js +69 -0
- package/dist/dist-Z8cIRxoB.js.map +1 -0
- package/dist/index.d.ts +112 -6722
- package/dist/index.js +2950 -2848
- package/dist/index.js.map +1 -1
- package/dist/{index.d.cts → index.node.d.ts} +4529 -5322
- package/dist/index.node.js +3264 -0
- package/dist/index.node.js.map +1 -0
- package/dist/isRecord-Kfmt-nk-.js +7 -0
- package/dist/isRecord-Kfmt-nk-.js.map +1 -0
- package/dist/media-library.d.ts +9 -100
- package/dist/media-library.js +36 -14
- package/dist/media-library.js.map +1 -1
- package/dist/request-BhMuKj0D.js +373 -0
- package/dist/request-BhMuKj0D.js.map +1 -0
- package/dist/request-SnMg7nUX.js +355 -0
- package/dist/request-SnMg7nUX.js.map +1 -0
- package/dist/resolveEditInfo-Cz-smq3a.js +339 -0
- package/dist/resolveEditInfo-Cz-smq3a.js.map +1 -0
- package/dist/rolldown-runtime-vyAXikos.js +9 -0
- package/dist/stega.d.ts +78 -7137
- package/dist/stega.js +27 -20
- package/dist/stega.js.map +1 -1
- package/dist/stegaClean-C18wLWau.js +21 -0
- package/dist/stegaClean-C18wLWau.js.map +1 -0
- package/dist/stegaEncodeSourceMap-DbM2fTN4.js +373 -0
- package/dist/stegaEncodeSourceMap-DbM2fTN4.js.map +1 -0
- package/dist/stegaEncodeSourceMap-YR3NQ3iz.js +163 -0
- package/dist/stegaEncodeSourceMap-YR3NQ3iz.js.map +1 -0
- package/dist/{index.browser.d.cts → types-BODIEY7F.d.ts} +4196 -5258
- package/dist/types-CfGzbXrl.d.ts +108 -0
- package/package.json +80 -142
- package/src/SanityClient.ts +101 -137
- package/src/agent/actions/AgentActionsClient.ts +12 -12
- package/src/agent/actions/commonTypes.ts +2 -1
- package/src/agent/actions/generate.ts +26 -6
- package/src/agent/actions/patch.ts +27 -7
- package/src/agent/actions/prompt.ts +19 -5
- package/src/agent/actions/transform.ts +23 -5
- package/src/agent/actions/translate.ts +23 -5
- package/src/assets/AssetsClient.ts +121 -24
- package/src/csm/applySourceDocuments.ts +5 -5
- package/src/csm/createEditUrl.ts +1 -1
- package/src/csm/draftUtils.ts +23 -5
- package/src/csm/index.ts +2 -2
- package/src/csm/studioPath.ts +2 -1
- package/src/csm/types.ts +8 -2
- package/src/data/dataMethods.ts +784 -349
- package/src/data/eventsource.ts +82 -49
- package/src/data/listen.ts +18 -23
- package/src/data/live.ts +60 -35
- package/src/data/resolveEventSourceFetch.ts +104 -0
- package/src/datasets/DatasetsClient.ts +58 -41
- package/src/defineCreateClient.ts +38 -22
- package/src/functions/FunctionsClient.ts +66 -0
- package/src/functions/invoke.ts +176 -0
- package/src/http/browserMiddleware.ts +7 -1
- package/src/http/browserUpload.ts +163 -0
- package/src/http/errors.ts +61 -6
- package/src/http/nodeMiddleware.ts +94 -30
- package/src/http/request.ts +304 -87
- package/src/http/requestOptions.ts +131 -15
- package/src/{index.browser.ts → index.node.ts} +9 -4
- package/src/index.ts +4 -3
- package/src/mediaLibrary/MediaLibraryVideoClient.ts +27 -12
- package/src/projects/ProjectsClient.ts +18 -16
- package/src/releases/ReleasesClient.ts +38 -33
- package/src/stega/index.ts +1 -2
- package/src/stega/stegaEncodeSourceMap.ts +5 -0
- package/src/stega/types.ts +2 -2
- package/src/types.ts +328 -103
- package/src/users/UsersClient.ts +10 -14
- package/src/util/shareReplayLatest.ts +1 -1
- package/src/validators.ts +1 -1
- package/src/warnings.ts +13 -2
- package/dist/_chunks-cjs/config.cjs +0 -206
- package/dist/_chunks-cjs/config.cjs.map +0 -1
- package/dist/_chunks-cjs/isRecord.cjs +0 -6
- package/dist/_chunks-cjs/isRecord.cjs.map +0 -1
- package/dist/_chunks-cjs/resolveEditInfo.cjs +0 -334
- package/dist/_chunks-cjs/resolveEditInfo.cjs.map +0 -1
- package/dist/_chunks-cjs/stegaClean.cjs +0 -46
- package/dist/_chunks-cjs/stegaClean.cjs.map +0 -1
- package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs +0 -388
- package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs.map +0 -1
- package/dist/_chunks-es/config.js +0 -207
- package/dist/_chunks-es/config.js.map +0 -1
- package/dist/_chunks-es/isRecord.js +0 -7
- package/dist/_chunks-es/isRecord.js.map +0 -1
- package/dist/_chunks-es/resolveEditInfo.js +0 -335
- package/dist/_chunks-es/resolveEditInfo.js.map +0 -1
- package/dist/_chunks-es/stegaClean.js +0 -47
- package/dist/_chunks-es/stegaClean.js.map +0 -1
- package/dist/_chunks-es/stegaEncodeSourceMap.js +0 -389
- package/dist/_chunks-es/stegaEncodeSourceMap.js.map +0 -1
- package/dist/csm.cjs +0 -99
- package/dist/csm.cjs.map +0 -1
- package/dist/csm.d.cts +0 -391
- package/dist/index.browser.cjs +0 -3106
- package/dist/index.browser.cjs.map +0 -1
- package/dist/index.browser.d.ts +0 -6802
- package/dist/index.browser.js +0 -3082
- package/dist/index.browser.js.map +0 -1
- package/dist/index.cjs +0 -2946
- package/dist/index.cjs.map +0 -1
- package/dist/media-library.cjs +0 -20
- package/dist/media-library.cjs.map +0 -1
- package/dist/media-library.d.cts +0 -117
- package/dist/stega.browser.cjs +0 -29
- package/dist/stega.browser.cjs.map +0 -1
- package/dist/stega.browser.d.cts +0 -7200
- package/dist/stega.browser.d.ts +0 -7200
- package/dist/stega.browser.js +0 -24
- package/dist/stega.browser.js.map +0 -1
- package/dist/stega.cjs +0 -29
- package/dist/stega.cjs.map +0 -1
- package/dist/stega.d.cts +0 -7200
- package/src/data/eventsourcePolyfill.ts +0 -7
- package/umd/.gitkeep +0 -1
- package/umd/sanityClient.js +0 -6543
- package/umd/sanityClient.min.js +0 -6
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {type Observable} from 'rxjs'
|
|
2
2
|
|
|
3
|
-
import {_request} from '../data/dataMethods'
|
|
3
|
+
import {_request, _requestObservable} from '../data/dataMethods'
|
|
4
4
|
import type {ObservableSanityClient, SanityClient} from '../SanityClient'
|
|
5
5
|
import type {
|
|
6
6
|
DatasetCreateOptions,
|
|
@@ -29,7 +29,7 @@ export class ObservableDatasetsClient {
|
|
|
29
29
|
* @param options - Options for the dataset, including optional embeddings configuration
|
|
30
30
|
*/
|
|
31
31
|
create(name: string, options?: DatasetCreateOptions): Observable<DatasetResponse> {
|
|
32
|
-
return
|
|
32
|
+
return _modifyObservable<DatasetResponse>(this.#client, this.#httpRequest, 'PUT', name, options)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
|
@@ -39,7 +39,13 @@ export class ObservableDatasetsClient {
|
|
|
39
39
|
* @param options - New options for the dataset
|
|
40
40
|
*/
|
|
41
41
|
edit(name: string, options?: DatasetEditOptions): Observable<DatasetResponse> {
|
|
42
|
-
return
|
|
42
|
+
return _modifyObservable<DatasetResponse>(
|
|
43
|
+
this.#client,
|
|
44
|
+
this.#httpRequest,
|
|
45
|
+
'PATCH',
|
|
46
|
+
name,
|
|
47
|
+
options,
|
|
48
|
+
)
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
/**
|
|
@@ -48,7 +54,7 @@ export class ObservableDatasetsClient {
|
|
|
48
54
|
* @param name - Name of the dataset to delete
|
|
49
55
|
*/
|
|
50
56
|
delete(name: string): Observable<{deleted: true}> {
|
|
51
|
-
return
|
|
57
|
+
return _modifyObservable<{deleted: true}>(this.#client, this.#httpRequest, 'DELETE', name)
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
/**
|
|
@@ -58,13 +64,13 @@ export class ObservableDatasetsClient {
|
|
|
58
64
|
validate.resourceGuard('dataset', this.#client.config())
|
|
59
65
|
const config = this.#client.config()
|
|
60
66
|
const projectId = config.projectId
|
|
61
|
-
let
|
|
67
|
+
let url = '/datasets'
|
|
62
68
|
if (config.useProjectHostname === false) {
|
|
63
|
-
|
|
69
|
+
url = `/projects/${projectId}/datasets`
|
|
64
70
|
}
|
|
65
71
|
|
|
66
|
-
return
|
|
67
|
-
|
|
72
|
+
return _requestObservable<DatasetsResponse>(this.#client, this.#httpRequest, {
|
|
73
|
+
url,
|
|
68
74
|
tag: null,
|
|
69
75
|
})
|
|
70
76
|
}
|
|
@@ -77,8 +83,8 @@ export class ObservableDatasetsClient {
|
|
|
77
83
|
getEmbeddingsSettings(name: string): Observable<EmbeddingsSettings> {
|
|
78
84
|
validate.resourceGuard('dataset', this.#client.config())
|
|
79
85
|
validate.dataset(name)
|
|
80
|
-
return
|
|
81
|
-
|
|
86
|
+
return _requestObservable<EmbeddingsSettings>(this.#client, this.#httpRequest, {
|
|
87
|
+
url: _embeddingsSettingsUri(this.#client, name),
|
|
82
88
|
tag: null,
|
|
83
89
|
})
|
|
84
90
|
}
|
|
@@ -92,9 +98,9 @@ export class ObservableDatasetsClient {
|
|
|
92
98
|
editEmbeddingsSettings(name: string, settings: EmbeddingsSettingsBody): Observable<void> {
|
|
93
99
|
validate.resourceGuard('dataset', this.#client.config())
|
|
94
100
|
validate.dataset(name)
|
|
95
|
-
return
|
|
101
|
+
return _requestObservable<void>(this.#client, this.#httpRequest, {
|
|
96
102
|
method: 'PUT',
|
|
97
|
-
|
|
103
|
+
url: _embeddingsSettingsUri(this.#client, name),
|
|
98
104
|
body: settings,
|
|
99
105
|
tag: null,
|
|
100
106
|
})
|
|
@@ -118,9 +124,7 @@ export class DatasetsClient {
|
|
|
118
124
|
*/
|
|
119
125
|
create(name: string, options?: DatasetCreateOptions): Promise<DatasetResponse> {
|
|
120
126
|
validate.resourceGuard('dataset', this.#client.config())
|
|
121
|
-
return
|
|
122
|
-
_modify<DatasetResponse>(this.#client, this.#httpRequest, 'PUT', name, options),
|
|
123
|
-
)
|
|
127
|
+
return _modify<DatasetResponse>(this.#client, this.#httpRequest, 'PUT', name, options)
|
|
124
128
|
}
|
|
125
129
|
|
|
126
130
|
/**
|
|
@@ -131,9 +135,7 @@ export class DatasetsClient {
|
|
|
131
135
|
*/
|
|
132
136
|
edit(name: string, options?: DatasetEditOptions): Promise<DatasetResponse> {
|
|
133
137
|
validate.resourceGuard('dataset', this.#client.config())
|
|
134
|
-
return
|
|
135
|
-
_modify<DatasetResponse>(this.#client, this.#httpRequest, 'PATCH', name, options),
|
|
136
|
-
)
|
|
138
|
+
return _modify<DatasetResponse>(this.#client, this.#httpRequest, 'PATCH', name, options)
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
/**
|
|
@@ -143,7 +145,7 @@ export class DatasetsClient {
|
|
|
143
145
|
*/
|
|
144
146
|
delete(name: string): Promise<{deleted: true}> {
|
|
145
147
|
validate.resourceGuard('dataset', this.#client.config())
|
|
146
|
-
return
|
|
148
|
+
return _modify<{deleted: true}>(this.#client, this.#httpRequest, 'DELETE', name)
|
|
147
149
|
}
|
|
148
150
|
|
|
149
151
|
/**
|
|
@@ -153,14 +155,15 @@ export class DatasetsClient {
|
|
|
153
155
|
validate.resourceGuard('dataset', this.#client.config())
|
|
154
156
|
const config = this.#client.config()
|
|
155
157
|
const projectId = config.projectId
|
|
156
|
-
let
|
|
158
|
+
let url = '/datasets'
|
|
157
159
|
if (config.useProjectHostname === false) {
|
|
158
|
-
|
|
160
|
+
url = `/projects/${projectId}/datasets`
|
|
159
161
|
}
|
|
160
162
|
|
|
161
|
-
return
|
|
162
|
-
|
|
163
|
-
|
|
163
|
+
return _request<DatasetsResponse>(this.#client, this.#httpRequest, {
|
|
164
|
+
url,
|
|
165
|
+
tag: null,
|
|
166
|
+
})
|
|
164
167
|
}
|
|
165
168
|
|
|
166
169
|
/**
|
|
@@ -171,12 +174,10 @@ export class DatasetsClient {
|
|
|
171
174
|
getEmbeddingsSettings(name: string): Promise<EmbeddingsSettings> {
|
|
172
175
|
validate.resourceGuard('dataset', this.#client.config())
|
|
173
176
|
validate.dataset(name)
|
|
174
|
-
return
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}),
|
|
179
|
-
)
|
|
177
|
+
return _request<EmbeddingsSettings>(this.#client, this.#httpRequest, {
|
|
178
|
+
url: _embeddingsSettingsUri(this.#client, name),
|
|
179
|
+
tag: null,
|
|
180
|
+
})
|
|
180
181
|
}
|
|
181
182
|
|
|
182
183
|
/**
|
|
@@ -188,14 +189,12 @@ export class DatasetsClient {
|
|
|
188
189
|
editEmbeddingsSettings(name: string, settings: EmbeddingsSettingsBody): Promise<void> {
|
|
189
190
|
validate.resourceGuard('dataset', this.#client.config())
|
|
190
191
|
validate.dataset(name)
|
|
191
|
-
return
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}),
|
|
198
|
-
)
|
|
192
|
+
return _request<void>(this.#client, this.#httpRequest, {
|
|
193
|
+
method: 'PUT',
|
|
194
|
+
url: _embeddingsSettingsUri(this.#client, name),
|
|
195
|
+
body: settings,
|
|
196
|
+
tag: null,
|
|
197
|
+
})
|
|
199
198
|
}
|
|
200
199
|
}
|
|
201
200
|
|
|
@@ -210,7 +209,7 @@ function _embeddingsSettingsUri(
|
|
|
210
209
|
return `/datasets/${name}/settings/embeddings`
|
|
211
210
|
}
|
|
212
211
|
|
|
213
|
-
function
|
|
212
|
+
function _modifyObservable<R = unknown>(
|
|
214
213
|
client: SanityClient | ObservableSanityClient,
|
|
215
214
|
httpRequest: HttpRequest,
|
|
216
215
|
method: 'DELETE' | 'PATCH' | 'PUT',
|
|
@@ -220,9 +219,27 @@ function _modify<R = unknown>(
|
|
|
220
219
|
validate.resourceGuard('dataset', client.config())
|
|
221
220
|
validate.dataset(name)
|
|
222
221
|
|
|
222
|
+
return _requestObservable<R>(client, httpRequest, {
|
|
223
|
+
method,
|
|
224
|
+
url: `/datasets/${name}`,
|
|
225
|
+
body: options,
|
|
226
|
+
tag: null,
|
|
227
|
+
})
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function _modify<R = unknown>(
|
|
231
|
+
client: SanityClient | ObservableSanityClient,
|
|
232
|
+
httpRequest: HttpRequest,
|
|
233
|
+
method: 'DELETE' | 'PATCH' | 'PUT',
|
|
234
|
+
name: string,
|
|
235
|
+
options?: DatasetCreateOptions | DatasetEditOptions,
|
|
236
|
+
): Promise<R> {
|
|
237
|
+
validate.resourceGuard('dataset', client.config())
|
|
238
|
+
validate.dataset(name)
|
|
239
|
+
|
|
223
240
|
return _request<R>(client, httpRequest, {
|
|
224
241
|
method,
|
|
225
|
-
|
|
242
|
+
url: `/datasets/${name}`,
|
|
226
243
|
body: options,
|
|
227
244
|
tag: null,
|
|
228
245
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import {defineRequester, type EnvironmentOptions} from './http/request'
|
|
2
|
+
import type {ClientConfig, HttpRequest} from './types'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
import type {Any, ClientConfig, HttpRequest} from './types'
|
|
4
|
+
export {isTimeoutError, type TimeoutErrorLike} from 'get-it'
|
|
5
5
|
|
|
6
6
|
export {validateApiPerspective} from './config'
|
|
7
7
|
export {
|
|
@@ -29,9 +29,6 @@ export {
|
|
|
29
29
|
export * from './SanityClient'
|
|
30
30
|
export * from './types'
|
|
31
31
|
|
|
32
|
-
/** @alpha */
|
|
33
|
-
export {adapter as unstable__adapter, environment as unstable__environment} from 'get-it'
|
|
34
|
-
|
|
35
32
|
/**
|
|
36
33
|
* Create the `requester` and `createClient` exports, that have environment specific middleware for node and browsers
|
|
37
34
|
* @internal
|
|
@@ -40,27 +37,46 @@ export default function defineCreateClientExports<
|
|
|
40
37
|
SanityClientType,
|
|
41
38
|
ClientConfigType extends ClientConfig,
|
|
42
39
|
>(
|
|
43
|
-
|
|
40
|
+
envOptions: EnvironmentOptions,
|
|
44
41
|
ClassConstructor: new (httpRequest: HttpRequest, config: ClientConfigType) => SanityClientType,
|
|
45
42
|
) {
|
|
46
|
-
// Set the http client to use for requests, and its environment specific
|
|
47
|
-
const defaultRequester =
|
|
43
|
+
// Set the http client to use for requests, and its environment specific options
|
|
44
|
+
const defaultRequester = defineRequester(envOptions).observable
|
|
48
45
|
|
|
49
46
|
const createClient = (config: ClientConfigType) => {
|
|
50
|
-
const clientRequester =
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
maxRetries: config.maxRetries,
|
|
58
|
-
retryDelay: config.retryDelay,
|
|
59
|
-
lineage: config.lineage,
|
|
60
|
-
...options,
|
|
61
|
-
} as Any),
|
|
62
|
-
config,
|
|
47
|
+
const {observable: clientRequester, promise: clientRequesterPromise} = defineRequester(
|
|
48
|
+
envOptions,
|
|
49
|
+
{
|
|
50
|
+
ignoreWarnings: config.ignoreWarnings,
|
|
51
|
+
maxRetries: config.maxRetries,
|
|
52
|
+
retryDelay: config.retryDelay,
|
|
53
|
+
},
|
|
63
54
|
)
|
|
55
|
+
// The single transport for the whole client. Resolves a request to its
|
|
56
|
+
// parsed response body as a Promise; the observable client surface wraps
|
|
57
|
+
// this in `new Observable(...)` (see `_observe` in dataMethods).
|
|
58
|
+
// Redirects are surfaced rather than followed unless a request opts in
|
|
59
|
+
// (via the public `maxRedirects` option, translated in `requestOptions`).
|
|
60
|
+
const performRequest = async (options: Parameters<HttpRequest>[0]): Promise<unknown> => {
|
|
61
|
+
const event = await clientRequesterPromise({redirect: 'manual', ...options})
|
|
62
|
+
return event.body
|
|
63
|
+
}
|
|
64
|
+
const httpRequest: HttpRequest = (options, requestHandler) =>
|
|
65
|
+
requestHandler ? requestHandler(options, performRequest) : performRequest(options)
|
|
66
|
+
// Populate `requester` on the initialized config so internal paths
|
|
67
|
+
// (e.g. the asset upload event stream) can reach the underlying transport.
|
|
68
|
+
// `resolveFetch` is threaded onto the config so request building and
|
|
69
|
+
// EventSource fetches can reach the environment's fetch without importing
|
|
70
|
+
// `get-it/node` from a browser-shared module (would leak `undici` into
|
|
71
|
+
// the browser bundle). A caller-supplied `resolveFetch` wins over the
|
|
72
|
+
// environment's — that is the supported way to swap the transport (the
|
|
73
|
+
// test suite injects its mock fetch through it).
|
|
74
|
+
const resolvedConfig = {
|
|
75
|
+
...config,
|
|
76
|
+
requester: clientRequester,
|
|
77
|
+
resolveFetch: config.resolveFetch ?? envOptions.resolveFetch,
|
|
78
|
+
}
|
|
79
|
+
return new ClassConstructor(httpRequest, resolvedConfig)
|
|
64
80
|
}
|
|
65
81
|
|
|
66
82
|
return {requester: defaultRequester, createClient}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {lastValueFrom, type Observable} from 'rxjs'
|
|
2
|
+
|
|
3
|
+
import type {ObservableSanityClient, SanityClient} from '../SanityClient'
|
|
4
|
+
import type {HttpRequest} from '../types'
|
|
5
|
+
import {_invoke, type InvokeFunctionRequest} from './invoke'
|
|
6
|
+
|
|
7
|
+
/** @public */
|
|
8
|
+
export class ObservableFunctionsClient {
|
|
9
|
+
#client: ObservableSanityClient
|
|
10
|
+
#httpRequest: HttpRequest
|
|
11
|
+
constructor(client: ObservableSanityClient, httpRequest: HttpRequest) {
|
|
12
|
+
this.#client = client
|
|
13
|
+
this.#httpRequest = httpRequest
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Invoke a deployed function by its blueprint name.
|
|
18
|
+
*
|
|
19
|
+
* The name is resolved within the stack given by `stackId` on the request or
|
|
20
|
+
* the client config. Passes the function's return value once it finishes.
|
|
21
|
+
*
|
|
22
|
+
* @param functionName - name of the function, as declared in the blueprint
|
|
23
|
+
* @param request - payload and request options
|
|
24
|
+
*/
|
|
25
|
+
invoke<R = unknown>(
|
|
26
|
+
functionName: string,
|
|
27
|
+
request?: InvokeFunctionRequest,
|
|
28
|
+
): Observable<R | undefined> {
|
|
29
|
+
return _invoke<R>(this.#client, this.#httpRequest, functionName, request)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** @public */
|
|
34
|
+
export class FunctionsClient {
|
|
35
|
+
#client: SanityClient
|
|
36
|
+
#httpRequest: HttpRequest
|
|
37
|
+
constructor(client: SanityClient, httpRequest: HttpRequest) {
|
|
38
|
+
this.#client = client
|
|
39
|
+
this.#httpRequest = httpRequest
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Invoke a deployed function by its blueprint name.
|
|
44
|
+
*
|
|
45
|
+
* The name is resolved within the stack given by `stackId` on the request or
|
|
46
|
+
* the client config, which costs one extra request per call. Rejects if the
|
|
47
|
+
* stack has no function by that name, or if the name resolves to anything
|
|
48
|
+
* other than a `sanity.function.pubsub` function.
|
|
49
|
+
*
|
|
50
|
+
* The lookup is scoped to `projectId`, or to `organizationId` when one is set
|
|
51
|
+
* for a stack deployed at organization scope.
|
|
52
|
+
*
|
|
53
|
+
* The request stays open until the function finishes, and resolves with its
|
|
54
|
+
* return value, or `undefined` if it returns nothing. Long-running functions
|
|
55
|
+
* may need an explicit `timeout`.
|
|
56
|
+
*
|
|
57
|
+
* @param functionName - name of the function, as declared in the blueprint
|
|
58
|
+
* @param request - payload and request options
|
|
59
|
+
*/
|
|
60
|
+
invoke<R = unknown>(
|
|
61
|
+
functionName: string,
|
|
62
|
+
request?: InvokeFunctionRequest,
|
|
63
|
+
): Promise<R | undefined> {
|
|
64
|
+
return lastValueFrom(_invoke<R>(this.#client, this.#httpRequest, functionName, request))
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import {defer, map, mergeMap, type Observable} from 'rxjs'
|
|
2
|
+
|
|
3
|
+
import {_requestObservable} from '../data/dataMethods'
|
|
4
|
+
import type {ObservableSanityClient, SanityClient} from '../SanityClient'
|
|
5
|
+
import type {HttpRequest, InitializedClientConfig} from '../types'
|
|
6
|
+
|
|
7
|
+
/** Function resource types in a blueprint are namespaced under this prefix. */
|
|
8
|
+
const FUNCTION_RESOURCE_PREFIX = 'sanity.function.'
|
|
9
|
+
const INVOKABLE_FUNCTION_TYPE = 'sanity.function.pubsub'
|
|
10
|
+
|
|
11
|
+
/** @public */
|
|
12
|
+
export interface InvokeFunctionEvent {
|
|
13
|
+
/**
|
|
14
|
+
* Payload handed to the function.
|
|
15
|
+
* The function receives it as `event.data`.
|
|
16
|
+
*/
|
|
17
|
+
data?: unknown
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** @public */
|
|
21
|
+
export interface InvokeFunctionRequest {
|
|
22
|
+
event?: InvokeFunctionEvent
|
|
23
|
+
/**
|
|
24
|
+
* Stack to resolve the function name against.
|
|
25
|
+
* Overrides `stackId` from the client config.
|
|
26
|
+
*/
|
|
27
|
+
stackId?: string
|
|
28
|
+
/**
|
|
29
|
+
* Organization owning the stack.
|
|
30
|
+
*/
|
|
31
|
+
organizationId?: string
|
|
32
|
+
/**
|
|
33
|
+
* Milliseconds to wait for the function to return.
|
|
34
|
+
*/
|
|
35
|
+
timeout?: number
|
|
36
|
+
/** Abort the invocation. */
|
|
37
|
+
signal?: AbortSignal
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Subset of a stack resource the client needs in order to resolve a name.
|
|
42
|
+
*
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
interface StackResource {
|
|
46
|
+
name: string
|
|
47
|
+
type: string
|
|
48
|
+
/** Provider-side id. For a function resource, the function id. */
|
|
49
|
+
externalId?: string
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type Client = SanityClient | ObservableSanityClient
|
|
53
|
+
|
|
54
|
+
const scopeHeaders = (
|
|
55
|
+
config: InitializedClientConfig,
|
|
56
|
+
request: InvokeFunctionRequest | undefined,
|
|
57
|
+
): Record<string, string> => {
|
|
58
|
+
const organizationId = request?.organizationId || config.organizationId
|
|
59
|
+
if (organizationId) {
|
|
60
|
+
return {
|
|
61
|
+
'X-Sanity-Scope-Type': 'organization',
|
|
62
|
+
'X-Sanity-Scope-Id': organizationId,
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const {projectId} = config
|
|
67
|
+
if (!projectId) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
'`functions.invoke()` requires a `projectId` to be set in the client config, or an ' +
|
|
70
|
+
'`organizationId` for a stack deployed at organization scope',
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
'X-Sanity-Scope-Type': 'project',
|
|
76
|
+
'X-Sanity-Scope-Id': projectId,
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* A per-call `stackId` overrides the one in the client config.
|
|
82
|
+
*/
|
|
83
|
+
const resolveStackId = (
|
|
84
|
+
config: InitializedClientConfig,
|
|
85
|
+
request: InvokeFunctionRequest | undefined,
|
|
86
|
+
): string => {
|
|
87
|
+
const stackId = request?.stackId || config.stackId
|
|
88
|
+
if (!stackId) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
'`functions.invoke()` requires a `stackId`, either in the client config or on the request. ' +
|
|
91
|
+
'Function names are only unique within a stack.',
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return stackId
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The invoke route is keyed by function id, but callers know functions by the
|
|
100
|
+
* name declared in the blueprint. Names are unique within a stack, so the stack
|
|
101
|
+
* both makes the name resolvable and confines the call to its own functions.
|
|
102
|
+
*
|
|
103
|
+
* @internal
|
|
104
|
+
*/
|
|
105
|
+
function _resolveFunctionId(
|
|
106
|
+
client: Client,
|
|
107
|
+
httpRequest: HttpRequest,
|
|
108
|
+
functionName: string,
|
|
109
|
+
stackId: string,
|
|
110
|
+
headers: Record<string, string>,
|
|
111
|
+
request: InvokeFunctionRequest | undefined,
|
|
112
|
+
): Observable<string> {
|
|
113
|
+
return _requestObservable<{resources?: StackResource[]}>(client, httpRequest, {
|
|
114
|
+
method: 'GET',
|
|
115
|
+
url: `/blueprints/stacks/${stackId}`,
|
|
116
|
+
headers,
|
|
117
|
+
signal: request?.signal,
|
|
118
|
+
}).pipe(
|
|
119
|
+
map((stack) => {
|
|
120
|
+
const match = (stack?.resources || []).find(
|
|
121
|
+
(resource) =>
|
|
122
|
+
resource.type?.startsWith(FUNCTION_RESOURCE_PREFIX) && resource.name === functionName,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if (!match) {
|
|
126
|
+
throw new Error(`Function "${functionName}" not found in stack "${stackId}"`)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!match.externalId) {
|
|
130
|
+
throw new Error(
|
|
131
|
+
`Function "${functionName}" is declared in stack "${stackId}" but is not deployed`,
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (match.type !== INVOKABLE_FUNCTION_TYPE) {
|
|
136
|
+
throw new Error(`Function invocation is not supported for ${match.type}`)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return match.externalId
|
|
140
|
+
}),
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** @internal */
|
|
145
|
+
export function _invoke<R = unknown>(
|
|
146
|
+
client: Client,
|
|
147
|
+
httpRequest: HttpRequest,
|
|
148
|
+
functionName: string,
|
|
149
|
+
request?: InvokeFunctionRequest,
|
|
150
|
+
): Observable<R | undefined> {
|
|
151
|
+
// Deferred so a bad config surfaces as an error on the returned observable
|
|
152
|
+
// (and so a rejected promise) rather than throwing at the call site.
|
|
153
|
+
return defer(() => {
|
|
154
|
+
const config = client.config()
|
|
155
|
+
const headers = scopeHeaders(config, request)
|
|
156
|
+
const stackId = resolveStackId(config, request)
|
|
157
|
+
|
|
158
|
+
return _resolveFunctionId(client, httpRequest, functionName, stackId, headers, request).pipe(
|
|
159
|
+
// A function that returns nothing answers 204, which the transport parses
|
|
160
|
+
// to an `undefined` body. The status code is not observable from here —
|
|
161
|
+
// the `HttpRequest` boundary resolves to the body alone — so an empty
|
|
162
|
+
// response and a function that returned nothing both surface as
|
|
163
|
+
// `undefined`.
|
|
164
|
+
mergeMap((functionId) =>
|
|
165
|
+
_requestObservable<R | undefined>(client, httpRequest, {
|
|
166
|
+
method: 'POST',
|
|
167
|
+
url: `/functions/${functionId}/invoke`,
|
|
168
|
+
headers,
|
|
169
|
+
body: {event: {data: request?.event?.data ?? {}}},
|
|
170
|
+
timeout: request?.timeout,
|
|
171
|
+
signal: request?.signal,
|
|
172
|
+
}),
|
|
173
|
+
),
|
|
174
|
+
)
|
|
175
|
+
})
|
|
176
|
+
}
|