@atproto/lex-client 0.0.9 → 0.0.11

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.
Files changed (53) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/LICENSE.txt +1 -1
  3. package/dist/agent.d.ts +5 -0
  4. package/dist/agent.d.ts.map +1 -1
  5. package/dist/agent.js +15 -1
  6. package/dist/agent.js.map +1 -1
  7. package/dist/client.d.ts +59 -40
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js +2 -6
  10. package/dist/client.js.map +1 -1
  11. package/dist/errors.d.ts +52 -51
  12. package/dist/errors.d.ts.map +1 -1
  13. package/dist/errors.js +90 -71
  14. package/dist/errors.js.map +1 -1
  15. package/dist/lexicons/com/atproto/repo/createRecord.defs.d.ts +20 -10
  16. package/dist/lexicons/com/atproto/repo/createRecord.defs.d.ts.map +1 -1
  17. package/dist/lexicons/com/atproto/repo/defs.defs.d.ts +1 -1
  18. package/dist/lexicons/com/atproto/repo/defs.defs.d.ts.map +1 -1
  19. package/dist/lexicons/com/atproto/repo/deleteRecord.defs.d.ts +14 -6
  20. package/dist/lexicons/com/atproto/repo/deleteRecord.defs.d.ts.map +1 -1
  21. package/dist/lexicons/com/atproto/repo/getRecord.defs.d.ts +12 -4
  22. package/dist/lexicons/com/atproto/repo/getRecord.defs.d.ts.map +1 -1
  23. package/dist/lexicons/com/atproto/repo/listRecords.defs.d.ts +11 -11
  24. package/dist/lexicons/com/atproto/repo/listRecords.defs.d.ts.map +1 -1
  25. package/dist/lexicons/com/atproto/repo/listRecords.defs.js +2 -1
  26. package/dist/lexicons/com/atproto/repo/listRecords.defs.js.map +1 -1
  27. package/dist/lexicons/com/atproto/repo/putRecord.defs.d.ts +18 -10
  28. package/dist/lexicons/com/atproto/repo/putRecord.defs.d.ts.map +1 -1
  29. package/dist/response.d.ts +14 -13
  30. package/dist/response.d.ts.map +1 -1
  31. package/dist/response.js +36 -35
  32. package/dist/response.js.map +1 -1
  33. package/dist/util.d.ts +1 -1
  34. package/dist/util.d.ts.map +1 -1
  35. package/dist/util.js.map +1 -1
  36. package/dist/www-authenticate.d.ts +12 -0
  37. package/dist/www-authenticate.d.ts.map +1 -0
  38. package/dist/www-authenticate.js +57 -0
  39. package/dist/www-authenticate.js.map +1 -0
  40. package/dist/xrpc.d.ts +14 -21
  41. package/dist/xrpc.d.ts.map +1 -1
  42. package/dist/xrpc.js +18 -35
  43. package/dist/xrpc.js.map +1 -1
  44. package/package.json +6 -6
  45. package/src/agent.ts +34 -1
  46. package/src/client.ts +34 -33
  47. package/src/errors.ts +161 -128
  48. package/src/lexicons/com/atproto/repo/listRecords.defs.ts +4 -1
  49. package/src/response.ts +71 -71
  50. package/src/util.ts +1 -1
  51. package/src/www-authenticate.test.ts +227 -0
  52. package/src/www-authenticate.ts +77 -0
  53. package/src/xrpc.ts +53 -95
