@atproto/lex-client 0.0.9 → 0.0.10
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 +15 -0
- package/LICENSE.txt +1 -1
- package/dist/client.d.ts +56 -39
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -6
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +15 -15
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +17 -17
- package/dist/errors.js.map +1 -1
- package/dist/lexicons/com/atproto/repo/createRecord.defs.d.ts +20 -10
- package/dist/lexicons/com/atproto/repo/createRecord.defs.d.ts.map +1 -1
- package/dist/lexicons/com/atproto/repo/defs.defs.d.ts +1 -1
- package/dist/lexicons/com/atproto/repo/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/com/atproto/repo/deleteRecord.defs.d.ts +14 -6
- package/dist/lexicons/com/atproto/repo/deleteRecord.defs.d.ts.map +1 -1
- package/dist/lexicons/com/atproto/repo/getRecord.defs.d.ts +12 -4
- package/dist/lexicons/com/atproto/repo/getRecord.defs.d.ts.map +1 -1
- package/dist/lexicons/com/atproto/repo/listRecords.defs.d.ts +11 -11
- package/dist/lexicons/com/atproto/repo/listRecords.defs.d.ts.map +1 -1
- package/dist/lexicons/com/atproto/repo/listRecords.defs.js +2 -1
- package/dist/lexicons/com/atproto/repo/listRecords.defs.js.map +1 -1
- package/dist/lexicons/com/atproto/repo/putRecord.defs.d.ts +18 -10
- package/dist/lexicons/com/atproto/repo/putRecord.defs.d.ts.map +1 -1
- package/dist/response.d.ts +12 -12
- package/dist/response.d.ts.map +1 -1
- package/dist/response.js +17 -19
- package/dist/response.js.map +1 -1
- package/dist/util.d.ts +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js.map +1 -1
- package/dist/xrpc.d.ts +17 -16
- package/dist/xrpc.d.ts.map +1 -1
- package/dist/xrpc.js +12 -16
- package/dist/xrpc.js.map +1 -1
- package/package.json +6 -6
- package/src/client.ts +33 -32
- package/src/errors.ts +26 -28
- package/src/lexicons/com/atproto/repo/listRecords.defs.ts +4 -1
- package/src/response.ts +28 -30
- package/src/util.ts +1 -1
- package/src/xrpc.ts +58 -68
package/src/errors.ts
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { LexError, LexErrorCode, LexErrorData } from '@atproto/lex-data'
|
|
2
2
|
import { l } from '@atproto/lex-schema'
|
|
3
|
-
import {
|
|
3
|
+
import { XrpcPayload } from './util.js'
|
|
4
4
|
|
|
5
5
|
export { LexError }
|
|
6
6
|
export type { LexErrorCode, LexErrorData }
|
|
7
7
|
|
|
8
|
-
export type
|
|
9
|
-
LexErrorData<N>,
|
|
10
|
-
'application/json'
|
|
11
|
-
>
|
|
8
|
+
export type XrpcErrorPayload<N extends LexErrorCode = LexErrorCode> =
|
|
9
|
+
XrpcPayload<LexErrorData<N>, 'application/json'>
|
|
12
10
|
|
|
13
|
-
export class
|
|
11
|
+
export class XrpcError<
|
|
14
12
|
N extends LexErrorCode = LexErrorCode,
|
|
15
13
|
> extends LexError<N> {
|
|
16
|
-
name = '
|
|
14
|
+
name = 'XrpcError'
|
|
17
15
|
|
|
18
16
|
constructor(
|
|
19
17
|
error: N,
|
|
@@ -36,9 +34,9 @@ export class LexRpcError<
|
|
|
36
34
|
*
|
|
37
35
|
* This function checks whether a given payload matches this schema.
|
|
38
36
|
*/
|
|
39
|
-
export function
|
|
40
|
-
payload:
|
|
41
|
-
): payload is
|
|
37
|
+
export function isXrpcErrorPayload(
|
|
38
|
+
payload: XrpcPayload | null,
|
|
39
|
+
): payload is XrpcErrorPayload {
|
|
42
40
|
return (
|
|
43
41
|
payload !== null &&
|
|
44
42
|
payload.encoding === 'application/json' &&
|
|
@@ -59,20 +57,20 @@ type LexRpcFailureResult<N extends LexErrorCode, E> = l.ResultFailure<E> & {
|
|
|
59
57
|
* Class used to represent an HTTP request that resulted in an XRPC method error
|
|
60
58
|
* That is, a non-2xx response with a valid XRPC error payload.
|
|
61
59
|
*/
|
|
62
|
-
export class
|
|
60
|
+
export class XrpcResponseError<
|
|
63
61
|
M extends l.Procedure | l.Query = l.Procedure | l.Query,
|
|
64
62
|
N extends LexErrorCode = LexErrorCode,
|
|
65
63
|
>
|
|
66
|
-
extends
|
|
67
|
-
implements LexRpcFailureResult<N,
|
|
64
|
+
extends XrpcError<N>
|
|
65
|
+
implements LexRpcFailureResult<N, XrpcResponseError<M, N>>
|
|
68
66
|
{
|
|
69
|
-
name = '
|
|
67
|
+
name = 'XrpcResponseError'
|
|
70
68
|
|
|
71
69
|
constructor(
|
|
72
70
|
readonly method: M,
|
|
73
71
|
readonly status: number,
|
|
74
72
|
readonly headers: Headers,
|
|
75
|
-
readonly payload:
|
|
73
|
+
readonly payload: XrpcErrorPayload<N>,
|
|
76
74
|
options?: ErrorOptions,
|
|
77
75
|
) {
|
|
78
76
|
const { error, message } = payload.body
|
|
@@ -92,7 +90,7 @@ export class LexRpcResponseError<
|
|
|
92
90
|
matchesSchema(): this is M extends {
|
|
93
91
|
errors: readonly (infer E extends string)[]
|
|
94
92
|
}
|
|
95
|
-
?
|
|
93
|
+
? XrpcResponseError<M, E>
|
|
96
94
|
: never {
|
|
97
95
|
return this.method.errors?.includes(this.error) ?? false
|
|
98
96
|
}
|
|
@@ -117,28 +115,28 @@ export class LexRpcResponseError<
|
|
|
117
115
|
/**
|
|
118
116
|
* This class represents an invalid XRPC response from the server.
|
|
119
117
|
*/
|
|
120
|
-
export class
|
|
118
|
+
export class XrpcUpstreamError<
|
|
121
119
|
N extends 'InvalidResponse' | 'UpstreamFailure' =
|
|
122
120
|
| 'InvalidResponse'
|
|
123
121
|
| 'UpstreamFailure',
|
|
124
122
|
>
|
|
125
|
-
extends
|
|
126
|
-
implements LexRpcFailureResult<N,
|
|
123
|
+
extends XrpcError<N>
|
|
124
|
+
implements LexRpcFailureResult<N, XrpcUpstreamError<N>>
|
|
127
125
|
{
|
|
128
|
-
name = '
|
|
126
|
+
name = 'XrpcUpstreamError' as const
|
|
129
127
|
|
|
130
128
|
// For debugging purposes, we keep the response details here
|
|
131
129
|
readonly response: {
|
|
132
130
|
status: number
|
|
133
131
|
headers: Headers
|
|
134
|
-
payload:
|
|
132
|
+
payload: XrpcPayload | null
|
|
135
133
|
}
|
|
136
134
|
|
|
137
135
|
constructor(
|
|
138
136
|
error: N,
|
|
139
137
|
message: string,
|
|
140
138
|
response: { status: number; headers: Headers },
|
|
141
|
-
payload:
|
|
139
|
+
payload: XrpcPayload | null,
|
|
142
140
|
options?: ErrorOptions,
|
|
143
141
|
) {
|
|
144
142
|
super(error, message, { cause: options?.cause })
|
|
@@ -169,11 +167,11 @@ export class LexRpcUpstreamError<
|
|
|
169
167
|
}
|
|
170
168
|
}
|
|
171
169
|
|
|
172
|
-
export class
|
|
173
|
-
extends
|
|
170
|
+
export class XrpcUnexpectedError
|
|
171
|
+
extends XrpcError<'InternalServerError'>
|
|
174
172
|
implements LexRpcFailureResult<'InternalServerError', unknown>
|
|
175
173
|
{
|
|
176
|
-
name = '
|
|
174
|
+
name = 'XrpcUnexpectedError' as const
|
|
177
175
|
|
|
178
176
|
protected constructor(message: string, options: Required<ErrorOptions>) {
|
|
179
177
|
super('InternalServerError', message, options)
|
|
@@ -202,8 +200,8 @@ export class LexRpcUnexpectedError
|
|
|
202
200
|
message: string = cause instanceof LexError
|
|
203
201
|
? cause.message
|
|
204
202
|
: 'XRPC request failed',
|
|
205
|
-
):
|
|
206
|
-
if (cause instanceof
|
|
207
|
-
return new
|
|
203
|
+
): XrpcUnexpectedError {
|
|
204
|
+
if (cause instanceof XrpcUnexpectedError) return cause
|
|
205
|
+
return new XrpcUnexpectedError(message, { cause })
|
|
208
206
|
}
|
|
209
207
|
}
|
|
@@ -17,7 +17,10 @@ const main =
|
|
|
17
17
|
repo: /*#__PURE__*/ l.string({ format: 'at-identifier' }),
|
|
18
18
|
collection: /*#__PURE__*/ l.string({ format: 'nsid' }),
|
|
19
19
|
limit: /*#__PURE__*/ l.optional(
|
|
20
|
-
/*#__PURE__*/ l.
|
|
20
|
+
/*#__PURE__*/ l.withDefault(
|
|
21
|
+
/*#__PURE__*/ l.integer({ minimum: 1, maximum: 100 }),
|
|
22
|
+
50,
|
|
23
|
+
),
|
|
21
24
|
),
|
|
22
25
|
cursor: /*#__PURE__*/ l.optional(/*#__PURE__*/ l.string()),
|
|
23
26
|
reverse: /*#__PURE__*/ l.optional(/*#__PURE__*/ l.boolean()),
|
package/src/response.ts
CHANGED
|
@@ -7,27 +7,27 @@ import {
|
|
|
7
7
|
ResultSuccess,
|
|
8
8
|
} from '@atproto/lex-schema'
|
|
9
9
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
XrpcResponseError,
|
|
11
|
+
XrpcUpstreamError,
|
|
12
|
+
isXrpcErrorPayload,
|
|
13
13
|
} from './errors.js'
|
|
14
|
-
import {
|
|
14
|
+
import { XrpcPayload } from './util.js'
|
|
15
15
|
|
|
16
|
-
export type
|
|
16
|
+
export type XrpcResponseBody<M extends Procedure | Query> =
|
|
17
17
|
InferMethodOutputBody<M, Uint8Array>
|
|
18
18
|
|
|
19
|
-
export type
|
|
19
|
+
export type XrpcResponsePayload<M extends Procedure | Query> =
|
|
20
20
|
InferMethodOutputEncoding<M> extends infer E extends string
|
|
21
|
-
?
|
|
21
|
+
? XrpcPayload<XrpcResponseBody<M>, E>
|
|
22
22
|
: null
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Small container for XRPC response data.
|
|
26
26
|
*
|
|
27
|
-
* @implements {ResultSuccess<
|
|
27
|
+
* @implements {ResultSuccess<XrpcResponse<M>>} for convenience in result handling contexts.
|
|
28
28
|
*/
|
|
29
|
-
export class
|
|
30
|
-
implements ResultSuccess<
|
|
29
|
+
export class XrpcResponse<const M extends Procedure | Query>
|
|
30
|
+
implements ResultSuccess<XrpcResponse<M>>
|
|
31
31
|
{
|
|
32
32
|
/** @see {@link ResultSuccess.success} */
|
|
33
33
|
readonly success = true as const
|
|
@@ -41,7 +41,7 @@ export class LexRpcResponse<const M extends Procedure | Query>
|
|
|
41
41
|
readonly method: M,
|
|
42
42
|
readonly status: number,
|
|
43
43
|
readonly headers: Headers,
|
|
44
|
-
readonly payload:
|
|
44
|
+
readonly payload: XrpcResponsePayload<M>,
|
|
45
45
|
) {}
|
|
46
46
|
|
|
47
47
|
/**
|
|
@@ -57,21 +57,21 @@ export class LexRpcResponse<const M extends Procedure | Query>
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
get body() {
|
|
60
|
-
return this.payload?.body as
|
|
60
|
+
return this.payload?.body as XrpcResponseBody<M>
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
* @throws {
|
|
65
|
-
* {@link
|
|
64
|
+
* @throws {XrpcResponseError} in case of (valid) XRPC error responses. Use
|
|
65
|
+
* {@link XrpcResponseError.matchesSchema} to narrow the error type based on
|
|
66
66
|
* the method's declared error schema.
|
|
67
|
-
* @throws {
|
|
67
|
+
* @throws {XrpcUpstreamError} when the response is not a valid XRPC
|
|
68
68
|
* response, or if the response does not conform to the method's schema.
|
|
69
69
|
*/
|
|
70
70
|
static async fromFetchResponse<const M extends Procedure | Query>(
|
|
71
71
|
method: M,
|
|
72
72
|
response: Response,
|
|
73
73
|
options?: { validateResponse?: boolean },
|
|
74
|
-
): Promise<
|
|
74
|
+
): Promise<XrpcResponse<M>> {
|
|
75
75
|
// @NOTE The body MUST either be read or canceled to avoid resource leaks.
|
|
76
76
|
// Since nothing should cause an exception before "readPayload" is
|
|
77
77
|
// called, we can safely not use a try/finally here.
|
|
@@ -81,8 +81,8 @@ export class LexRpcResponse<const M extends Procedure | Query>
|
|
|
81
81
|
// Always parse json for error responses
|
|
82
82
|
const payload = await readPayload(response, { parse: true })
|
|
83
83
|
|
|
84
|
-
if (response.status >= 400 &&
|
|
85
|
-
throw new
|
|
84
|
+
if (response.status >= 400 && isXrpcErrorPayload(payload)) {
|
|
85
|
+
throw new XrpcResponseError(
|
|
86
86
|
method,
|
|
87
87
|
response.status,
|
|
88
88
|
response.headers,
|
|
@@ -91,7 +91,7 @@ export class LexRpcResponse<const M extends Procedure | Query>
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
if (response.status >= 500) {
|
|
94
|
-
throw new
|
|
94
|
+
throw new XrpcUpstreamError(
|
|
95
95
|
'UpstreamFailure',
|
|
96
96
|
`Upstream server encountered an error`,
|
|
97
97
|
response,
|
|
@@ -99,7 +99,7 @@ export class LexRpcResponse<const M extends Procedure | Query>
|
|
|
99
99
|
)
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
throw new
|
|
102
|
+
throw new XrpcUpstreamError(
|
|
103
103
|
'InvalidResponse',
|
|
104
104
|
response.status >= 400
|
|
105
105
|
? `Upstream server returned an invalid response payload`
|
|
@@ -118,7 +118,7 @@ export class LexRpcResponse<const M extends Procedure | Query>
|
|
|
118
118
|
if (method.output.encoding == null) {
|
|
119
119
|
// Schema expects no payload
|
|
120
120
|
if (payload) {
|
|
121
|
-
throw new
|
|
121
|
+
throw new XrpcUpstreamError(
|
|
122
122
|
'InvalidResponse',
|
|
123
123
|
`Expected response with no body, got ${payload.encoding}`,
|
|
124
124
|
response,
|
|
@@ -128,7 +128,7 @@ export class LexRpcResponse<const M extends Procedure | Query>
|
|
|
128
128
|
} else {
|
|
129
129
|
// Schema expects a payload
|
|
130
130
|
if (!payload || !method.output.matchesEncoding(payload.encoding)) {
|
|
131
|
-
throw new
|
|
131
|
+
throw new XrpcUpstreamError(
|
|
132
132
|
'InvalidResponse',
|
|
133
133
|
payload
|
|
134
134
|
? `Expected ${method.output.encoding} response, got ${payload.encoding}`
|
|
@@ -140,12 +140,10 @@ export class LexRpcResponse<const M extends Procedure | Query>
|
|
|
140
140
|
|
|
141
141
|
// Assert valid response body.
|
|
142
142
|
if (method.output.schema && options?.validateResponse !== false) {
|
|
143
|
-
const result = method.output.schema.safeParse(payload.body
|
|
144
|
-
allowTransform: false,
|
|
145
|
-
})
|
|
143
|
+
const result = method.output.schema.safeParse(payload.body)
|
|
146
144
|
|
|
147
145
|
if (!result.success) {
|
|
148
|
-
throw new
|
|
146
|
+
throw new XrpcUpstreamError(
|
|
149
147
|
'InvalidResponse',
|
|
150
148
|
`Response validation failed: ${result.reason.message}`,
|
|
151
149
|
response,
|
|
@@ -156,11 +154,11 @@ export class LexRpcResponse<const M extends Procedure | Query>
|
|
|
156
154
|
}
|
|
157
155
|
}
|
|
158
156
|
|
|
159
|
-
return new
|
|
157
|
+
return new XrpcResponse<M>(
|
|
160
158
|
method,
|
|
161
159
|
response.status,
|
|
162
160
|
response.headers,
|
|
163
|
-
payload as
|
|
161
|
+
payload as XrpcResponsePayload<M>,
|
|
164
162
|
)
|
|
165
163
|
}
|
|
166
164
|
}
|
|
@@ -175,7 +173,7 @@ function shouldParse(method: Procedure | Query) {
|
|
|
175
173
|
async function readPayload(
|
|
176
174
|
response: Response,
|
|
177
175
|
options?: { parse?: boolean },
|
|
178
|
-
): Promise<
|
|
176
|
+
): Promise<XrpcPayload | null> {
|
|
179
177
|
// @TODO Should we limit the maximum response size here (this could also be
|
|
180
178
|
// done by the FetchHandler)?
|
|
181
179
|
|
|
@@ -214,7 +212,7 @@ async function readPayload(
|
|
|
214
212
|
// @TODO verify statement above
|
|
215
213
|
return { encoding, body: lexParse(text) }
|
|
216
214
|
} catch (cause) {
|
|
217
|
-
throw new
|
|
215
|
+
throw new XrpcUpstreamError(
|
|
218
216
|
'InvalidResponse',
|
|
219
217
|
'Invalid JSON response body',
|
|
220
218
|
response,
|
package/src/util.ts
CHANGED
package/src/xrpc.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { LexValue, isLexScalar, isPlainObject } from '@atproto/lex-data'
|
|
2
2
|
import { lexStringify } from '@atproto/lex-json'
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
InferInput,
|
|
5
|
+
InferPayload,
|
|
6
6
|
Main,
|
|
7
7
|
Params,
|
|
8
|
-
|
|
9
|
-
Payload as LexPayload,
|
|
8
|
+
Payload,
|
|
10
9
|
Procedure,
|
|
11
10
|
Query,
|
|
12
11
|
Restricted,
|
|
@@ -15,14 +14,14 @@ import {
|
|
|
15
14
|
} from '@atproto/lex-schema'
|
|
16
15
|
import { Agent } from './agent.js'
|
|
17
16
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
XrpcResponseError,
|
|
18
|
+
XrpcUnexpectedError,
|
|
19
|
+
XrpcUpstreamError,
|
|
21
20
|
} from './errors.js'
|
|
22
|
-
import {
|
|
21
|
+
import { XrpcResponse } from './response.js'
|
|
23
22
|
import { BinaryBodyInit, CallOptions } from './types.js'
|
|
24
23
|
import {
|
|
25
|
-
|
|
24
|
+
XrpcPayload,
|
|
26
25
|
buildAtprotoHeaders,
|
|
27
26
|
isAsyncIterable,
|
|
28
27
|
isBlobLike,
|
|
@@ -30,106 +29,108 @@ import {
|
|
|
30
29
|
} from './util.js'
|
|
31
30
|
|
|
32
31
|
// If all params are optional, allow omitting the params object
|
|
33
|
-
type
|
|
32
|
+
type XrpcParamsOptions<P extends Params> =
|
|
34
33
|
NonNullable<unknown> extends P ? { params?: P } : { params: P }
|
|
35
34
|
|
|
36
|
-
type
|
|
37
|
-
M
|
|
38
|
-
|
|
39
|
-
>
|
|
35
|
+
export type XrpcRequestParams<M extends Procedure | Query | Subscription> =
|
|
36
|
+
InferInput<M['parameters']>
|
|
37
|
+
|
|
38
|
+
type XrpcRequestPayload<M extends Procedure | Query> = M extends Procedure
|
|
39
|
+
? InferPayload<M['input'], BinaryBodyInit>
|
|
40
|
+
: undefined
|
|
40
41
|
|
|
41
|
-
type
|
|
42
|
+
type XrpcInputOptions<In> = In extends { body: infer B; encoding: infer E }
|
|
42
43
|
? // encoding will be inferred from the schema at runtime if not provided
|
|
43
44
|
{ body: B; encoding?: E }
|
|
44
45
|
: { body?: undefined; encoding?: undefined }
|
|
45
46
|
|
|
46
|
-
export type
|
|
47
|
+
export type XrpcOptions<M extends Procedure | Query = Procedure | Query> =
|
|
47
48
|
CallOptions &
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
XrpcInputOptions<XrpcRequestPayload<M>> &
|
|
50
|
+
XrpcParamsOptions<XrpcRequestParams<M>>
|
|
50
51
|
|
|
51
|
-
export type
|
|
52
|
+
export type XrpcFailure<M extends Procedure | Query> =
|
|
52
53
|
// The server returned a valid XRPC error response
|
|
53
|
-
|
|
|
54
|
+
| XrpcResponseError<M>
|
|
54
55
|
// The response was not a valid XRPC response, or it does not match the schema
|
|
55
|
-
|
|
|
56
|
+
| XrpcUpstreamError
|
|
56
57
|
// Something went wrong (network error, etc.)
|
|
57
|
-
|
|
|
58
|
+
| XrpcUnexpectedError
|
|
58
59
|
|
|
59
|
-
export type
|
|
60
|
-
|
|
|
61
|
-
|
|
|
60
|
+
export type XrpcResult<M extends Procedure | Query> =
|
|
61
|
+
| XrpcResponse<M>
|
|
62
|
+
| XrpcFailure<M>
|
|
62
63
|
|
|
63
64
|
/**
|
|
64
65
|
* Utility method to type cast the error thrown by {@link xrpc} to an
|
|
65
|
-
* {@link
|
|
66
|
+
* {@link XrpcFailure} matching the provided method. Only use this function
|
|
66
67
|
* inside a catch block right after calling {@link xrpc}, and use the same
|
|
67
68
|
* method type parameter as used in the {@link xrpc} call.
|
|
68
69
|
*/
|
|
69
|
-
export function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (err instanceof
|
|
73
|
-
if (err instanceof
|
|
74
|
-
return
|
|
70
|
+
export function asXrpcFailure<M extends Procedure | Query = Procedure | Query>(
|
|
71
|
+
err: unknown,
|
|
72
|
+
): XrpcFailure<M> {
|
|
73
|
+
if (err instanceof XrpcResponseError) return err
|
|
74
|
+
if (err instanceof XrpcUpstreamError) return err
|
|
75
|
+
return XrpcUnexpectedError.from(err)
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
/**
|
|
78
|
-
* @throws
|
|
79
|
+
* @throws XrpcFailure<M>
|
|
79
80
|
*/
|
|
80
81
|
export async function xrpc<const M extends Query | Procedure>(
|
|
81
82
|
agent: Agent,
|
|
82
|
-
ns: NonNullable<unknown> extends
|
|
83
|
+
ns: NonNullable<unknown> extends XrpcOptions<M>
|
|
83
84
|
? Main<M>
|
|
84
85
|
: Restricted<'This XRPC method requires an "options" argument'>,
|
|
85
|
-
): Promise<
|
|
86
|
+
): Promise<XrpcResponse<M>>
|
|
86
87
|
export async function xrpc<const M extends Query | Procedure>(
|
|
87
88
|
agent: Agent,
|
|
88
89
|
ns: Main<M>,
|
|
89
|
-
options:
|
|
90
|
-
): Promise<
|
|
90
|
+
options: XrpcOptions<M>,
|
|
91
|
+
): Promise<XrpcResponse<M>>
|
|
91
92
|
export async function xrpc<const M extends Query | Procedure>(
|
|
92
93
|
agent: Agent,
|
|
93
94
|
ns: Main<M>,
|
|
94
|
-
options:
|
|
95
|
-
): Promise<
|
|
95
|
+
options: XrpcOptions<M> = {} as XrpcOptions<M>,
|
|
96
|
+
): Promise<XrpcResponse<M>> {
|
|
96
97
|
try {
|
|
97
98
|
return await lexRpcRequest<M>(agent, ns, options)
|
|
98
99
|
} catch (err) {
|
|
99
|
-
throw
|
|
100
|
+
throw asXrpcFailure<M>(err)
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
export async function xrpcSafe<const M extends Query | Procedure>(
|
|
104
105
|
agent: Agent,
|
|
105
|
-
ns: NonNullable<unknown> extends
|
|
106
|
+
ns: NonNullable<unknown> extends XrpcOptions<M>
|
|
106
107
|
? Main<M>
|
|
107
108
|
: Restricted<'This XRPC method requires an "options" argument'>,
|
|
108
|
-
): Promise<
|
|
109
|
+
): Promise<XrpcResult<M>>
|
|
109
110
|
export async function xrpcSafe<const M extends Query | Procedure>(
|
|
110
111
|
agent: Agent,
|
|
111
112
|
ns: Main<M>,
|
|
112
|
-
options:
|
|
113
|
-
): Promise<
|
|
113
|
+
options: XrpcOptions<M>,
|
|
114
|
+
): Promise<XrpcResult<M>>
|
|
114
115
|
export async function xrpcSafe<const M extends Query | Procedure>(
|
|
115
116
|
agent: Agent,
|
|
116
117
|
ns: Main<M>,
|
|
117
|
-
options:
|
|
118
|
-
): Promise<
|
|
119
|
-
return lexRpcRequest<M>(agent, ns, options).catch(
|
|
118
|
+
options: XrpcOptions<M> = {} as XrpcOptions<M>,
|
|
119
|
+
): Promise<XrpcResult<M>> {
|
|
120
|
+
return lexRpcRequest<M>(agent, ns, options).catch(asXrpcFailure<M>)
|
|
120
121
|
}
|
|
121
122
|
|
|
122
123
|
async function lexRpcRequest<const M extends Query | Procedure>(
|
|
123
124
|
agent: Agent,
|
|
124
125
|
ns: Main<M>,
|
|
125
|
-
options:
|
|
126
|
-
): Promise<
|
|
126
|
+
options: XrpcOptions<M> = {} as XrpcOptions<M>,
|
|
127
|
+
): Promise<XrpcResponse<M>> {
|
|
127
128
|
const method = getMain(ns)
|
|
128
129
|
options.signal?.throwIfAborted()
|
|
129
130
|
const url = xrpcRequestUrl(method, options)
|
|
130
131
|
const request = xrpcRequestInit(method, options)
|
|
131
132
|
const response = await agent.fetchHandler(url, request)
|
|
132
|
-
return
|
|
133
|
+
return XrpcResponse.fromFetchResponse<M>(method, response, options)
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
function xrpcRequestUrl<M extends Procedure | Query | Subscription>(
|
|
@@ -138,24 +139,13 @@ function xrpcRequestUrl<M extends Procedure | Query | Subscription>(
|
|
|
138
139
|
) {
|
|
139
140
|
const path = `/xrpc/${method.nsid}`
|
|
140
141
|
|
|
141
|
-
const queryString =
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
const queryString = method.parameters
|
|
143
|
+
?.toURLSearchParams(options.params ?? {})
|
|
144
|
+
.toString()
|
|
144
145
|
|
|
145
146
|
return queryString ? `${path}?${queryString}` : path
|
|
146
147
|
}
|
|
147
148
|
|
|
148
|
-
function xrpcRequestParams(
|
|
149
|
-
schema: ParamsSchema | undefined,
|
|
150
|
-
params: Params | undefined,
|
|
151
|
-
options: CallOptions,
|
|
152
|
-
): undefined | string {
|
|
153
|
-
const urlSearchParams = schema?.toURLSearchParams(
|
|
154
|
-
options.validateRequest ? schema.parse(params) : (params as any),
|
|
155
|
-
)
|
|
156
|
-
return urlSearchParams?.size ? urlSearchParams.toString() : undefined
|
|
157
|
-
}
|
|
158
|
-
|
|
159
149
|
function xrpcRequestInit<T extends Procedure | Query>(
|
|
160
150
|
schema: T,
|
|
161
151
|
options: CallOptions & {
|
|
@@ -215,7 +205,7 @@ function xrpcProcedureInput(
|
|
|
215
205
|
method: Procedure,
|
|
216
206
|
options: CallOptions & { body?: LexValue | BinaryBodyInit },
|
|
217
207
|
encodingHint?: string,
|
|
218
|
-
): null |
|
|
208
|
+
): null | XrpcPayload<BodyInit> {
|
|
219
209
|
const { input } = method
|
|
220
210
|
const { body } = options
|
|
221
211
|
|
|
@@ -261,10 +251,10 @@ function xrpcProcedureInput(
|
|
|
261
251
|
}
|
|
262
252
|
|
|
263
253
|
function buildPayload(
|
|
264
|
-
schema:
|
|
254
|
+
schema: Payload,
|
|
265
255
|
body: undefined | BodyInit,
|
|
266
256
|
encodingHint?: string,
|
|
267
|
-
): null |
|
|
257
|
+
): null | XrpcPayload<BodyInit> {
|
|
268
258
|
if (schema.encoding === undefined) {
|
|
269
259
|
if (body !== undefined) {
|
|
270
260
|
throw new TypeError(
|
|
@@ -286,7 +276,7 @@ function buildPayload(
|
|
|
286
276
|
return { encoding, body }
|
|
287
277
|
}
|
|
288
278
|
|
|
289
|
-
function buildEncoding(schema:
|
|
279
|
+
function buildEncoding(schema: Payload, encodingHint?: string): string {
|
|
290
280
|
// Should never happen (required for type safety)
|
|
291
281
|
if (!schema.encoding) {
|
|
292
282
|
throw new TypeError('Unexpected payload')
|