@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/src/xrpc.ts CHANGED
@@ -14,20 +14,17 @@ import {
14
14
  getMain,
15
15
  } from '@atproto/lex-schema'
16
16
  import { Agent, AgentOptions, buildAgent } from './agent.js'
17
- import { XrpcFailure, asXrpcFailure } from './errors.js'
18
- import { XrpcResponse } from './response.js'
19
- import { BinaryBodyInit, CallOptions } from './types.js'
17
+ import { XrpcFailure, XrpcFetchError, asXrpcFailure } from './errors.js'
18
+ import { XrpcResponse, XrpcResponseOptions } from './response.js'
19
+ import { BinaryBodyInit } from './types.js'
20
20
  import {
21
- buildAtprotoHeaders,
21
+ XrpcRequestHeadersOptions,
22
+ buildXrpcRequestHeaders,
22
23
  isAsyncIterable,
23
24
  isBlobLike,
24
25
  toReadableStream,
25
26
  } from './util.js'
26
27
 
27
- // If all params are optional, allow omitting the params object
28
- type XrpcParamsOptions<P extends Params> =
29
- NonNullable<unknown> extends P ? { params?: P } : { params: P }
30
-
31
28
  /**
32
29
  * The query/path parameters type for an XRPC method, inferred from its schema.
33
30
  *
@@ -36,25 +33,43 @@ type XrpcParamsOptions<P extends Params> =
36
33
  export type XrpcRequestParams<M extends Procedure | Query | Subscription> =
37
34
  InferInput<M['parameters']>
38
35
 
36
+ // If all params are optional, allow omitting the params object
37
+ type XrpcRequestParamsOptions<P extends Params> =
38
+ NonNullable<unknown> extends P ? { params?: P } : { params: P }
39
+
39
40
  type XrpcRequestPayload<M extends Procedure | Query> = M extends Procedure
40
41
  ? InferPayload<M['input'], BinaryBodyInit>
41
42
  : undefined
42
43
 
43
- type XrpcInputOptions<In> = In extends { body: infer B; encoding: infer E }
44
- ? // encoding will be inferred from the schema at runtime if not provided
45
- { body: B; encoding?: E }
44
+ type XrpcRequestPayloadOptions<TPayload> = TPayload extends {
45
+ body: infer B
46
+ encoding: infer E
47
+ }
48
+ ? {
49
+ body: B
50
+
51
+ /**
52
+ * mime type hint for binary bodies
53
+ *
54
+ * Only needed for endpoints that accept binary input (e.g. file uploads)
55
+ * when the body is a Blob-like object without a type (e.g. fetch-blob's
56
+ * Blob). If the body is a Blob-like object with a type, that type will be
57
+ * used as the content-type header instead of this option.
58
+ *
59
+ * @default "application/octet-stream"
60
+ */
61
+ encoding?: E
62
+ }
46
63
  : { body?: undefined; encoding?: undefined }
47
64
 
48
65
  /**
49
- * Options for making an XRPC request.
66
+ * Options for making an XRPC request, based on the method schema.
50
67
  *
51
- * Combines {@link CallOptions} with method-specific params and body requirements.
52
- * The type system ensures required params/body are provided based on the method schema.
68
+ * Combines {@link XrpcRequestOptions} and {@link XrpcResponseOptions} with
69
+ * method-specific params and body requirements. The type system ensures
70
+ * required params/body are provided based on the method schema.
53
71
  *
54
72
  * @typeParam M - The XRPC method type (Procedure or Query)
55
- * @see {@link CallOptions} for general request options like signal and validateRequest
56
- * @see {@link XrpcParamsOptions} for method-specific query parameters
57
- * @see {@link XrpcInputOptions} for method-specific body and encoding requirements
58
73
  *
59
74
  * @example Query with params
60
75
  * ```typescript
@@ -71,9 +86,31 @@ type XrpcInputOptions<In> = In extends { body: infer B; encoding: infer E }
71
86
  * ```
72
87
  */
73
88
  export type XrpcOptions<M extends Procedure | Query = Procedure | Query> =