@@ -0,0 +1,227 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { parseWWWAuthenticateHeader } from './www-authenticate.js'
3
+
4
+ describe(parseWWWAuthenticateHeader, () => {
5
+ describe('auth-params', () => {
6
+ it('parses single unquoted auth param', () => {
7
+ expect(parseWWWAuthenticateHeader('Bearer realm=example.com')).toEqual({
8
+ Bearer: { realm: 'example.com' },
9
+ })
10
+ })
11
+
12
+ it('parses single quoted auth param', () => {
13
+ expect(parseWWWAuthenticateHeader('Bearer realm="example.com"')).toEqual({
14
+ Bearer: { realm: 'example.com' },
15
+ })
16
+ })
17
+
18
+ it('parses quoted values with spaces', () => {
19
+ expect(parseWWWAuthenticateHeader('Bearer realm="my realm"')).toEqual({
20
+ Bearer: { realm: 'my realm' },
21
+ })
22
+ })
23
+
24
+ it('parses quoted values with escaped double quotes', () => {
25
+ expect(
26
+ parseWWWAuthenticateHeader('Bearer realm="example\\"quoted\\""'),
27
+ ).toEqual({
28
+ Bearer: { realm: 'example"quoted"' },
29
+ })
30
+ })
31
+
32
+ it('parses quoted values with escaped backslash', () => {
33
+ expect(
34
+ parseWWWAuthenticateHeader('Bearer realm="path\\\\to\\\\file"'),
35
+ ).toEqual({
36
+ Bearer: { realm: 'path\\to\\file' },
37
+ })
38
+ })
39
+
40
+ it('parses param names with hyphens', () => {
41
+ expect(
42
+ parseWWWAuthenticateHeader('Bearer error-uri="https://example.com"'),
43
+ ).toEqual({
44
+ Bearer: { 'error-uri': 'https://example.com' },
45
+ })
46
+ })
47
+
48
+ it('parses param names with underscores', () => {
49
+ expect(
50
+ parseWWWAuthenticateHeader('Bearer error_description="test"'),
51
+ ).toEqual({
52
+ Bearer: { error_description: 'test' },
53
+ })
54
+ })
55
+
56
+ it('parses param with numeric value', () => {
57
+ expect(parseWWWAuthenticateHeader('Bearer max-age=3600')).toEqual({
58
+ Bearer: { 'max-age': '3600' },
59
+ })
60
+ })
61
+
62
+ it('parses empty quoted value', () => {
63
+ expect(parseWWWAuthenticateHeader('Bearer realm=""')).toEqual({
64
+ Bearer: { realm: '' },
65
+ })
66
+ })
67
+
68
+ it('parses Basic auth challenge', () => {
69
+ expect(
70
+ parseWWWAuthenticateHeader('Basic realm="Access to staging site"'),
71
+ ).toEqual({
72
+ Basic: { realm: 'Access to staging site' },
73
+ })
74
+ })
75
+
76
+ it('parses Bearer with realm', () => {
77
+ expect(
78
+ parseWWWAuthenticateHeader('Bearer realm="https://auth.example.com"'),
79
+ ).toEqual({
80
+ Bearer: { realm: 'https://auth.example.com' },
81
+ })
82
+ })
83
+
84
+ it('parses DPoP with algs param', () => {
85
+ expect(parseWWWAuthenticateHeader('DPoP algs="ES256 RS256"')).toEqual({
86
+ DPoP: { algs: 'ES256 RS256' },
87
+ })
88
+ })
89
+
90
+ it('parses Digest auth challenge', () => {
91
+ const result = parseWWWAuthenticateHeader(
92
+ 'Digest realm="digest-realm", nonce="abc123"',
93
+ )
94
+ expect(result).toEqual({
95
+ Digest: { realm: 'digest-realm', nonce: 'abc123' },
96
+ })
97
+ })
98
+
99
+ it('handle empty unquoted params', () => {
100
+ const result = parseWWWAuthenticateHeader('Bearer realm=')
101
+ expect(result).toEqual({ Bearer: { realm: '' } })
102
+ })
103
+
104
+ it('handle empty params', () => {
105
+ const result = parseWWWAuthenticateHeader('Bearer realm=""')
106
+ expect(result).toEqual({ Bearer: { realm: '' } })
107
+ })
108
+
109
+ it('treats scheme-only header as scheme with itself as token68', () => {
110
+ const result = parseWWWAuthenticateHeader('Basic')
111
+ expect(result).toEqual({ Basic: {} })
112
+ })
113
+
114
+ it('parses multiple challenges with commas and escaped quotes', () => {
115
+ const result = parseWWWAuthenticateHeader(
116
+ `Newauth realm="apps", type=1,\n\t title="Login to \\"apps\\"", Basic realm="simple"`,
117
+ )
118
+ expect(result).toEqual({
119
+ Newauth: {
120
+ realm: 'apps',
121
+ type: '1',
122
+ title: 'Login to "apps"',
123
+ },
124
+ Basic: { realm: 'simple' },
125
+ })
126
+ })
127
+
128
+ it('parses first challenge before comma', () => {
129
+ const result = parseWWWAuthenticateHeader(
130
+ 'Basic realm="foo", Bearer realm="bar"',
131
+ )
132
+ expect(result).toEqual({
133
+ Basic: { realm: 'foo' },
134
+ Bearer: { realm: 'bar' },
135
+ })
136
+ })
137
+ })
138
+
139
+ describe('edge cases', () => {
140
+ it('handles empty string', () => {
141
+ expect(parseWWWAuthenticateHeader('')).toEqual({})
142
+ })
143
+
144
+ it('handles whitespace-only string', () => {
145
+ expect(parseWWWAuthenticateHeader(' ')).toEqual({})
146
+ })
147
+
148
+ it('trims whitespace from header', () => {
149
+ expect(parseWWWAuthenticateHeader(' Bearer realm="test" ')).toEqual({
150
+ Bearer: { realm: 'test' },
151
+ })
152
+ })
153
+
154
+ it('handles commas as quoted param value', () => {
155
+ expect(
156
+ parseWWWAuthenticateHeader('Bearer realm="example, with, commas"'),
157
+ ).toEqual({ Bearer: { realm: 'example, with, commas' } })
158
+ })
159
+
160
+ it('handles multiple challenges with varying whitespace', () => {
161
+ expect(
162
+ parseWWWAuthenticateHeader(
163
+ ' Bearer realm="test" , Basic rr= ',
164
+ ),
165
+ ).toEqual({
166
+ Bearer: { realm: 'test' },
167
+ Basic: { rr: '' },
168
+ })
169
+ })
170
+ })
171
+
172
+ describe('invalid challenges', () => {
173
+ it('parses single challenge with no comma correctly', () => {
174
+ expect(
175
+ parseWWWAuthenticateHeader('Bearer realm="oauth" error="invalid"'),
176
+ ).toEqual(undefined)
177
+ })
178
+
179
+ it('ignores invalid challenges', () => {
180
+ expect(parseWWWAuthenticateHeader('Bearer realm="unclosed')).toEqual(
181
+ undefined,
182
+ )
183
+ })
184
+
185
+ it('handles random text without equals sign as token68', () => {
186
+ expect(parseWWWAuthenticateHeader('Bearer sometoken')).toEqual({
187
+ Bearer: 'sometoken',
188
+ })
189
+ })
190
+
191
+ it('ignores trailing whitespace after scheme', () => {
192
+ expect(parseWWWAuthenticateHeader('Bearer ')).toEqual({ Bearer: {} })
193
+ })
194
+
195
+ it('handles duplicate params (last wins)', () => {
196
+ expect(
197
+ parseWWWAuthenticateHeader('Bearer realm="first", realm="second"'),
198
+ ).toEqual({ Bearer: { realm: 'second' } })
199
+ })
200
+
201
+ it('extracts valid param after invalid characters', () => {
202
+ expect(parseWWWAuthenticateHeader('Bearer realm@foo="bar"')).toEqual({
203
+ Bearer: { 'realm@foo': 'bar' },
204
+ })
205
+ })
206
+
207
+ it('ignores param with empty name', () => {
208
+ expect(parseWWWAuthenticateHeader('Bearer ="value"')).toEqual(undefined)
209
+ })
210
+
211
+ it('handles completely malformed input gracefully', () => {
212
+ expect(parseWWWAuthenticateHeader('!@#$%')).toEqual({ '!@#$%': {} })
213
+ })
214
+
215
+ it('handles duplicate schemes as invalid', () => {
216
+ expect(
217
+ parseWWWAuthenticateHeader('Basic realm="first", Basic realm="second"'),
218
+ ).toEqual(undefined)
219
+ })
220
+
221
+ it('handles params without scheme as invalid', () => {
222
+ expect(parseWWWAuthenticateHeader('Bearer, realm="foo"')).toEqual(
223
+ undefined,
224
+ )
225
+ })
226
+ })
227
+ })
@@ -0,0 +1,77 @@
1
+ type WWWAuthenticateParams = { [authParam in string]: string }
2
+ export type WWWAuthenticate = {
3
+ [authScheme in string]:
4
+ | string // token68
5
+ | WWWAuthenticateParams
6
+ }
7
+
8
+ /**
9
+ * Returns `undefined` if the header is malformed.
10
+ */
11
+ export function parseWWWAuthenticateHeader(
12
+ header?: unknown,
13
+ ): undefined | WWWAuthenticate {
14
+ if (typeof header !== 'string') return undefined
15
+
16
+ const wwwAuthenticate: WWWAuthenticate = {}
17
+
18
+ // Split over commas, not within quoted strings
19
+ const trimmedHeader = header.trim()
20
+ if (!trimmedHeader) return wwwAuthenticate
21
+
22
+ const parts = trimmedHeader.split(/,(?=(?:[^"]*"[^"]*")*[^"]*$)/)
23
+
24
+ let currentParams: WWWAuthenticateParams | null = null
25
+
26
+ for (let part of parts) {
27
+ // Check if the part starts with an auth scheme
28
+ const schemeMatch = part.trim().match(/^([^"=\s]+)(\s+.*)?$/)
29
+ if (schemeMatch) {
30
+ const scheme = schemeMatch[1]
31
+
32
+ // Duplicate scheme
33
+ if (Object.hasOwn(wwwAuthenticate, scheme)) return undefined
34
+
35
+ const rest = schemeMatch[2]?.trim()
36
+ if (!rest) {
37
+ // Scheme only (no params or token68)
38
+ currentParams = null
39
+ wwwAuthenticate[scheme] = Object.create(null)
40
+ continue
41
+ }
42
+
43
+ if (!rest.includes('=')) {
44
+ // Scheme with token68
45
+ currentParams = null
46
+ wwwAuthenticate[scheme] = rest
47
+ continue
48
+ }
49
+
50
+ // Scheme with params
51
+
52
+ currentParams = Object.create(null) as WWWAuthenticateParams
53
+ wwwAuthenticate[scheme] = currentParams
54
+
55
+ // Fall through to parse params
56
+ part = rest
57
+ }
58
+
59
+ // Invalid header
60
+ if (!currentParams) return undefined
61
+
62
+ const param = part.match(
63
+ /^\s*([^"\s=]+)=(?:("[^"\\]*(?:\\.[^"\\]*)*")|([^\s,"]*))\s*$/,
64
+ )
65
+
66
+ // invalid param
67
+ if (!param) return undefined
68
+
69
+ const paramName = param[1]
70
+ const paramValue =
71
+ param[3] ?? param[2]!.slice(1, -1).replaceAll(/\\(.)/g, '$1')
72
+
73
+ currentParams[paramName] = paramValue
74
+ }
75
+
76
+ return wwwAuthenticate
77
+ }
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
- InferMethodInput,
5
- InferMethodParams,
4
+ InferInput,
5
+ InferPayload,
6
6
  Main,
7
7
  Params,
8
- ParamsSchema,
9
- Payload as LexPayload,
8
+ Payload,
10
9
  Procedure,
11
10
  Query,
12
11
  Restricted,
@@ -14,15 +13,11 @@ import {
14
13
  getMain,
15
14
  } from '@atproto/lex-schema'
16
15
  import { Agent } from './agent.js'
17
- import {
18
- LexRpcResponseError,
19
- LexRpcUnexpectedError,
20
- LexRpcUpstreamError,
21
- } from './errors.js'
22
- import { LexRpcResponse } from './response.js'
16
+ import { XrpcFailure, asXrpcFailure } from './errors.js'
17
+ import { XrpcResponse } from './response.js'
23
18
  import { BinaryBodyInit, CallOptions } from './types.js'
24
19
  import {
25
- Payload,
20
+ XrpcPayload,
26
21
  buildAtprotoHeaders,
27
22
  isAsyncIterable,
28
23
  isBlobLike,
@@ -30,106 +25,80 @@ import {
30
25
  } from './util.js'
31
26
 
32
27
  // If all params are optional, allow omitting the params object
33
- type LexRpcParamsOptions<P extends Params> =
28
+ type XrpcParamsOptions<P extends Params> =
34
29
  NonNullable<unknown> extends P ? { params?: P } : { params: P }
35
30
 
36
- type LexRpcRequestPayload<M extends Procedure | Query> = InferMethodInput<
37
- M,
38
- BinaryBodyInit
39
- >
31
+ export type XrpcRequestParams<M extends Procedure | Query | Subscription> =
32
+ InferInput<M['parameters']>
40
33
 
41
- type LexRpcInputOptions<In> = In extends { body: infer B; encoding: infer E }
34
+ type XrpcRequestPayload<M extends Procedure | Query> = M extends Procedure
35
+ ? InferPayload<M['input'], BinaryBodyInit>
36
+ : undefined
37
+
38
+ type XrpcInputOptions<In> = In extends { body: infer B; encoding: infer E }
42
39
  ? // encoding will be inferred from the schema at runtime if not provided
43
40
  { body: B; encoding?: E }
44
41
  : { body?: undefined; encoding?: undefined }
45
42
 
46
- export type LexRpcOptions<M extends Procedure | Query = Procedure | Query> =
43
+ export type XrpcOptions<M extends Procedure | Query = Procedure | Query> =
47
44
  CallOptions &
48
- LexRpcInputOptions<LexRpcRequestPayload<M>> &
49
- LexRpcParamsOptions<InferMethodParams<M>>
50
-
51
- export type LexRpcFailure<M extends Procedure | Query> =
52
- // The server returned a valid XRPC error response
53
- | LexRpcResponseError<M>
54
- // The response was not a valid XRPC response, or it does not match the schema
55
- | LexRpcUpstreamError
56
- // Something went wrong (network error, etc.)
57
- | LexRpcUnexpectedError
58
-
59
- export type LexRpcResult<M extends Procedure | Query> =
60
- | LexRpcResponse<M>
61
- | LexRpcFailure<M>
45
+ XrpcInputOptions<XrpcRequestPayload<M>> &
46
+ XrpcParamsOptions<XrpcRequestParams<M>>
62
47
 
63
48
  /**
64
- * Utility method to type cast the error thrown by {@link xrpc} to an
65
- * {@link LexRpcFailure} matching the provided method. Only use this function
66
- * inside a catch block right after calling {@link xrpc}, and use the same
67
- * method type parameter as used in the {@link xrpc} call.
68
- */
69
- export function asLexRpcFailure<
70
- M extends Procedure | Query = Procedure | Query,
71
- >(err: unknown): LexRpcFailure<M> {
72
- if (err instanceof LexRpcResponseError) return err
73
- if (err instanceof LexRpcUpstreamError) return err
74
- return LexRpcUnexpectedError.from(err)
75
- }
76
-
77
- /**
78
- * @throws LexRpcFailure<M>
49
+ * @throws XrpcFailure<M>
79
50
  */
80
51
  export async function xrpc<const M extends Query | Procedure>(
81
52
  agent: Agent,
82
- ns: NonNullable<unknown> extends LexRpcOptions<M>
53
+ ns: NonNullable<unknown> extends XrpcOptions<M>
83
54
  ? Main<M>
84
55
  : Restricted<'This XRPC method requires an "options" argument'>,
85
- ): Promise<LexRpcResponse<M>>
56
+ ): Promise<XrpcResponse<M>>
86
57
  export async function xrpc<const M extends Query | Procedure>(
87
58
  agent: Agent,
88
59
  ns: Main<M>,
89
- options: LexRpcOptions<M>,
90
- ): Promise<LexRpcResponse<M>>
60
+ options: XrpcOptions<M>,
61
+ ): Promise<XrpcResponse<M>>
91
62
  export async function xrpc<const M extends Query | Procedure>(
92
63
  agent: Agent,
93
64
  ns: Main<M>,
94
- options: LexRpcOptions<M> = {} as LexRpcOptions<M>,
95
- ): Promise<LexRpcResponse<M>> {
96
- try {
97
- return await lexRpcRequest<M>(agent, ns, options)
98
- } catch (err) {
99
- throw asLexRpcFailure<M>(err)
100
- }
65
+ options: XrpcOptions<M> = {} as XrpcOptions<M>,
66
+ ): Promise<XrpcResponse<M>> {
67
+ const response = await xrpcSafe<M>(agent, ns, options)
68
+ if (response.success) return response
69
+ else throw response
101
70
  }
102
71
 
72
+ export type XrpcResult<M extends Procedure | Query> =
73
+ | XrpcResponse<M>
74
+ | XrpcFailure<M>
75
+
103
76
  export async function xrpcSafe<const M extends Query | Procedure>(
104
77
  agent: Agent,
105
- ns: NonNullable<unknown> extends LexRpcOptions<M>
78
+ ns: NonNullable<unknown> extends XrpcOptions<M>
106
79
  ? Main<M>
107
80
  : Restricted<'This XRPC method requires an "options" argument'>,
108
- ): Promise<LexRpcResult<M>>
81
+ ): Promise<XrpcResult<M>>
109
82
  export async function xrpcSafe<const M extends Query | Procedure>(
110
83
  agent: Agent,
111
84
  ns: Main<M>,
112
- options: LexRpcOptions<M>,
113
- ): Promise<LexRpcResult<M>>
85
+ options: XrpcOptions<M>,
86
+ ): Promise<XrpcResult<M>>
114
87
  export async function xrpcSafe<const M extends Query | Procedure>(
115
88
  agent: Agent,
116
89
  ns: Main<M>,
117
- options: LexRpcOptions<M> = {} as LexRpcOptions<M>,
118
- ): Promise<LexRpcResult<M>> {
119
- return lexRpcRequest<M>(agent, ns, options).catch(asLexRpcFailure<M>)
120
- }
121
-
122
- async function lexRpcRequest<const M extends Query | Procedure>(
123
- agent: Agent,
124
- ns: Main<M>,
125
- options: LexRpcOptions<M> = {} as LexRpcOptions<M>,
126
- ): Promise<LexRpcResponse<M>> {
127
- const method = getMain(ns)
90
+ options: XrpcOptions<M> = {} as XrpcOptions<M>,
91
+ ): Promise<XrpcResult<M>> {
128
92
  options.signal?.throwIfAborted()
129
- const url = xrpcRequestUrl(method, options)
130
- const request = xrpcRequestInit(method, options)
131
- const response = await agent.fetchHandler(url, request)
132
- return LexRpcResponse.fromFetchResponse<M>(method, response, options)
93
+ const method: M = getMain(ns)
94
+ try {
95
+ const url = xrpcRequestUrl(method, options)
96
+ const request = xrpcRequestInit(method, options)
97
+ const response = await agent.fetchHandler(url, request)
98
+ return await XrpcResponse.fromFetchResponse<M>(method, response, options)
99
+ } catch (cause) {
100
+ return asXrpcFailure(method, cause)
101
+ }
133
102
  }
134
103
 
135
104
  function xrpcRequestUrl<M extends Procedure | Query | Subscription>(
@@ -138,24 +107,13 @@ function xrpcRequestUrl<M extends Procedure | Query | Subscription>(
138
107
  ) {
139
108
  const path = `/xrpc/${method.nsid}`
140
109
 
141
- const queryString = options.params
142
- ? xrpcRequestParams(method.parameters, options.params, options)
143
- : undefined
110
+ const queryString = method.parameters
111
+ ?.toURLSearchParams(options.params ?? {})
112
+ .toString()
144
113
 
145
114
  return queryString ? `${path}?${queryString}` : path
146
115
  }
147
116
 
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
117
  function xrpcRequestInit<T extends Procedure | Query>(
160
118
  schema: T,
161
119
  options: CallOptions & {
@@ -215,7 +173,7 @@ function xrpcProcedureInput(
215
173
  method: Procedure,
216
174
  options: CallOptions & { body?: LexValue | BinaryBodyInit },
217
175
  encodingHint?: string,
218
- ): null | Payload<BodyInit> {
176
+ ): null | XrpcPayload<BodyInit> {
219
177
  const { input } = method
220
178
  const { body } = options
221
179
 
@@ -261,10 +219,10 @@ function xrpcProcedureInput(
261
219
  }
262
220
 
263
221
  function buildPayload(
264
- schema: LexPayload,
222
+ schema: Payload,
265
223
  body: undefined | BodyInit,
266
224
  encodingHint?: string,
267
- ): null | Payload<BodyInit> {
225
+ ): null | XrpcPayload<BodyInit> {
268
226
  if (schema.encoding === undefined) {
269
227
  if (body !== undefined) {
270
228
  throw new TypeError(
@@ -286,7 +244,7 @@ function buildPayload(
286
244
  return { encoding, body }
287
245
  }
288
246
 
289
- function buildEncoding(schema: LexPayload, encodingHint?: string): string {
247
+ function buildEncoding(schema: Payload, encodingHint?: string): string {
290
248
  // Should never happen (required for type safety)
291
249
  if (!schema.encoding) {
292
250
  throw new TypeError('Unexpected payload')