@atproto/lex-client 0.0.15 → 0.0.17
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/CHANGELOG.md +28 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +7 -5
- package/dist/agent.js.map +1 -1
- package/dist/client.d.ts +24 -21
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +10 -7
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +29 -17
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +43 -16
- package/dist/errors.js.map +1 -1
- package/dist/response.d.ts +61 -6
- package/dist/response.d.ts.map +1 -1
- package/dist/response.js +59 -40
- package/dist/response.js.map +1 -1
- package/dist/types.d.ts +8 -37
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +15 -27
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +21 -6
- package/dist/util.js.map +1 -1
- package/dist/xrpc.d.ts +40 -15
- package/dist/xrpc.d.ts.map +1 -1
- package/dist/xrpc.js +6 -2
- package/dist/xrpc.js.map +1 -1
- package/package.json +6 -6
- package/src/agent.test.ts +216 -0
- package/src/agent.ts +8 -6
- package/src/client.ts +81 -31
- package/src/errors.test.ts +77 -8
- package/src/errors.ts +58 -21
- package/src/response.ts +186 -63
- package/src/types.ts +17 -40
- package/src/util.test.ts +333 -0
- package/src/util.ts +42 -36
- package/src/xrpc.test.ts +1453 -0
- package/src/xrpc.ts +76 -28
package/src/errors.ts
CHANGED
|
@@ -7,12 +7,16 @@ import {
|
|
|
7
7
|
ResultFailure,
|
|
8
8
|
lexErrorDataSchema,
|
|
9
9
|
} from '@atproto/lex-schema'
|
|
10
|
-
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
11
|
+
import { Agent } from './agent.js'
|
|
12
|
+
import { XrpcUnknownResponsePayload } from './types.js'
|
|
11
13
|
import {
|
|
12
14
|
WWWAuthenticate,
|
|
13
15
|
parseWWWAuthenticateHeader,
|
|
14
16
|
} from './www-authenticate.js'
|
|
15
17
|
|
|
18
|
+
export type { XrpcUnknownResponsePayload }
|
|
19
|
+
|
|
16
20
|
export type DownstreamError<N extends LexErrorCode = LexErrorCode> = {
|
|
17
21
|
status: number
|
|
18
22
|
headers?: Headers
|
|
@@ -66,7 +70,7 @@ export type XrpcErrorPayload<N extends LexErrorCode = LexErrorCode> = {
|
|
|
66
70
|
* This function checks whether a given payload matches this schema.
|
|
67
71
|
*/
|
|
68
72
|
export function isXrpcErrorPayload(
|
|
69
|
-
payload:
|
|
73
|
+
payload: XrpcUnknownResponsePayload | null | undefined,
|
|
70
74
|
): payload is XrpcErrorPayload {
|
|
71
75
|
return (
|
|
72
76
|
payload != null &&
|
|
@@ -290,7 +294,7 @@ export class XrpcUpstreamError<
|
|
|
290
294
|
constructor(
|
|
291
295
|
method: M,
|
|
292
296
|
readonly response: Response,
|
|
293
|
-
readonly payload:
|
|
297
|
+
readonly payload: XrpcUnknownResponsePayload | null = null,
|
|
294
298
|
message: string = `Unexpected upstream XRPC response`,
|
|
295
299
|
options?: ErrorOptions,
|
|
296
300
|
) {
|
|
@@ -329,7 +333,7 @@ export class XrpcInvalidResponseError<
|
|
|
329
333
|
constructor(
|
|
330
334
|
method: M,
|
|
331
335
|
response: Response,
|
|
332
|
-
payload:
|
|
336
|
+
payload: XrpcUnknownResponsePayload,
|
|
333
337
|
readonly cause: LexValidationError,
|
|
334
338
|
) {
|
|
335
339
|
super(method, response, payload, `Invalid response: ${cause.message}`, {
|
|
@@ -347,17 +351,11 @@ export class XrpcInvalidResponseError<
|
|
|
347
351
|
}
|
|
348
352
|
|
|
349
353
|
/**
|
|
350
|
-
* Error class for internal/client-side errors during XRPC requests.
|
|
351
|
-
*
|
|
352
|
-
* This represents errors that occur before or during the request that are not
|
|
353
|
-
* server responses, such as:
|
|
354
|
-
* - Network errors (connection refused, DNS failure)
|
|
355
|
-
* - Request timeouts
|
|
356
|
-
* - Request aborted via AbortSignal
|
|
357
|
-
* - Invalid request construction
|
|
354
|
+
* Error class for unexpected internal/client-side errors during XRPC requests.
|
|
358
355
|
*
|
|
359
|
-
* The error code is always 'InternalServerError' and these errors
|
|
360
|
-
*
|
|
356
|
+
* The error code is always 'InternalServerError' and these errors not
|
|
357
|
+
* considered retryable as they stem from unforeseen issues in the
|
|
358
|
+
* implementation.
|
|
361
359
|
*
|
|
362
360
|
* @typeParam M - The XRPC method type
|
|
363
361
|
*/
|
|
@@ -379,15 +377,11 @@ export class XrpcInternalError<
|
|
|
379
377
|
return this
|
|
380
378
|
}
|
|
381
379
|
|
|
382
|
-
override shouldRetry():
|
|
383
|
-
|
|
384
|
-
// (by detecting network errors, timeouts, etc.). Since these cases are
|
|
385
|
-
// highly platform-dependent, we optimistically assume all internal
|
|
386
|
-
// errors are retryable.
|
|
387
|
-
return true
|
|
380
|
+
override shouldRetry(): boolean {
|
|
381
|
+
return false
|
|
388
382
|
}
|
|
389
383
|
|
|
390
|
-
override toJSON(): LexErrorData
|
|
384
|
+
override toJSON(): LexErrorData {
|
|
391
385
|
// @NOTE Do not expose internal error details to downstream clients
|
|
392
386
|
return { error: this.error, message: 'Internal Server Error' }
|
|
393
387
|
}
|
|
@@ -397,6 +391,49 @@ export class XrpcInternalError<
|
|
|
397
391
|
}
|
|
398
392
|
}
|
|
399
393
|
|
|
394
|
+
/**
|
|
395
|
+
* Special case of XrpcInternalError that specifically represents errors thrown
|
|
396
|
+
* by {@link Agent.fetchHandler} during the XRPC request. This includes:
|
|
397
|
+
* - Network errors (connection refused, DNS failure)
|
|
398
|
+
* - Request timeouts
|
|
399
|
+
* - Request aborted via AbortSignal
|
|
400
|
+
*
|
|
401
|
+
* These errors are optimistically considered retryable, as many fetch errors
|
|
402
|
+
* are transient and may succeed on retry.
|
|
403
|
+
*/
|
|
404
|
+
export class XrpcFetchError<
|
|
405
|
+
M extends Procedure | Query = Procedure | Query,
|
|
406
|
+
> extends XrpcInternalError<M> {
|
|
407
|
+
name = 'XrpcFetchError'
|
|
408
|
+
|
|
409
|
+
constructor(method: M, cause: unknown) {
|
|
410
|
+
const message = cause instanceof Error ? cause.message : String(cause)
|
|
411
|
+
super(method, `Unexpected fetchHandler() error: ${message}`, { cause })
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
override shouldRetry(): boolean {
|
|
415
|
+
// Ideally, we would inspect the reason to determine if it's retryable (by
|
|
416
|
+
// detecting network errors, timeouts, etc.). Since these cases are highly
|
|
417
|
+
// platform-dependent, we optimistically assume all fetch errors are
|
|
418
|
+
// transient and retryable.
|
|
419
|
+
return true
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
override toJSON(): LexErrorData {
|
|
423
|
+
// @NOTE Do not expose internal error details to downstream clients
|
|
424
|
+
return { error: this.error, message: 'Failed to perform upstream request' }
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
override toDownstreamError(): DownstreamError {
|
|
428
|
+
// While it might technically be a 500 error, we use 502 Bad Gateway here to
|
|
429
|
+
// indicate that the error occurred while communicating with the upstream
|
|
430
|
+
// server, allowing downstream clients to distinguish between errors in our
|
|
431
|
+
// internal processing (500) and errors in the upstream server or network
|
|
432
|
+
// (502).
|
|
433
|
+
return { status: 502, body: this.toJSON() }
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
400
437
|
/**
|
|
401
438
|
* Union type of all possible XRPC failure types.
|
|
402
439
|
*
|
package/src/response.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { lexParse } from '@atproto/lex-json'
|
|
1
|
+
import { LexParseOptions, lexParse } from '@atproto/lex-json'
|
|
2
2
|
import {
|
|
3
3
|
InferMethodOutputEncoding,
|
|
4
|
+
InferOutput,
|
|
5
|
+
LexValue,
|
|
6
|
+
Payload,
|
|
4
7
|
Procedure,
|
|
5
8
|
Query,
|
|
6
9
|
ResultSuccess,
|
|
10
|
+
Validator,
|
|
7
11
|
} from '@atproto/lex-schema'
|
|
8
12
|
import {
|
|
9
13
|
XrpcAuthenticationError,
|
|
@@ -12,12 +16,104 @@ import {
|
|
|
12
16
|
XrpcUpstreamError,
|
|
13
17
|
isXrpcErrorPayload,
|
|
14
18
|
} from './errors.js'
|
|
15
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
EncodingString,
|
|
21
|
+
XrpcUnknownResponsePayload,
|
|
22
|
+
isEncodingString,
|
|
23
|
+
} from './types.js'
|
|
16
24
|
|
|
17
25
|
const CONTENT_TYPE_BINARY = 'application/octet-stream'
|
|
18
26
|
const CONTENT_TYPE_JSON = 'application/json'
|
|
19
27
|
|
|
20
|
-
|
|
28
|
+
// @NOTE the output schema is used in "parse" mode (safeParse), which means that
|
|
29
|
+
// defaults will be applied and coercions will be performed, so we need to use
|
|
30
|
+
// InferOutput here to get the final parsed type, not Infer/InferInput. For this
|
|
31
|
+
// reason, we cannot use InferMethodOutputBody and InferMethodOutput from
|
|
32
|
+
// lex-schema here.
|
|
33
|
+
|
|
34
|
+
type InferEncodingType<TEncoding extends string> = TEncoding extends '*/*'
|
|
35
|
+
? EncodingString
|
|
36
|
+
: TEncoding extends `${infer T extends string}/*`
|
|
37
|
+
? `${T}/${string}`
|
|
38
|
+
: TEncoding
|
|
39
|
+
|
|
40
|
+
type InferBodyType<
|
|
41
|
+
TEncoding extends string,
|
|
42
|
+
TSchema,
|
|
43
|
+
> = TSchema extends Validator
|
|
44
|
+
? InferOutput<TSchema>
|
|
45
|
+
: TEncoding extends `application/json`
|
|
46
|
+
? LexValue
|
|
47
|
+
: Uint8Array
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The body type of an XRPC response, inferred from the method's output schema.
|
|
51
|
+
*
|
|
52
|
+
* For JSON responses, this is the parsed LexValue. For binary responses,
|
|
53
|
+
* this is a Uint8Array.
|
|
54
|
+
*
|
|
55
|
+
* @typeParam M - The XRPC method type (Procedure or Query)
|
|
56
|
+
*/
|
|
57
|
+
export type XrpcResponseBody<M extends Procedure | Query> =
|
|
58
|
+
M['output'] extends Payload<infer TEncoding, infer TSchema>
|
|
59
|
+
? TEncoding extends string
|
|
60
|
+
? InferBodyType<TEncoding, TSchema>
|
|
61
|
+
: undefined
|
|
62
|
+
: never
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The full payload type of an XRPC response, including body and encoding.
|
|
66
|
+
*
|
|
67
|
+
* Returns `null` for methods that have no output.
|
|
68
|
+
*
|
|
69
|
+
* @typeParam M - The XRPC method type (Procedure or Query)
|
|
70
|
+
*/
|
|
71
|
+
export type XrpcResponsePayload<M extends Procedure | Query> =
|
|
72
|
+
M['output'] extends Payload<infer TEncoding, infer TSchema>
|
|
73
|
+
? TEncoding extends string
|
|
74
|
+
? {
|
|
75
|
+
encoding: InferEncodingType<TEncoding>
|
|
76
|
+
body: InferBodyType<TEncoding, TSchema>
|
|
77
|
+
}
|
|
78
|
+
: undefined
|
|
79
|
+
: never
|
|
80
|
+
|
|
81
|
+
export type XrpcResponseOptions = {
|
|
82
|
+
/**
|
|
83
|
+
* Whether to validate the response against the method's output schema.
|
|
84
|
+
* Disabling this can improve performance but may lead to runtime errors if
|
|
85
|
+
* the response does not conform to the expected schema. Only set this to
|
|
86
|
+
* `false` if you are certain that the upstream service will always return
|
|
87
|
+
* valid responses.
|
|
88
|
+
*
|
|
89
|
+
* @default true
|
|
90
|
+
*/
|
|
91
|
+
validateResponse?: boolean
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Whether to strictly process response payloads according to Lex encoding
|
|
95
|
+
* rules. By default, the client will reject responses with invalid Lex data
|
|
96
|
+
* (floats and invalid $bytes / $link objects).
|
|
97
|
+
*
|
|
98
|
+
* Setting this option to `false` will allow the client to accept such
|
|
99
|
+
* responses in a non-strict mode, where invalid Lex data will be returned
|
|
100
|
+
* as-is (e.g., floats will not be rejected, and invalid $bytes / $link
|
|
101
|
+
* objects will not be converted to Uint8Array / Cid). When in non-strict
|
|
102
|
+
* mode, the validation will also be relaxed when validating the response
|
|
103
|
+
* against the method's output schema, allowing values that do not strictly
|
|
104
|
+
* conform to the schema (e.g. datetime strings that are not valid RFC3339
|
|
105
|
+
* format, blobs that are not of the right size/mime-type, etc.) to be
|
|
106
|
+
* accepted as long as their basic structure is correct.
|
|
107
|
+
*
|
|
108
|
+
* When validation is enabled (the default), the values defined through the
|
|
109
|
+
* method schema will be enforced, ensuring that the client can still process
|
|
110
|
+
* the response even if the server returns invalid Lex data.
|
|
111
|
+
*
|
|
112
|
+
* @default true
|
|
113
|
+
* @see {@link LexParseOptions.strict}
|
|
114
|
+
*/
|
|
115
|
+
strictResponseProcessing?: boolean
|
|
116
|
+
}
|
|
21
117
|
|
|
22
118
|
/**
|
|
23
119
|
* Small container for XRPC response data.
|
|
@@ -80,7 +176,7 @@ export class XrpcResponse<M extends Procedure | Query>
|
|
|
80
176
|
static async fromFetchResponse<const M extends Procedure | Query>(
|
|
81
177
|
method: M,
|
|
82
178
|
response: Response,
|
|
83
|
-
options?:
|
|
179
|
+
options?: XrpcResponseOptions,
|
|
84
180
|
): Promise<XrpcResponse<M>> {
|
|
85
181
|
// @NOTE The body MUST either be read or canceled to avoid resource leaks.
|
|
86
182
|
// Since nothing should cause an exception before "readPayload" is
|
|
@@ -89,17 +185,9 @@ export class XrpcResponse<M extends Procedure | Query>
|
|
|
89
185
|
// @NOTE redirect is set to 'follow', so we shouldn't get 3xx responses here
|
|
90
186
|
if (response.status < 200 || response.status >= 300) {
|
|
91
187
|
// Always parse json for error responses
|
|
92
|
-
const payload = await readPayload(response, {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
method,
|
|
96
|
-
response,
|
|
97
|
-
null,
|
|
98
|
-
'Unable to parse response payload',
|
|
99
|
-
{ cause },
|
|
100
|
-
)
|
|
101
|
-
},
|
|
102
|
-
)
|
|
188
|
+
const payload = await readPayload(method, response, {
|
|
189
|
+
parse: { strict: options?.strictResponseProcessing ?? true },
|
|
190
|
+
})
|
|
103
191
|
|
|
104
192
|
// Properly formatted XRPC error response ?
|
|
105
193
|
if (response.status >= 400 && isXrpcErrorPayload(payload)) {
|
|
@@ -121,17 +209,11 @@ export class XrpcResponse<M extends Procedure | Query>
|
|
|
121
209
|
)
|
|
122
210
|
}
|
|
123
211
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
parse: method.output.encoding === CONTENT_TYPE_JSON
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
method,
|
|
130
|
-
response,
|
|
131
|
-
null,
|
|
132
|
-
'Unable to parse response payload',
|
|
133
|
-
{ cause },
|
|
134
|
-
)
|
|
212
|
+
const payload = await readPayload(method, response, {
|
|
213
|
+
// Only parse json if the schema expects it
|
|
214
|
+
parse: method.output.encoding === CONTENT_TYPE_JSON && {
|
|
215
|
+
strict: options?.strictResponseProcessing ?? true,
|
|
216
|
+
},
|
|
135
217
|
})
|
|
136
218
|
|
|
137
219
|
// Response is successful (2xx). Validate payload (data and encoding) against schema.
|
|
@@ -160,7 +242,9 @@ export class XrpcResponse<M extends Procedure | Query>
|
|
|
160
242
|
|
|
161
243
|
// Assert valid response body.
|
|
162
244
|
if (method.output.schema && options?.validateResponse !== false) {
|
|
163
|
-
const result = method.output.schema.safeParse(payload.body
|
|
245
|
+
const result = method.output.schema.safeParse(payload.body, {
|
|
246
|
+
strict: options?.strictResponseProcessing ?? true,
|
|
247
|
+
})
|
|
164
248
|
|
|
165
249
|
if (!result.success) {
|
|
166
250
|
throw new XrpcInvalidResponseError(
|
|
@@ -170,6 +254,18 @@ export class XrpcResponse<M extends Procedure | Query>
|
|
|
170
254
|
result.reason,
|
|
171
255
|
)
|
|
172
256
|
}
|
|
257
|
+
|
|
258
|
+
const parsedPayload = {
|
|
259
|
+
body: result.value,
|
|
260
|
+
encoding: payload.encoding,
|
|
261
|
+
} as XrpcResponsePayload<M>
|
|
262
|
+
|
|
263
|
+
return new XrpcResponse<M>(
|
|
264
|
+
method,
|
|
265
|
+
response.status,
|
|
266
|
+
response.headers,
|
|
267
|
+
parsedPayload,
|
|
268
|
+
)
|
|
173
269
|
}
|
|
174
270
|
}
|
|
175
271
|
|
|
@@ -182,50 +278,77 @@ export class XrpcResponse<M extends Procedure | Query>
|
|
|
182
278
|
}
|
|
183
279
|
}
|
|
184
280
|
|
|
281
|
+
type ReadPayloadOptions = {
|
|
282
|
+
/**
|
|
283
|
+
* Whether to parse the response body as JSON and convert it to LexValue.
|
|
284
|
+
*
|
|
285
|
+
* @default false
|
|
286
|
+
*/
|
|
287
|
+
parse?: false | LexParseOptions
|
|
288
|
+
}
|
|
289
|
+
|
|
185
290
|
/**
|
|
186
291
|
* @note this function always consumes the response body
|
|
187
292
|
*/
|
|
188
293
|
async function readPayload(
|
|
294
|
+
method: Query | Procedure,
|
|
189
295
|
response: Response,
|
|
190
|
-
options?:
|
|
191
|
-
): Promise<
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
.
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
296
|
+
options?: ReadPayloadOptions,
|
|
297
|
+
): Promise<undefined | XrpcUnknownResponsePayload> {
|
|
298
|
+
try {
|
|
299
|
+
// @TODO Should we limit the maximum response size here (this could also be
|
|
300
|
+
// done by the FetchHandler)?
|
|
301
|
+
|
|
302
|
+
const encoding = response.headers
|
|
303
|
+
.get('content-type')
|
|
304
|
+
?.split(';')[0]
|
|
305
|
+
.trim()
|
|
306
|
+
.toLowerCase()
|
|
307
|
+
|
|
308
|
+
// Response content-type is undefined
|
|
309
|
+
if (!encoding) {
|
|
310
|
+
// If the body is empty, return undefined (= no payload)
|
|
311
|
+
const arrayBuffer = await response.arrayBuffer()
|
|
312
|
+
if (arrayBuffer.byteLength === 0) return undefined
|
|
313
|
+
|
|
314
|
+
// If we got data despite no content-type, treat it as binary
|
|
315
|
+
return {
|
|
316
|
+
encoding: CONTENT_TYPE_BINARY,
|
|
317
|
+
body: new Uint8Array(arrayBuffer),
|
|
318
|
+
}
|
|
211
319
|
}
|
|
212
|
-
}
|
|
213
320
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
// bytes->LexValue in one step instead of bytes->text->JSON->LexValue.
|
|
218
|
-
// This would require adding encode/decode utilities to lex-json (similar
|
|
219
|
-
// to @ipld/dag-json)
|
|
220
|
-
const text = await response.text()
|
|
321
|
+
if (!isEncodingString(encoding)) {
|
|
322
|
+
throw new TypeError(`Invalid content-type "${encoding}" in response`)
|
|
323
|
+
}
|
|
221
324
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
325
|
+
if (options?.parse && encoding === CONTENT_TYPE_JSON) {
|
|
326
|
+
// @NOTE It might be worth returning the raw bytes here (Uint8Array) and
|
|
327
|
+
// perform the lex parsing using cborg/json, allowing to do
|
|
328
|
+
// bytes->LexValue in one step instead of bytes->text->JSON->LexValue.
|
|
329
|
+
// This would require adding encode/decode utilities to lex-json (similar
|
|
330
|
+
// to @ipld/dag-json)
|
|
331
|
+
const text = await response.text()
|
|
225
332
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
333
|
+
// @NOTE Using `lexParse(text)` (instead of `jsonToLex(json)`) here as
|
|
334
|
+
// using a reviver function during JSON.parse should be faster than
|
|
335
|
+
// parsing to JSON then converting to Lex (?)
|
|
336
|
+
|
|
337
|
+
// @TODO verify statement above
|
|
338
|
+
return { encoding, body: lexParse(text, options.parse) }
|
|
339
|
+
}
|
|
229
340
|
|
|
230
|
-
|
|
341
|
+
const arrayBuffer = await response.arrayBuffer()
|
|
342
|
+
return { encoding, body: new Uint8Array(arrayBuffer) }
|
|
343
|
+
} catch (cause) {
|
|
344
|
+
const message = 'Unable to parse response payload'
|
|
345
|
+
const messageDetail = cause instanceof TypeError ? cause.message : undefined
|
|
346
|
+
throw new XrpcUpstreamError(
|
|
347
|
+
method,
|
|
348
|
+
response,
|
|
349
|
+
null,
|
|
350
|
+
messageDetail ? `${message}: ${messageDetail}` : message,
|
|
351
|
+
{ cause },
|
|
352
|
+
)
|
|
353
|
+
}
|
|
231
354
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { DidString, UnknownString } from '@atproto/lex-schema'
|
|
1
|
+
import { DidString, LexValue, UnknownString } from '@atproto/lex-schema'
|
|
2
2
|
|
|
3
|
-
export type { DidString, UnknownString }
|
|
3
|
+
export type { DidString, LexValue, UnknownString }
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Service identifier fragment for DID service endpoints.
|
|
@@ -22,44 +22,6 @@ export type DidServiceIdentifier = 'atproto_labeler' | UnknownString
|
|
|
22
22
|
*/
|
|
23
23
|
export type Service = `${DidString}#${DidServiceIdentifier}`
|
|
24
24
|
|
|
25
|
-
/**
|
|
26
|
-
* Common options available for all XRPC calls.
|
|
27
|
-
*
|
|
28
|
-
* These options can be passed to any method that makes XRPC requests,
|
|
29
|
-
* including `xrpc()`, `call()`, and record operations.
|
|
30
|
-
*/
|
|
31
|
-
export type CallOptions = {
|
|
32
|
-
/** Labeler DIDs to request labels from for content moderation. */
|
|
33
|
-
labelers?: Iterable<DidString>
|
|
34
|
-
/** AbortSignal to cancel the request. */
|
|
35
|
-
signal?: AbortSignal
|
|
36
|
-
/** Additional HTTP headers to include in the request. */
|
|
37
|
-
headers?: HeadersInit
|
|
38
|
-
/** Service proxy identifier for routing requests through a specific service. */
|
|
39
|
-
service?: Service
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Whether to validate the request against the method's input schema. Enabling
|
|
43
|
-
* this can help catch errors early but may have a performance cost. This
|
|
44
|
-
* would typically only be set to `true` in development or debugging
|
|
45
|
-
* scenarios.
|
|
46
|
-
*
|
|
47
|
-
* @default false
|
|
48
|
-
*/
|
|
49
|
-
validateRequest?: boolean
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Whether to validate the response against the method's output schema.
|
|
53
|
-
* Disabling this can improve performance but may lead to runtime errors if
|
|
54
|
-
* the response does not conform to the expected schema. Only set this to
|
|
55
|
-
* `false` if you are certain that the upstream service will always return
|
|
56
|
-
* valid responses.
|
|
57
|
-
*
|
|
58
|
-
* @default true
|
|
59
|
-
*/
|
|
60
|
-
validateResponse?: boolean
|
|
61
|
-
}
|
|
62
|
-
|
|
63
25
|
/**
|
|
64
26
|
* Valid input types for binary request bodies.
|
|
65
27
|
*
|
|
@@ -92,3 +54,18 @@ export type BinaryBodyInit =
|
|
|
92
54
|
| ReadableStream<Uint8Array>
|
|
93
55
|
| AsyncIterable<Uint8Array>
|
|
94
56
|
| string
|
|
57
|
+
|
|
58
|
+
export type EncodingString = `${string}/${string}`
|
|
59
|
+
|
|
60
|
+
export function isEncodingString(
|
|
61
|
+
contentType: string,
|
|
62
|
+
): contentType is EncodingString {
|
|
63
|
+
return contentType.includes('/')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export type XrpcUnknownResponsePayload<
|
|
67
|
+
TBinary extends BinaryBodyInit = Uint8Array,
|
|
68
|
+
> = {
|
|
69
|
+
encoding: EncodingString
|
|
70
|
+
body: LexValue | TBinary
|
|
71
|
+
}
|