@atproto/lex-client 0.0.17 → 0.0.19
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 +30 -0
- package/dist/client.d.ts +2 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +4 -0
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +18 -19
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +62 -37
- package/dist/errors.js.map +1 -1
- package/dist/lexicons/com/atproto/repo/uploadBlob.defs.d.ts +2 -6
- package/dist/lexicons/com/atproto/repo/uploadBlob.defs.d.ts.map +1 -1
- package/dist/lexicons/com/atproto/repo/uploadBlob.defs.js +1 -3
- package/dist/lexicons/com/atproto/repo/uploadBlob.defs.js.map +1 -1
- package/dist/response.d.ts +7 -3
- package/dist/response.d.ts.map +1 -1
- package/dist/response.js +41 -46
- package/dist/response.js.map +1 -1
- package/dist/xrpc.js +1 -1
- package/dist/xrpc.js.map +1 -1
- package/package.json +6 -6
- package/src/client.ts +3 -1
- package/src/errors.test.ts +243 -32
- package/src/errors.ts +86 -49
- package/src/lexicons/com/atproto/repo/uploadBlob.defs.ts +1 -3
- package/src/response.ts +60 -65
- package/src/xrpc.test.ts +80 -83
- package/src/xrpc.ts +1 -3
package/src/errors.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
LexError,
|
|
3
|
+
LexErrorCode,
|
|
4
|
+
LexErrorData,
|
|
5
|
+
LexValue,
|
|
6
|
+
} from '@atproto/lex-data'
|
|
2
7
|
import {
|
|
3
8
|
InferMethodError,
|
|
4
9
|
LexValidationError,
|
|
@@ -15,6 +20,28 @@ import {
|
|
|
15
20
|
parseWWWAuthenticateHeader,
|
|
16
21
|
} from './www-authenticate.js'
|
|
17
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Mapping that allows generating an XRPC error code from an HTTP status code
|
|
25
|
+
* when the response does not contain a valid XRPC error payload. This is used
|
|
26
|
+
* to convert non-XRPC error responses from upstream servers into a standardized
|
|
27
|
+
* XRPC error for downstream clients.
|
|
28
|
+
*/
|
|
29
|
+
const StatusErrorCodes = new Map<number, LexErrorCode>([
|
|
30
|
+
[400, 'InvalidRequest'],
|
|
31
|
+
[401, 'AuthenticationRequired'],
|
|
32
|
+
[403, 'Forbidden'],
|
|
33
|
+
[404, 'XRPCNotSupported'],
|
|
34
|
+
[406, 'NotAcceptable'],
|
|
35
|
+
[413, 'PayloadTooLarge'],
|
|
36
|
+
[415, 'UnsupportedMediaType'],
|
|
37
|
+
[429, 'RateLimitExceeded'],
|
|
38
|
+
[500, 'InternalServerError'],
|
|
39
|
+
[501, 'MethodNotImplemented'],
|
|
40
|
+
[502, 'UpstreamFailure'],
|
|
41
|
+
[503, 'NotEnoughResources'],
|
|
42
|
+
[504, 'UpstreamTimeout'],
|
|
43
|
+
])
|
|
44
|
+
|
|
18
45
|
export type { XrpcUnknownResponsePayload }
|
|
19
46
|
|
|
20
47
|
export type DownstreamError<N extends LexErrorCode = LexErrorCode> = {
|
|
@@ -90,7 +117,7 @@ export function isXrpcErrorPayload(
|
|
|
90
117
|
* @typeParam TReason - The reason type for ResultFailure
|
|
91
118
|
*
|
|
92
119
|
* @see {@link XrpcResponseError} - For valid XRPC error responses
|
|
93
|
-
* @see {@link
|
|
120
|
+
* @see {@link XrpcInvalidResponseError} - For invalid/unexpected responses
|
|
94
121
|
* @see {@link XrpcInternalError} - For network/internal errors
|
|
95
122
|
*/
|
|
96
123
|
export abstract class XrpcError<
|
|
@@ -160,17 +187,23 @@ export abstract class XrpcError<
|
|
|
160
187
|
*/
|
|
161
188
|
export class XrpcResponseError<
|
|
162
189
|
M extends Procedure | Query = Procedure | Query,
|
|
163
|
-
|
|
164
|
-
> extends XrpcError<M, N, XrpcResponseError<M, N>> {
|
|
190
|
+
> extends XrpcError<M, LexErrorCode, XrpcResponseError<M>> {
|
|
165
191
|
name = 'XrpcResponseError'
|
|
166
192
|
|
|
167
193
|
constructor(
|
|
168
194
|
method: M,
|
|
169
195
|
readonly response: Response,
|
|
170
|
-
readonly payload
|
|
196
|
+
readonly payload?: XrpcUnknownResponsePayload,
|
|
171
197
|
options?: ErrorOptions,
|
|
172
198
|
) {
|
|
173
|
-
const { error, message } = payload
|
|
199
|
+
const { error, message } = isXrpcErrorPayload(payload)
|
|
200
|
+
? payload.body
|
|
201
|
+
: {
|
|
202
|
+
error:
|
|
203
|
+
StatusErrorCodes.get(response.status) ??
|
|
204
|
+
(response.status >= 500 ? 'UpstreamFailure' : 'InvalidRequest'),
|
|
205
|
+
message: buildResponseOverviewMessage(response),
|
|
206
|
+
}
|
|
174
207
|
super(method, error, message, options)
|
|
175
208
|
}
|
|
176
209
|
|
|
@@ -182,19 +215,27 @@ export class XrpcResponseError<
|
|
|
182
215
|
return RETRYABLE_HTTP_STATUS_CODES.has(this.response.status)
|
|
183
216
|
}
|
|
184
217
|
|
|
185
|
-
override toJSON(): LexErrorData
|
|
186
|
-
|
|
218
|
+
override toJSON(): LexErrorData {
|
|
219
|
+
// Return the original error payload if it's a valid XRPC error, otherwise
|
|
220
|
+
// convert to an XRPC error format.
|
|
221
|
+
const { payload } = this
|
|
222
|
+
if (isXrpcErrorPayload(payload)) {
|
|
223
|
+
return payload.body
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return super.toJSON()
|
|
187
227
|
}
|
|
188
228
|
|
|
189
229
|
override toDownstreamError(): DownstreamError {
|
|
190
|
-
|
|
230
|
+
const { status, headers } = this.response
|
|
231
|
+
// If the upstream server returned a 500 error, we want to return a 502 Bad
|
|
191
232
|
// Gateway to downstream clients, as the issue is with the upstream server,
|
|
192
233
|
// not us. We still return the original error code and message in the body
|
|
193
234
|
// for transparency, but we do not want to expose internal server errors
|
|
194
235
|
// from the upstream server as-is to downstream clients.
|
|
195
236
|
return {
|
|
196
|
-
status:
|
|
197
|
-
headers: stripHopByHopHeaders(
|
|
237
|
+
status: status === 500 ? 502 : status,
|
|
238
|
+
headers: stripHopByHopHeaders(headers),
|
|
198
239
|
body: this.toJSON(),
|
|
199
240
|
}
|
|
200
241
|
}
|
|
@@ -207,8 +248,8 @@ export class XrpcResponseError<
|
|
|
207
248
|
return this.response.headers
|
|
208
249
|
}
|
|
209
250
|
|
|
210
|
-
get body():
|
|
211
|
-
return this.payload
|
|
251
|
+
get body(): undefined | Uint8Array | LexValue {
|
|
252
|
+
return this.payload?.body
|
|
212
253
|
}
|
|
213
254
|
}
|
|
214
255
|
|
|
@@ -242,8 +283,7 @@ export type { WWWAuthenticate }
|
|
|
242
283
|
*/
|
|
243
284
|
export class XrpcAuthenticationError<
|
|
244
285
|
M extends Procedure | Query = Procedure | Query,
|
|
245
|
-
|
|
246
|
-
> extends XrpcResponseError<M, N> {
|
|
286
|
+
> extends XrpcResponseError<M> {
|
|
247
287
|
name = 'XrpcAuthenticationError'
|
|
248
288
|
|
|
249
289
|
override shouldRetry(): boolean {
|
|
@@ -261,14 +301,6 @@ export class XrpcAuthenticationError<
|
|
|
261
301
|
this.response.headers.get('www-authenticate'),
|
|
262
302
|
) ?? {})
|
|
263
303
|
}
|
|
264
|
-
|
|
265
|
-
override toDownstreamError(): DownstreamError {
|
|
266
|
-
return {
|
|
267
|
-
status: 401,
|
|
268
|
-
headers: stripHopByHopHeaders(this.headers),
|
|
269
|
-
body: this.toJSON(),
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
304
|
}
|
|
273
305
|
|
|
274
306
|
/**
|
|
@@ -281,24 +313,25 @@ export class XrpcAuthenticationError<
|
|
|
281
313
|
* - Non-JSON error responses
|
|
282
314
|
* - Responses from non-XRPC endpoints
|
|
283
315
|
*
|
|
284
|
-
* The error code is always '
|
|
285
|
-
* when converted to a response.
|
|
316
|
+
* The error code is always 'InvalidResponse' and maps to HTTP 502 Bad Gateway
|
|
317
|
+
* when converted to a response. This should allow downstream clients to
|
|
318
|
+
* determine at which boundary the error occurred.
|
|
286
319
|
*
|
|
287
320
|
* @typeParam M - The XRPC method type
|
|
288
321
|
*/
|
|
289
|
-
export class
|
|
322
|
+
export class XrpcInvalidResponseError<
|
|
290
323
|
M extends Procedure | Query = Procedure | Query,
|
|
291
|
-
> extends XrpcError<M, '
|
|
292
|
-
name = '
|
|
324
|
+
> extends XrpcError<M, 'InvalidResponse', XrpcInvalidResponseError<M>> {
|
|
325
|
+
name = 'XrpcInvalidResponseError'
|
|
293
326
|
|
|
294
327
|
constructor(
|
|
295
328
|
method: M,
|
|
296
329
|
readonly response: Response,
|
|
297
|
-
readonly payload
|
|
298
|
-
message: string =
|
|
330
|
+
readonly payload?: XrpcUnknownResponsePayload,
|
|
331
|
+
message: string = buildResponseOverviewMessage(response),
|
|
299
332
|
options?: ErrorOptions,
|
|
300
333
|
) {
|
|
301
|
-
super(method, '
|
|
334
|
+
super(method, 'InvalidResponse', message, options)
|
|
302
335
|
}
|
|
303
336
|
|
|
304
337
|
override get reason(): this {
|
|
@@ -317,7 +350,7 @@ export class XrpcUpstreamError<
|
|
|
317
350
|
/**
|
|
318
351
|
* Error class for invalid XRPC responses that fail schema validation.
|
|
319
352
|
*
|
|
320
|
-
* This is a specific type of {@link
|
|
353
|
+
* This is a specific type of {@link XrpcInvalidResponseError} that indicates the
|
|
321
354
|
* upstream server returned a response that was structurally valid but did not
|
|
322
355
|
* conform to the expected schema for the method. This likely indicates a
|
|
323
356
|
* mismatch between client and server versions or an issue with the server's
|
|
@@ -325,10 +358,10 @@ export class XrpcUpstreamError<
|
|
|
325
358
|
*
|
|
326
359
|
* @typeParam M - The XRPC method type
|
|
327
360
|
*/
|
|
328
|
-
export class
|
|
361
|
+
export class XrpcResponseValidationError<
|
|
329
362
|
M extends Procedure | Query = Procedure | Query,
|
|
330
|
-
> extends
|
|
331
|
-
name = '
|
|
363
|
+
> extends XrpcInvalidResponseError<M> {
|
|
364
|
+
name = 'XrpcResponseValidationError'
|
|
332
365
|
|
|
333
366
|
constructor(
|
|
334
367
|
method: M,
|
|
@@ -336,17 +369,13 @@ export class XrpcInvalidResponseError<
|
|
|
336
369
|
payload: XrpcUnknownResponsePayload,
|
|
337
370
|
readonly cause: LexValidationError,
|
|
338
371
|
) {
|
|
339
|
-
super(
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
// ("they" are at fault). We are using 502 here to allow downstream clients
|
|
347
|
-
// to determine that the issue lies at the interface between us and the
|
|
348
|
-
// upstream server, rather than an issue with our internal processing.
|
|
349
|
-
return { status: 502, body: this.toJSON() }
|
|
372
|
+
super(
|
|
373
|
+
method,
|
|
374
|
+
response,
|
|
375
|
+
payload,
|
|
376
|
+
`Invalid response payload: ${cause.message}`,
|
|
377
|
+
{ cause },
|
|
378
|
+
)
|
|
350
379
|
}
|
|
351
380
|
}
|
|
352
381
|
|
|
@@ -448,7 +477,7 @@ export class XrpcFetchError<
|
|
|
448
477
|
* if (result.success) {
|
|
449
478
|
* console.log(result.body) // XrpcResponse
|
|
450
479
|
* } else {
|
|
451
|
-
* // result is XrpcFailure (XrpcResponseError |
|
|
480
|
+
* // result is XrpcFailure (XrpcResponseError | XrpcInvalidResponseError | XrpcInternalError)
|
|
452
481
|
* console.error(result.error, result.message)
|
|
453
482
|
* }
|
|
454
483
|
* ```
|
|
@@ -457,7 +486,7 @@ export type XrpcFailure<M extends Procedure | Query = Procedure | Query> =
|
|
|
457
486
|
// The server returned a valid XRPC error response
|
|
458
487
|
| XrpcResponseError<M>
|
|
459
488
|
// The response was not a valid XRPC response, or it does not match the schema
|
|
460
|
-
|
|
|
489
|
+
| XrpcInvalidResponseError<M>
|
|
461
490
|
// Something went wrong (network error, etc.)
|
|
462
491
|
| XrpcInternalError<M>
|
|
463
492
|
|
|
@@ -487,7 +516,7 @@ export function asXrpcFailure<M extends Procedure | Query>(
|
|
|
487
516
|
): XrpcFailure<M> {
|
|
488
517
|
if (
|
|
489
518
|
cause instanceof XrpcResponseError ||
|
|
490
|
-
cause instanceof
|
|
519
|
+
cause instanceof XrpcInvalidResponseError ||
|
|
491
520
|
cause instanceof XrpcInternalError
|
|
492
521
|
) {
|
|
493
522
|
if (cause.method === method) return cause
|
|
@@ -531,3 +560,11 @@ function stripHopByHopHeaders(headers: Headers): Headers {
|
|
|
531
560
|
|
|
532
561
|
return result
|
|
533
562
|
}
|
|
563
|
+
|
|
564
|
+
function buildResponseOverviewMessage(response: Response): string {
|
|
565
|
+
if (response.status < 400) {
|
|
566
|
+
return `Upstream server responded with an invalid status code (${response.status})`
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return `Upstream server responded with a ${response.status} error`
|
|
570
|
+
}
|
|
@@ -15,9 +15,7 @@ const main =
|
|
|
15
15
|
$nsid,
|
|
16
16
|
/*#__PURE__*/ l.params(),
|
|
17
17
|
/*#__PURE__*/ l.payload('*/*'),
|
|
18
|
-
/*#__PURE__*/ l.jsonPayload({
|
|
19
|
-
blob: /*#__PURE__*/ l.blob({ allowLegacy: false }),
|
|
20
|
-
}),
|
|
18
|
+
/*#__PURE__*/ l.jsonPayload({ blob: /*#__PURE__*/ l.blob() }),
|
|
21
19
|
)
|
|
22
20
|
export { main }
|
|
23
21
|
|
package/src/response.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LexParseOptions,
|
|
1
|
+
import { LexParseOptions, lexParseJsonBytes } from '@atproto/lex-json'
|
|
2
2
|
import {
|
|
3
3
|
InferMethodOutputEncoding,
|
|
4
4
|
InferOutput,
|
|
@@ -13,8 +13,7 @@ import {
|
|
|
13
13
|
XrpcAuthenticationError,
|
|
14
14
|
XrpcInvalidResponseError,
|
|
15
15
|
XrpcResponseError,
|
|
16
|
-
|
|
17
|
-
isXrpcErrorPayload,
|
|
16
|
+
XrpcResponseValidationError,
|
|
18
17
|
} from './errors.js'
|
|
19
18
|
import {
|
|
20
19
|
EncodingString,
|
|
@@ -58,7 +57,7 @@ export type XrpcResponseBody<M extends Procedure | Query> =
|
|
|
58
57
|
M['output'] extends Payload<infer TEncoding, infer TSchema>
|
|
59
58
|
? TEncoding extends string
|
|
60
59
|
? InferBodyType<TEncoding, TSchema>
|
|
61
|
-
: undefined
|
|
60
|
+
: undefined | LexValue | Uint8Array
|
|
62
61
|
: never
|
|
63
62
|
|
|
64
63
|
/**
|
|
@@ -75,7 +74,9 @@ export type XrpcResponsePayload<M extends Procedure | Query> =
|
|
|
75
74
|
encoding: InferEncodingType<TEncoding>
|
|
76
75
|
body: InferBodyType<TEncoding, TSchema>
|
|
77
76
|
}
|
|
78
|
-
:
|
|
77
|
+
: // If the schema does not specify an output encoding, anything could be
|
|
78
|
+
// returned, including no payload at all (undefined).
|
|
79
|
+
undefined | { body: LexValue | Uint8Array; encoding: string }
|
|
79
80
|
: never
|
|
80
81
|
|
|
81
82
|
export type XrpcResponseOptions = {
|
|
@@ -170,7 +171,7 @@ export class XrpcResponse<M extends Procedure | Query>
|
|
|
170
171
|
* {@link XrpcResponseError.matchesSchemaErrors} to narrow the error type based on
|
|
171
172
|
* the method's declared error schema. This can be narrowed further as a
|
|
172
173
|
* {@link XrpcAuthenticationError} if the error is an authentication error.
|
|
173
|
-
* @throws {
|
|
174
|
+
* @throws {XrpcInvalidResponseError} when the response is not a valid XRPC
|
|
174
175
|
* response, or if the response does not conform to the method's schema.
|
|
175
176
|
*/
|
|
176
177
|
static async fromFetchResponse<const M extends Procedure | Query>(
|
|
@@ -182,63 +183,62 @@ export class XrpcResponse<M extends Procedure | Query>
|
|
|
182
183
|
// Since nothing should cause an exception before "readPayload" is
|
|
183
184
|
// called, we can safely not use a try/finally here.
|
|
184
185
|
|
|
185
|
-
//
|
|
186
|
-
if (response.status
|
|
187
|
-
// Always parse json for error responses
|
|
186
|
+
// Always turn 4xx/5xx responses into XrpcResponseError
|
|
187
|
+
if (response.status >= 400) {
|
|
188
188
|
const payload = await readPayload(method, response, {
|
|
189
|
-
|
|
189
|
+
// Always parse errors in non-strict mode
|
|
190
|
+
parse: { strict: false },
|
|
190
191
|
})
|
|
191
192
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
throw response.status === 401
|
|
195
|
-
? new XrpcAuthenticationError<M>(method, response, payload)
|
|
196
|
-
: new XrpcResponseError<M>(method, response, payload)
|
|
193
|
+
if (response.status === 401) {
|
|
194
|
+
throw new XrpcAuthenticationError<M>(method, response, payload)
|
|
197
195
|
}
|
|
198
196
|
|
|
199
|
-
|
|
200
|
-
|
|
197
|
+
throw new XrpcResponseError<M>(method, response, payload)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// @NOTE redirect is set to 'follow', so we shouldn't get 3xx responses here
|
|
201
|
+
if (response.status < 200 || response.status >= 300) {
|
|
202
|
+
await response.body?.cancel()
|
|
203
|
+
|
|
204
|
+
throw new XrpcInvalidResponseError(
|
|
201
205
|
method,
|
|
202
206
|
response,
|
|
203
|
-
|
|
204
|
-
response.status
|
|
205
|
-
? 'Upstream server encountered an error'
|
|
206
|
-
: response.status >= 400
|
|
207
|
-
? 'Invalid response payload'
|
|
208
|
-
: 'Invalid response status code',
|
|
207
|
+
undefined,
|
|
208
|
+
`Unexpected status code ${response.status}`,
|
|
209
209
|
)
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
const payload = await readPayload(method, response, {
|
|
213
|
-
//
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
213
|
+
// Parse response if there is a schema, or if the encoding is
|
|
214
|
+
// "application/json"
|
|
215
|
+
parse:
|
|
216
|
+
method.output.schema || method.output.encoding === CONTENT_TYPE_JSON
|
|
217
|
+
? { strict: options?.strictResponseProcessing ?? true }
|
|
218
|
+
: // If there is no declared output encoding, we'll parse the output (in loose mode)
|
|
219
|
+
method.output.encoding == null
|
|
220
|
+
? { strict: false }
|
|
221
|
+
: false,
|
|
217
222
|
})
|
|
218
223
|
|
|
224
|
+
if (!method.output.matchesEncoding(payload?.encoding)) {
|
|
225
|
+
throw new XrpcInvalidResponseError(
|
|
226
|
+
method,
|
|
227
|
+
response,
|
|
228
|
+
payload,
|
|
229
|
+
`Expected ${stringifyEncoding(method.output.encoding)} response (got ${stringifyEncoding(payload?.encoding)})`,
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
|
|
219
233
|
// Response is successful (2xx). Validate payload (data and encoding) against schema.
|
|
220
|
-
if (method.output.encoding
|
|
221
|
-
//
|
|
222
|
-
if
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
)
|
|
229
|
-
}
|
|
230
|
-
} else {
|
|
231
|
-
// Schema expects a payload
|
|
232
|
-
if (!payload || !method.output.matchesEncoding(payload.encoding)) {
|
|
233
|
-
throw new XrpcUpstreamError(
|
|
234
|
-
method,
|
|
235
|
-
response,
|
|
236
|
-
payload,
|
|
237
|
-
payload
|
|
238
|
-
? `Expected ${method.output.encoding} response, got ${payload.encoding}`
|
|
239
|
-
: `Expected non-empty response with content-type ${method.output.encoding}`,
|
|
240
|
-
)
|
|
241
|
-
}
|
|
234
|
+
if (method.output.encoding != null) {
|
|
235
|
+
// If the schema specifies an output, verify that the response properly
|
|
236
|
+
// matches the expected format (encoding and schema, if present). If no
|
|
237
|
+
// output is specified, any payload could be returned.
|
|
238
|
+
|
|
239
|
+
// Needed for type safety. Should never happen since matchesEncoding()
|
|
240
|
+
// should return not succeed if there is a schema encoding but no payload.
|
|
241
|
+
if (!payload) throw new Error('Expected payload')
|
|
242
242
|
|
|
243
243
|
// Assert valid response body.
|
|
244
244
|
if (method.output.schema && options?.validateResponse !== false) {
|
|
@@ -247,7 +247,7 @@ export class XrpcResponse<M extends Procedure | Query>
|
|
|
247
247
|
})
|
|
248
248
|
|
|
249
249
|
if (!result.success) {
|
|
250
|
-
throw new
|
|
250
|
+
throw new XrpcResponseValidationError(
|
|
251
251
|
method,
|
|
252
252
|
response,
|
|
253
253
|
payload,
|
|
@@ -323,19 +323,10 @@ async function readPayload(
|
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
if (options?.parse && encoding === CONTENT_TYPE_JSON) {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
// to @ipld/dag-json)
|
|
331
|
-
const text = await response.text()
|
|
332
|
-
|
|
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) }
|
|
326
|
+
const arrayBuffer = await response.arrayBuffer()
|
|
327
|
+
const bytes = new Uint8Array(arrayBuffer)
|
|
328
|
+
const body = lexParseJsonBytes(bytes, options.parse)
|
|
329
|
+
return { encoding, body }
|
|
339
330
|
}
|
|
340
331
|
|
|
341
332
|
const arrayBuffer = await response.arrayBuffer()
|
|
@@ -343,12 +334,16 @@ async function readPayload(
|
|
|
343
334
|
} catch (cause) {
|
|
344
335
|
const message = 'Unable to parse response payload'
|
|
345
336
|
const messageDetail = cause instanceof TypeError ? cause.message : undefined
|
|
346
|
-
throw new
|
|
337
|
+
throw new XrpcInvalidResponseError(
|
|
347
338
|
method,
|
|
348
339
|
response,
|
|
349
|
-
|
|
340
|
+
undefined,
|
|
350
341
|
messageDetail ? `${message}: ${messageDetail}` : message,
|
|
351
342
|
{ cause },
|
|
352
343
|
)
|
|
353
344
|
}
|
|
354
345
|
}
|
|
346
|
+
|
|
347
|
+
function stringifyEncoding(encoding: string | undefined) {
|
|
348
|
+
return encoding ? `"${encoding}"` : 'no payload'
|
|
349
|
+
}
|