74
- CallOptions &
75
- XrpcInputOptions<XrpcRequestPayload<M>> &
76
- XrpcParamsOptions<XrpcRequestParams<M>>
89
+ XrpcRequestOptions<M> & XrpcResponseOptions
90
+
91
+ export type XrpcRequestOptions<
92
+ M extends Procedure | Query = Procedure | Query,
93
+ > = XrpcRequestProcessingOptions &
94
+ XrpcRequestHeadersOptions &
95
+ XrpcRequestPayloadOptions<XrpcRequestPayload<M>> &
96
+ XrpcRequestParamsOptions<XrpcRequestParams<M>>
97
+
98
+ export type XrpcRequestProcessingOptions = {
99
+ /**
100
+ * AbortSignal to cancel the request.
101
+ */
102
+ signal?: AbortSignal
103
+
104
+ /**
105
+ * Whether to validate the request against the method's input schema. Enabling
106
+ * this can help catch errors early but may have a performance cost. This
107
+ * would typically only be set to `true` in development or debugging
108
+ * scenarios.
109
+ *
110
+ * @default false
111
+ */
112
+ validateRequest?: boolean
113
+ }
77
114
 
78
115
  /**
79
116
  * Makes an XRPC request and throws on failure.
@@ -181,7 +218,9 @@ export async function xrpcSafe<const M extends Query | Procedure>(
181
218
  const agent = buildAgent(agentOpts)
182
219
  const url = xrpcRequestUrl(method, options)
183
220
  const request = xrpcRequestInit(method, options)
184
- const response = await agent.fetchHandler(url, request)
221
+ const response = await agent.fetchHandler(url, request).catch((cause) => {
222
+ throw new XrpcFetchError(method, cause)
223
+ })
185
224
  return await XrpcResponse.fromFetchResponse<M>(method, response, options)
186
225
  } catch (cause) {
187
226
  return asXrpcFailure(method, cause)
@@ -190,10 +229,13 @@ export async function xrpcSafe<const M extends Query | Procedure>(
190
229
 
191
230
  function xrpcRequestUrl<M extends Procedure | Query | Subscription>(
192
231
  method: M,
193
- options: CallOptions & { params?: Params },
232
+ options: { params?: Params },
194
233
  ): `/xrpc/${NsidString}${'' | `?${string}`}` {
195
234
  const path = `/xrpc/${method.nsid}` as const
196
235
 
236
+ // @NOTE param.toURLSearchParams() will always validate the params in order to
237
+ // apply default values, so we can't disable it with options.validateRequest
238
+
197
239
  const queryString = method.parameters
198
240
  ?.toURLSearchParams(options.params ?? {})
199
241
  .toString()
@@ -203,12 +245,13 @@ function xrpcRequestUrl<M extends Procedure | Query | Subscription>(
203
245
 
204
246
  function xrpcRequestInit<T extends Procedure | Query>(
205
247
  schema: T,
206
- options: CallOptions & {
207
- body?: LexValue | BinaryBodyInit
208
- encoding?: string
209
- },
248
+ options: XrpcRequestProcessingOptions &
249
+ XrpcRequestHeadersOptions &
250
+ XrpcProcedureInputOptions & {
251
+ encoding?: string
252
+ },
210
253
  ): RequestInit & { duplex?: 'half' } {
211
- const headers = buildAtprotoHeaders(options)
254
+ const headers = buildXrpcRequestHeaders(options)
212
255
 
213
256
  // Tell the server what type of response we're expecting
214
257
  if (schema.output.encoding) {
@@ -256,9 +299,14 @@ function xrpcRequestInit<T extends Procedure | Query>(
256
299
  }
257
300
  }
258
301
 
302
+ type XrpcProcedureInputOptions = {
303
+ body?: LexValue | BinaryBodyInit
304
+ validateRequest?: boolean
305
+ }
306
+
259
307
  function xrpcProcedureInput(
260
308
  method: Procedure,
261
- options: CallOptions & { body?: LexValue | BinaryBodyInit },
309
+ options: XrpcProcedureInputOptions,
262
310
  encodingHint?: string,
263
311
  ): null | { body: BodyInit; encoding: string } {
264
312
  const { input } = method