@sanity/client 8.0.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 +265 -0
- package/dist/{browserUpload-CQgx9YYo.js → browserUpload-2tz6Sdqp.js} +4 -3
- package/dist/browserUpload-2tz6Sdqp.js.map +1 -0
- package/dist/{browserUpload-icWlVP15.js → browserUpload-CwpNx7Vl.js} +4 -3
- package/dist/browserUpload-CwpNx7Vl.js.map +1 -0
- package/dist/{config-a8VajuEY.js → config-3wiPP-sZ.js} +2 -2
- package/dist/config-3wiPP-sZ.js.map +1 -0
- package/dist/csm.js +2 -2
- package/dist/csm.js.map +1 -1
- package/dist/index.d.ts +17 -11
- package/dist/index.js +610 -136
- package/dist/index.js.map +1 -1
- package/dist/index.node.d.ts +918 -26
- package/dist/index.node.js +559 -66
- package/dist/index.node.js.map +1 -1
- package/dist/media-library.d.ts +1 -1
- package/dist/{request-CJxcN16k.js → request-BhMuKj0D.js} +10 -9
- package/dist/request-BhMuKj0D.js.map +1 -0
- package/dist/{request-k7VS_NnC.js → request-SnMg7nUX.js} +10 -9
- package/dist/request-SnMg7nUX.js.map +1 -0
- package/dist/{resolveEditInfo-sq7yF78q.js → resolveEditInfo-Cz-smq3a.js} +17 -3
- package/dist/resolveEditInfo-Cz-smq3a.js.map +1 -0
- package/dist/stega.js +1 -1
- package/dist/{stegaEncodeSourceMap-DkoIlutY.js → stegaEncodeSourceMap-DbM2fTN4.js} +8 -2
- package/dist/stegaEncodeSourceMap-DbM2fTN4.js.map +1 -0
- package/dist/{stegaEncodeSourceMap-B2fGArSf.js → stegaEncodeSourceMap-YR3NQ3iz.js} +2 -2
- package/dist/{stegaEncodeSourceMap-B2fGArSf.js.map → stegaEncodeSourceMap-YR3NQ3iz.js.map} +1 -1
- package/dist/{types-CUxZSgB2.d.ts → types-nJhm5Nyq.d.ts} +910 -24
- package/package.json +26 -11
- package/src/SanityClient.ts +39 -20
- package/src/assets/AssetsClient.ts +54 -5
- package/src/collaboration/CollaborationCommentsClient.ts +387 -0
- package/src/collaboration/comments.ts +313 -0
- package/src/collaboration/types.ts +252 -0
- package/src/csm/applySourceDocuments.ts +2 -4
- package/src/csm/draftUtils.ts +23 -4
- package/src/data/dataMethods.ts +9 -20
- package/src/data/eventsource.ts +71 -41
- package/src/data/listen.ts +20 -5
- package/src/data/live.ts +17 -9
- package/src/data/resolveEventSourceFetch.ts +9 -1
- package/src/defineCreateClient.ts +5 -1
- package/src/functions/FunctionsClient.ts +66 -0
- package/src/functions/invoke.ts +176 -0
- package/src/http/browserUpload.ts +1 -0
- package/src/http/errors.ts +2 -1
- package/src/http/request.ts +8 -14
- package/src/mediaLibrary/MediaLibraryVideoClient.ts +1 -1
- package/src/types.ts +420 -4
- package/src/validators.ts +1 -1
- package/src/warnings.ts +7 -1
- package/dist/browserUpload-CQgx9YYo.js.map +0 -1
- package/dist/browserUpload-icWlVP15.js.map +0 -1
- package/dist/config-a8VajuEY.js.map +0 -1
- package/dist/request-CJxcN16k.js.map +0 -1
- package/dist/request-k7VS_NnC.js.map +0 -1
- package/dist/resolveEditInfo-sq7yF78q.js.map +0 -1
- package/dist/stegaEncodeSourceMap-DkoIlutY.js.map +0 -1
package/src/data/live.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {EventSource} from 'eventsource'
|
|
2
|
+
import type {FetchFunction} from 'get-it'
|
|
2
3
|
import {catchError, mergeMap, Observable, of, throwError} from 'rxjs'
|
|
3
4
|
import {finalize, map} from 'rxjs/operators'
|
|
4
5
|
|
|
@@ -14,11 +15,12 @@ import type {
|
|
|
14
15
|
LiveEventWelcome,
|
|
15
16
|
SyncTag,
|
|
16
17
|
} from '../types'
|
|
18
|
+
import {isRecord} from '../util/isRecord'
|
|
17
19
|
import {shareReplayLatest} from '../util/shareReplayLatest'
|
|
18
20
|
import {_getDataUrl} from './dataMethods'
|
|
19
21
|
import {connectEventSource} from './eventsource'
|
|
20
22
|
import {reconnectOnConnectionFailure} from './reconnectOnConnectionFailure'
|
|
21
|
-
import {resolveEventSourceFetch} from './resolveEventSourceFetch'
|
|
23
|
+
import {pickBaseFetch, resolveEventSourceFetch} from './resolveEventSourceFetch'
|
|
22
24
|
|
|
23
25
|
const requiredApiVersion = '2021-03-25'
|
|
24
26
|
|
|
@@ -132,6 +134,7 @@ export class LiveClient {
|
|
|
132
134
|
new URL(this.#client.getUrl('/check/cors', false)),
|
|
133
135
|
projectId,
|
|
134
136
|
eventSourceWithCredentials,
|
|
137
|
+
pickBaseFetch(config),
|
|
135
138
|
)
|
|
136
139
|
|
|
137
140
|
const observable = events
|
|
@@ -221,35 +224,40 @@ function checkCorsObservable(
|
|
|
221
224
|
url: URL,
|
|
222
225
|
projectId: string | undefined,
|
|
223
226
|
requireCredentials: boolean,
|
|
227
|
+
fetcher: FetchFunction,
|
|
224
228
|
): Observable<void> {
|
|
225
229
|
return new Observable<void>((observer) => {
|
|
226
230
|
const controller = new AbortController()
|
|
227
231
|
const {signal} = controller
|
|
228
|
-
|
|
232
|
+
fetcher(url.href, {method: 'GET', credentials: 'omit', signal})
|
|
229
233
|
.then((response) => {
|
|
230
234
|
// Aborted or non-2xx: not a confirmed CORS rejection. Fall through with
|
|
231
235
|
// an undefined body so the next step takes the silent-completion path.
|
|
232
|
-
if (signal.aborted || !response.ok) return
|
|
233
|
-
return response.
|
|
234
|
-
result?: {allowed?: boolean; withCredentials?: boolean}
|
|
235
|
-
}>
|
|
236
|
+
if (signal.aborted || !response.ok) return undefined
|
|
237
|
+
return response.text()
|
|
236
238
|
})
|
|
237
|
-
.then((
|
|
239
|
+
.then((text) => {
|
|
238
240
|
if (signal.aborted) return
|
|
241
|
+
// `get-it`'s `FetchResponse` only guarantees `.text()`/`.arrayBuffer()`,
|
|
242
|
+
// not `.json()`, so the body is parsed by hand here. An empty/aborted
|
|
243
|
+
// fall-through (`text === undefined`) and malformed JSON both leave
|
|
244
|
+
// `result` unresolved, taking the same "no signal either way" path.
|
|
245
|
+
const parsed: unknown = text === undefined ? undefined : JSON.parse(text)
|
|
246
|
+
const result = isRecord(parsed) ? parsed.result : undefined
|
|
239
247
|
// Check the credentialed case first: if the EventSource was about to
|
|
240
248
|
// send credentials but the project's CORS config doesn't permit them,
|
|
241
249
|
// the credentialed request would fail with a missing
|
|
242
250
|
// `access-control-allow-credentials` header. Surface this as a CORS
|
|
243
251
|
// rejection with `credentials: true` so the deep-link pre-selects the
|
|
244
252
|
// "Allow credentials" toggle.
|
|
245
|
-
if (requireCredentials &&
|
|
253
|
+
if (requireCredentials && isRecord(result) && result.withCredentials === false) {
|
|
246
254
|
observer.error(new CorsOriginError({projectId, credentials: true}))
|
|
247
255
|
return
|
|
248
256
|
}
|
|
249
257
|
// Generic case: the server actively rejected this origin. Propagate
|
|
250
258
|
// `credentials: requireCredentials` so the deep-link still pre-selects
|
|
251
259
|
// credentials when the caller needed them.
|
|
252
|
-
if (
|
|
260
|
+
if (isRecord(result) && result.allowed === false) {
|
|
253
261
|
observer.error(new CorsOriginError({projectId, credentials: requireCredentials}))
|
|
254
262
|
return
|
|
255
263
|
}
|
|
@@ -88,7 +88,15 @@ export type EventSourceFetch = (
|
|
|
88
88
|
init?: EventSourceFetchInit,
|
|
89
89
|
) => Promise<FetchLikeResponse>
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
/**
|
|
92
|
+
* The fetch the client's own transport resolves for this config: the
|
|
93
|
+
* configured `resolveFetch` (honouring an explicit `proxy`) if present,
|
|
94
|
+
* otherwise the global fetch. Shared by the EventSource connection and the
|
|
95
|
+
* `/check/cors` probe so both resolve identically.
|
|
96
|
+
*
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
99
|
+
export function pickBaseFetch(config: InitializedClientConfig): FetchFunction {
|
|
92
100
|
if (config.resolveFetch) {
|
|
93
101
|
return config.resolveFetch(typeof config.proxy === 'string' ? config.proxy : undefined)
|
|
94
102
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {defineRequester, type EnvironmentOptions} from './http/request'
|
|
2
2
|
import type {ClientConfig, HttpRequest} from './types'
|
|
3
3
|
|
|
4
|
+
export {isTimeoutError, type TimeoutErrorLike} from 'get-it'
|
|
5
|
+
|
|
4
6
|
export {validateApiPerspective} from './config'
|
|
5
7
|
export {
|
|
6
8
|
ChannelError,
|
|
@@ -55,10 +57,12 @@ export default function defineCreateClientExports<
|
|
|
55
57
|
// this in `new Observable(...)` (see `_observe` in dataMethods).
|
|
56
58
|
// Redirects are surfaced rather than followed unless a request opts in
|
|
57
59
|
// (via the public `maxRedirects` option, translated in `requestOptions`).
|
|
58
|
-
const
|
|
60
|
+
const performRequest = async (options: Parameters<HttpRequest>[0]): Promise<unknown> => {
|
|
59
61
|
const event = await clientRequesterPromise({redirect: 'manual', ...options})
|
|
60
62
|
return event.body
|
|
61
63
|
}
|
|
64
|
+
const httpRequest: HttpRequest = (options, requestHandler) =>
|
|
65
|
+
requestHandler ? requestHandler(options, performRequest) : performRequest(options)
|
|
62
66
|
// Populate `requester` on the initialized config so internal paths
|
|
63
67
|
// (e.g. the asset upload event stream) can reach the underlying transport.
|
|
64
68
|
// `resolveFetch` is threaded onto the config so request building and
|
|
@@ -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
|
+
}
|
package/src/http/errors.ts
CHANGED
|
@@ -39,6 +39,7 @@ export function httpResponseFromFetch(
|
|
|
39
39
|
statusText: string
|
|
40
40
|
headers: Headers
|
|
41
41
|
body: unknown
|
|
42
|
+
url: string
|
|
42
43
|
},
|
|
43
44
|
reqUrl: string,
|
|
44
45
|
reqMethod: string,
|
|
@@ -48,7 +49,7 @@ export function httpResponseFromFetch(
|
|
|
48
49
|
statusMessage: res.statusText || null,
|
|
49
50
|
headers: headersToRecord(res.headers),
|
|
50
51
|
body: res.body,
|
|
51
|
-
url: reqUrl,
|
|
52
|
+
url: res.url || reqUrl,
|
|
52
53
|
method: reqMethod,
|
|
53
54
|
}
|
|
54
55
|
}
|
package/src/http/request.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createRequester,
|
|
3
3
|
type FetchFunction,
|
|
4
|
-
|
|
4
|
+
isHttpError as isGetItHttpError,
|
|
5
5
|
type RequestOptions as FetchRequestOptions,
|
|
6
6
|
type TransformMiddleware,
|
|
7
7
|
type WrappingMiddleware,
|
|
@@ -40,8 +40,9 @@ export interface ResponseEvent {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
* Legacy "requester" type
|
|
44
|
-
* single-event Observable for compatibility with the rest
|
|
43
|
+
* Legacy "requester" type - the observable half of `defineRequester`'s
|
|
44
|
+
* result. Returns a single-event Observable for compatibility with the rest
|
|
45
|
+
* of the codebase.
|
|
45
46
|
*
|
|
46
47
|
* @internal
|
|
47
48
|
*/
|
|
@@ -163,14 +164,6 @@ export function defineRequester(
|
|
|
163
164
|
return {promise, observable}
|
|
164
165
|
}
|
|
165
166
|
|
|
166
|
-
/** @internal */
|
|
167
|
-
export function defineHttpRequest(
|
|
168
|
-
envOptions: EnvironmentOptions,
|
|
169
|
-
config: HttpRequestConfig = {},
|
|
170
|
-
): LegacyRequester {
|
|
171
|
-
return defineRequester(envOptions, config).observable
|
|
172
|
-
}
|
|
173
|
-
|
|
174
167
|
/**
|
|
175
168
|
* Options describing the environment-specific defaults (Node vs. browser).
|
|
176
169
|
*
|
|
@@ -208,7 +201,7 @@ async function executeRequest(
|
|
|
208
201
|
try {
|
|
209
202
|
response = await requester(fetchOptions)
|
|
210
203
|
} catch (err) {
|
|
211
|
-
if (err
|
|
204
|
+
if (isGetItHttpError(err)) {
|
|
212
205
|
// `err.body` is the response body as a string (get-it v9 stores the
|
|
213
206
|
// already-decoded text), regardless of which response variant
|
|
214
207
|
// `err.response` is.
|
|
@@ -220,6 +213,7 @@ async function executeRequest(
|
|
|
220
213
|
statusText: err.statusText,
|
|
221
214
|
headers: err.headers,
|
|
222
215
|
body: errBody,
|
|
216
|
+
url: err.response.url ?? err.url,
|
|
223
217
|
},
|
|
224
218
|
url,
|
|
225
219
|
method,
|
|
@@ -240,7 +234,7 @@ async function executeRequest(
|
|
|
240
234
|
statusCode: response.status,
|
|
241
235
|
statusMessage: response.statusText || null,
|
|
242
236
|
headers: headersToRecord(response.headers),
|
|
243
|
-
url,
|
|
237
|
+
url: response.url || url,
|
|
244
238
|
method,
|
|
245
239
|
}
|
|
246
240
|
}
|
|
@@ -291,7 +285,7 @@ function headersToRecord(headers: Headers): Record<string, string> {
|
|
|
291
285
|
function shouldRetryRequest(err: unknown, attempt: number, options: FetchRequestOptions): boolean {
|
|
292
286
|
// HTTP errors aren't usually retryable, but Content Lake gives us a few
|
|
293
287
|
// status codes where retrying *is* the right move.
|
|
294
|
-
if (err
|
|
288
|
+
if (isGetItHttpError(err)) {
|
|
295
289
|
const isSafe = (options.method ?? 'GET') === 'GET' || options.method === 'HEAD'
|
|
296
290
|
const isQuery = (options.url ?? '').includes('/data/query')
|
|
297
291
|
const status = err.status
|
|
@@ -111,7 +111,7 @@ function isSanityReference(
|
|
|
111
111
|
* @param assetIdentifier - The asset identifier - either a asset instance id or a Media Library GDR
|
|
112
112
|
* @returns The asset instance id and library id
|
|
113
113
|
*/
|
|
114
|
-
|
|
114
|
+
function parseAssetInstanceId(assetIdentifier: MediaLibraryAssetInstanceIdentifier): {
|
|
115
115
|
instanceId: string
|
|
116
116
|
libraryId?: string
|
|
117
117
|
} {
|