@atproto/lex-client 0.3.6 → 0.4.0

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 (135) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +4 -3
  3. package/dist/client.d.ts +4 -11
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js +6 -12
  6. package/dist/client.js.map +1 -1
  7. package/dist/index.d.ts +2 -5
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +2 -5
  10. package/dist/index.js.map +1 -1
  11. package/dist/lexicons/com/atproto/repo/applyWrites.d.ts +2 -2
  12. package/dist/lexicons/com/atproto/repo/applyWrites.d.ts.map +1 -1
  13. package/dist/lexicons/com/atproto/repo/applyWrites.defs.d.ts +23 -23
  14. package/dist/lexicons/com/atproto/repo/applyWrites.defs.d.ts.map +1 -1
  15. package/dist/lexicons/com/atproto/repo/applyWrites.defs.js +13 -64
  16. package/dist/lexicons/com/atproto/repo/applyWrites.defs.js.map +1 -1
  17. package/dist/lexicons/com/atproto/repo/applyWrites.js +2 -2
  18. package/dist/lexicons/com/atproto/repo/applyWrites.js.map +1 -1
  19. package/dist/lexicons/com/atproto/repo/createRecord.d.ts +2 -2
  20. package/dist/lexicons/com/atproto/repo/createRecord.d.ts.map +1 -1
  21. package/dist/lexicons/com/atproto/repo/createRecord.defs.d.ts +2 -2
  22. package/dist/lexicons/com/atproto/repo/createRecord.defs.d.ts.map +1 -1
  23. package/dist/lexicons/com/atproto/repo/createRecord.defs.js +6 -24
  24. package/dist/lexicons/com/atproto/repo/createRecord.defs.js.map +1 -1
  25. package/dist/lexicons/com/atproto/repo/createRecord.js +2 -2
  26. package/dist/lexicons/com/atproto/repo/createRecord.js.map +1 -1
  27. package/dist/lexicons/com/atproto/repo/defs.d.ts +1 -1
  28. package/dist/lexicons/com/atproto/repo/defs.d.ts.map +1 -1
  29. package/dist/lexicons/com/atproto/repo/defs.defs.d.ts +4 -4
  30. package/dist/lexicons/com/atproto/repo/defs.defs.d.ts.map +1 -1
  31. package/dist/lexicons/com/atproto/repo/defs.defs.js +3 -7
  32. package/dist/lexicons/com/atproto/repo/defs.defs.js.map +1 -1
  33. package/dist/lexicons/com/atproto/repo/defs.js +1 -1
  34. package/dist/lexicons/com/atproto/repo/defs.js.map +1 -1
  35. package/dist/lexicons/com/atproto/repo/deleteRecord.d.ts +2 -2
  36. package/dist/lexicons/com/atproto/repo/deleteRecord.d.ts.map +1 -1
  37. package/dist/lexicons/com/atproto/repo/deleteRecord.defs.d.ts +2 -2
  38. package/dist/lexicons/com/atproto/repo/deleteRecord.defs.d.ts.map +1 -1
  39. package/dist/lexicons/com/atproto/repo/deleteRecord.defs.js +6 -19
  40. package/dist/lexicons/com/atproto/repo/deleteRecord.defs.js.map +1 -1
  41. package/dist/lexicons/com/atproto/repo/deleteRecord.js +2 -2
  42. package/dist/lexicons/com/atproto/repo/deleteRecord.js.map +1 -1
  43. package/dist/lexicons/com/atproto/repo/getRecord.d.ts +2 -2
  44. package/dist/lexicons/com/atproto/repo/getRecord.d.ts.map +1 -1
  45. package/dist/lexicons/com/atproto/repo/getRecord.defs.d.ts +1 -1
  46. package/dist/lexicons/com/atproto/repo/getRecord.defs.d.ts.map +1 -1
  47. package/dist/lexicons/com/atproto/repo/getRecord.defs.js +5 -14
  48. package/dist/lexicons/com/atproto/repo/getRecord.defs.js.map +1 -1
  49. package/dist/lexicons/com/atproto/repo/getRecord.js +2 -2
  50. package/dist/lexicons/com/atproto/repo/getRecord.js.map +1 -1
  51. package/dist/lexicons/com/atproto/repo/listRecords.d.ts +2 -2
  52. package/dist/lexicons/com/atproto/repo/listRecords.d.ts.map +1 -1
  53. package/dist/lexicons/com/atproto/repo/listRecords.defs.d.ts +5 -5
  54. package/dist/lexicons/com/atproto/repo/listRecords.defs.d.ts.map +1 -1
  55. package/dist/lexicons/com/atproto/repo/listRecords.defs.js +5 -22
  56. package/dist/lexicons/com/atproto/repo/listRecords.defs.js.map +1 -1
  57. package/dist/lexicons/com/atproto/repo/listRecords.js +2 -2
  58. package/dist/lexicons/com/atproto/repo/listRecords.js.map +1 -1
  59. package/dist/lexicons/com/atproto/repo/putRecord.d.ts +2 -2
  60. package/dist/lexicons/com/atproto/repo/putRecord.d.ts.map +1 -1
  61. package/dist/lexicons/com/atproto/repo/putRecord.defs.d.ts +2 -2
  62. package/dist/lexicons/com/atproto/repo/putRecord.defs.d.ts.map +1 -1
  63. package/dist/lexicons/com/atproto/repo/putRecord.defs.js +6 -25
  64. package/dist/lexicons/com/atproto/repo/putRecord.defs.js.map +1 -1
  65. package/dist/lexicons/com/atproto/repo/putRecord.js +2 -2
  66. package/dist/lexicons/com/atproto/repo/putRecord.js.map +1 -1
  67. package/dist/lexicons/com/atproto/repo/uploadBlob.d.ts +2 -2
  68. package/dist/lexicons/com/atproto/repo/uploadBlob.d.ts.map +1 -1
  69. package/dist/lexicons/com/atproto/repo/uploadBlob.defs.d.ts +1 -1
  70. package/dist/lexicons/com/atproto/repo/uploadBlob.defs.d.ts.map +1 -1
  71. package/dist/lexicons/com/atproto/repo/uploadBlob.defs.js +4 -6
  72. package/dist/lexicons/com/atproto/repo/uploadBlob.defs.js.map +1 -1
  73. package/dist/lexicons/com/atproto/repo/uploadBlob.js +2 -2
  74. package/dist/lexicons/com/atproto/repo/uploadBlob.js.map +1 -1
  75. package/dist/lexicons/com/atproto/repo.d.ts +8 -8
  76. package/dist/lexicons/com/atproto/repo.d.ts.map +1 -1
  77. package/dist/lexicons/com/atproto/repo.js +8 -8
  78. package/dist/lexicons/com/atproto/repo.js.map +1 -1
  79. package/dist/lexicons/com/atproto/sync/getBlob.d.ts +2 -2
  80. package/dist/lexicons/com/atproto/sync/getBlob.d.ts.map +1 -1
  81. package/dist/lexicons/com/atproto/sync/getBlob.defs.d.ts +1 -1
  82. package/dist/lexicons/com/atproto/sync/getBlob.defs.d.ts.map +1 -1
  83. package/dist/lexicons/com/atproto/sync/getBlob.defs.js +5 -14
  84. package/dist/lexicons/com/atproto/sync/getBlob.defs.js.map +1 -1
  85. package/dist/lexicons/com/atproto/sync/getBlob.js +2 -2
  86. package/dist/lexicons/com/atproto/sync/getBlob.js.map +1 -1
  87. package/dist/lexicons/com/atproto/sync.d.ts +1 -1
  88. package/dist/lexicons/com/atproto/sync.d.ts.map +1 -1
  89. package/dist/lexicons/com/atproto/sync.js +1 -1
  90. package/dist/lexicons/com/atproto/sync.js.map +1 -1
  91. package/dist/lexicons/com/atproto.d.ts +2 -2
  92. package/dist/lexicons/com/atproto.d.ts.map +1 -1
  93. package/dist/lexicons/com/atproto.js +2 -2
  94. package/dist/lexicons/com/atproto.js.map +1 -1
  95. package/dist/lexicons/com.d.ts +1 -1
  96. package/dist/lexicons/com.d.ts.map +1 -1
  97. package/dist/lexicons/com.js +1 -1
  98. package/dist/lexicons/com.js.map +1 -1
  99. package/dist/lexicons/index.d.ts +1 -1
  100. package/dist/lexicons/index.d.ts.map +1 -1
  101. package/dist/lexicons/index.js +1 -1
  102. package/dist/lexicons/index.js.map +1 -1
  103. package/dist/write-operation-builder.d.ts +1 -1
  104. package/dist/write-operation-builder.d.ts.map +1 -1
  105. package/dist/write-operation-builder.js +4 -4
  106. package/dist/write-operation-builder.js.map +1 -1
  107. package/package.json +14 -7
  108. package/dist/agent.d.ts +0 -127
  109. package/dist/agent.d.ts.map +0 -1
  110. package/dist/agent.js +0 -41
  111. package/dist/agent.js.map +0 -1
  112. package/dist/errors.d.ts +0 -277
  113. package/dist/errors.d.ts.map +0 -1
  114. package/dist/errors.js +0 -388
  115. package/dist/errors.js.map +0 -1
  116. package/dist/response.d.ts +0 -124
  117. package/dist/response.d.ts.map +0 -1
  118. package/dist/response.js +0 -178
  119. package/dist/response.js.map +0 -1
  120. package/dist/types.d.ts +0 -54
  121. package/dist/types.d.ts.map +0 -1
  122. package/dist/types.js +0 -16
  123. package/dist/types.js.map +0 -1
  124. package/dist/util.d.ts +0 -90
  125. package/dist/util.d.ts.map +0 -1
  126. package/dist/util.js +0 -210
  127. package/dist/util.js.map +0 -1
  128. package/dist/www-authenticate.d.ts +0 -35
  129. package/dist/www-authenticate.d.ts.map +0 -1
  130. package/dist/www-authenticate.js +0 -54
  131. package/dist/www-authenticate.js.map +0 -1
  132. package/dist/xrpc.d.ts +0 -194
  133. package/dist/xrpc.d.ts.map +0 -1
  134. package/dist/xrpc.js +0 -235
  135. package/dist/xrpc.js.map +0 -1
@@ -1,35 +0,0 @@
1
- type WWWAuthenticateParams = {
2
- [authParam in string]: string;
3
- };
4
- /**
5
- * Parsed representation of a WWW-Authenticate HTTP header.
6
- *
7
- * Maps authentication scheme names to either:
8
- * - A token68 string (compact authentication data)
9
- * - A params object with key-value pairs
10
- *
11
- * @example Bearer with realm
12
- * ```typescript
13
- * // WWW-Authenticate: Bearer realm="example"
14
- * const parsed: WWWAuthenticate = {
15
- * Bearer: { realm: 'example' }
16
- * }
17
- * ```
18
- *
19
- * @example DPoP with error
20
- * ```typescript
21
- * // WWW-Authenticate: DPoP error="use_dpop_nonce", error_description="..."
22
- * const parsed: WWWAuthenticate = {
23
- * DPoP: { error: 'use_dpop_nonce', error_description: '...' }
24
- * }
25
- * ```
26
- */
27
- export type WWWAuthenticate = {
28
- [authScheme in string]: string | WWWAuthenticateParams;
29
- };
30
- /**
31
- * Returns `undefined` if the header is malformed.
32
- */
33
- export declare function parseWWWAuthenticateHeader(header?: unknown): undefined | WWWAuthenticate;
34
- export {};
35
- //# sourceMappingURL=www-authenticate.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"www-authenticate.d.ts","sourceRoot":"","sources":["../src/www-authenticate.ts"],"names":[],"mappings":"AAAA,KAAK,qBAAqB,GAAG;KAAG,SAAS,IAAI,MAAM,GAAG,MAAM;CAAE,CAAA;AAE9D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,eAAe,GAAG;KAC3B,UAAU,IAAI,MAAM,GACjB,MAAM,GACN,qBAAqB;CAC1B,CAAA;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,CAAC,EAAE,OAAO,GACf,SAAS,GAAG,eAAe,CAgE7B"}
@@ -1,54 +0,0 @@
1
- /**
2
- * Returns `undefined` if the header is malformed.
3
- */
4
- export function parseWWWAuthenticateHeader(header) {
5
- if (typeof header !== 'string')
6
- return undefined;
7
- const wwwAuthenticate = {};
8
- // Split over commas, not within quoted strings
9
- const trimmedHeader = header.trim();
10
- if (!trimmedHeader)
11
- return wwwAuthenticate;
12
- const parts = trimmedHeader.split(/,(?=(?:[^"]*"[^"]*")*[^"]*$)/);
13
- let currentParams = null;
14
- for (let part of parts) {
15
- // Check if the part starts with an auth scheme
16
- const schemeMatch = part.trim().match(/^([^"=\s]+)(\s+.*)?$/);
17
- if (schemeMatch) {
18
- const scheme = schemeMatch[1];
19
- // Duplicate scheme
20
- if (Object.hasOwn(wwwAuthenticate, scheme))
21
- return undefined;
22
- const rest = schemeMatch[2]?.trim();
23
- if (!rest) {
24
- // Scheme only (no params or token68)
25
- currentParams = null;
26
- wwwAuthenticate[scheme] = Object.create(null);
27
- continue;
28
- }
29
- if (!rest.includes('=')) {
30
- // Scheme with token68
31
- currentParams = null;
32
- wwwAuthenticate[scheme] = rest;
33
- continue;
34
- }
35
- // Scheme with params
36
- currentParams = Object.create(null);
37
- wwwAuthenticate[scheme] = currentParams;
38
- // Fall through to parse params
39
- part = rest;
40
- }
41
- // Invalid header
42
- if (!currentParams)
43
- return undefined;
44
- const param = part.match(/^\s*([^"\s=]+)=(?:("[^"\\]*(?:\\.[^"\\]*)*")|([^\s,"]*))\s*$/);
45
- // invalid param
46
- if (!param)
47
- return undefined;
48
- const paramName = param[1];
49
- const paramValue = param[3] ?? param[2].slice(1, -1).replaceAll(/\\(.)/g, '$1');
50
- currentParams[paramName] = paramValue;
51
- }
52
- return wwwAuthenticate;
53
- }
54
- //# sourceMappingURL=www-authenticate.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"www-authenticate.js","sourceRoot":"","sources":["../src/www-authenticate.ts"],"names":[],"mappings":"AA+BA;;GAEG;AACH,MAAM,UAAU,0BAA0B,CACxC,MAAgB;IAEhB,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IAEhD,MAAM,eAAe,GAAoB,EAAE,CAAA;IAE3C,+CAA+C;IAC/C,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,EAAE,CAAA;IACnC,IAAI,CAAC,aAAa;QAAE,OAAO,eAAe,CAAA;IAE1C,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAA;IAEjE,IAAI,aAAa,GAAiC,IAAI,CAAA;IAEtD,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,+CAA+C;QAC/C,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAA;QAC7D,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;YAE7B,mBAAmB;YACnB,IAAI,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC;gBAAE,OAAO,SAAS,CAAA;YAE5D,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAA;YACnC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,qCAAqC;gBACrC,aAAa,GAAG,IAAI,CAAA;gBACpB,eAAe,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;gBAC7C,SAAQ;YACV,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACxB,sBAAsB;gBACtB,aAAa,GAAG,IAAI,CAAA;gBACpB,eAAe,CAAC,MAAM,CAAC,GAAG,IAAI,CAAA;gBAC9B,SAAQ;YACV,CAAC;YAED,qBAAqB;YAErB,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAA0B,CAAA;YAC5D,eAAe,CAAC,MAAM,CAAC,GAAG,aAAa,CAAA;YAEvC,+BAA+B;YAC/B,IAAI,GAAG,IAAI,CAAA;QACb,CAAC;QAED,iBAAiB;QACjB,IAAI,CAAC,aAAa;YAAE,OAAO,SAAS,CAAA;QAEpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CACtB,8DAA8D,CAC/D,CAAA;QAED,gBAAgB;QAChB,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAA;QAE5B,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QAC1B,MAAM,UAAU,GACd,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QAE/D,aAAa,CAAC,SAAS,CAAC,GAAG,UAAU,CAAA;IACvC,CAAC;IAED,OAAO,eAAe,CAAA;AACxB,CAAC","sourcesContent":["type WWWAuthenticateParams = { [authParam in string]: string }\n\n/**\n * Parsed representation of a WWW-Authenticate HTTP header.\n *\n * Maps authentication scheme names to either:\n * - A token68 string (compact authentication data)\n * - A params object with key-value pairs\n *\n * @example Bearer with realm\n * ```typescript\n * // WWW-Authenticate: Bearer realm=\"example\"\n * const parsed: WWWAuthenticate = {\n * Bearer: { realm: 'example' }\n * }\n * ```\n *\n * @example DPoP with error\n * ```typescript\n * // WWW-Authenticate: DPoP error=\"use_dpop_nonce\", error_description=\"...\"\n * const parsed: WWWAuthenticate = {\n * DPoP: { error: 'use_dpop_nonce', error_description: '...' }\n * }\n * ```\n */\nexport type WWWAuthenticate = {\n [authScheme in string]:\n | string // token68\n | WWWAuthenticateParams\n}\n\n/**\n * Returns `undefined` if the header is malformed.\n */\nexport function parseWWWAuthenticateHeader(\n header?: unknown,\n): undefined | WWWAuthenticate {\n if (typeof header !== 'string') return undefined\n\n const wwwAuthenticate: WWWAuthenticate = {}\n\n // Split over commas, not within quoted strings\n const trimmedHeader = header.trim()\n if (!trimmedHeader) return wwwAuthenticate\n\n const parts = trimmedHeader.split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/)\n\n let currentParams: WWWAuthenticateParams | null = null\n\n for (let part of parts) {\n // Check if the part starts with an auth scheme\n const schemeMatch = part.trim().match(/^([^\"=\\s]+)(\\s+.*)?$/)\n if (schemeMatch) {\n const scheme = schemeMatch[1]\n\n // Duplicate scheme\n if (Object.hasOwn(wwwAuthenticate, scheme)) return undefined\n\n const rest = schemeMatch[2]?.trim()\n if (!rest) {\n // Scheme only (no params or token68)\n currentParams = null\n wwwAuthenticate[scheme] = Object.create(null)\n continue\n }\n\n if (!rest.includes('=')) {\n // Scheme with token68\n currentParams = null\n wwwAuthenticate[scheme] = rest\n continue\n }\n\n // Scheme with params\n\n currentParams = Object.create(null) as WWWAuthenticateParams\n wwwAuthenticate[scheme] = currentParams\n\n // Fall through to parse params\n part = rest\n }\n\n // Invalid header\n if (!currentParams) return undefined\n\n const param = part.match(\n /^\\s*([^\"\\s=]+)=(?:(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")|([^\\s,\"]*))\\s*$/,\n )\n\n // invalid param\n if (!param) return undefined\n\n const paramName = param[1]\n const paramValue =\n param[3] ?? param[2]!.slice(1, -1).replaceAll(/\\\\(.)/g, '$1')\n\n currentParams[paramName] = paramValue\n }\n\n return wwwAuthenticate\n}\n"]}
package/dist/xrpc.d.ts DELETED
@@ -1,194 +0,0 @@
1
- import { type InferInput, type InferPayload, type Main, type Params, type Procedure, type Query, type Restricted, type Subscription } from '@atproto/lex-schema';
2
- import type { Agent, AgentOptions } from './agent.js';
3
- import type { XrpcFailure } from './errors.js';
4
- import type { XrpcResponseOptions } from './response.js';
5
- import { XrpcResponse } from './response.js';
6
- import type { BinaryBodyInit } from './types.js';
7
- import type { XrpcRequestHeadersOptions } from './util.js';
8
- /**
9
- * The query/path parameters type for an XRPC method, inferred from its schema.
10
- *
11
- * @typeParam M - The XRPC method type (Procedure, Query, or Subscription)
12
- */
13
- export type XrpcRequestParams<M extends Procedure | Query | Subscription> = InferInput<M['parameters']>;
14
- type XrpcRequestParamsOptions<P extends Params> = NonNullable<unknown> extends P ? {
15
- params?: P;
16
- } : {
17
- params: P;
18
- };
19
- type XrpcRequestPayload<M extends Procedure | Query> = M extends Procedure ? InferPayload<M['input'], BinaryBodyInit> : undefined;
20
- type XrpcRequestPayloadOptions<TPayload> = TPayload extends {
21
- body: infer B;
22
- encoding: infer E;
23
- } ? {
24
- body: B;
25
- /**
26
- * mime type hint for binary bodies
27
- *
28
- * Only needed for endpoints that accept binary input (e.g. file uploads)
29
- * when the body is a Blob-like object without a type (e.g. fetch-blob's
30
- * Blob). If the body is a Blob-like object with a type, that type will be
31
- * used as the content-type header instead of this option.
32
- *
33
- * @default "application/octet-stream"
34
- */
35
- encoding?: E;
36
- } : {
37
- body?: undefined;
38
- encoding?: undefined;
39
- };
40
- /**
41
- * Options for making an XRPC request, based on the method schema.
42
- *
43
- * Combines {@link XrpcRequestOptions} and {@link XrpcResponseOptions} with
44
- * method-specific params and body requirements. The type system ensures
45
- * required params/body are provided based on the method schema.
46
- *
47
- * @typeParam M - The XRPC method type (Procedure or Query)
48
- *
49
- * @example Query with params
50
- * ```typescript
51
- * const options: XrpcOptions<typeof app.bsky.feed.getTimeline.main> = {
52
- * params: { limit: 50 }
53
- * }
54
- * ```
55
- *
56
- * @example Procedure with body
57
- * ```typescript
58
- * const options: XrpcOptions<typeof com.atproto.repo.createRecord.main> = {
59
- * body: { repo: did, collection: 'app.bsky.feed.post', record: { ... } }
60
- * }
61
- * ```
62
- */
63
- export type XrpcOptions<M extends Procedure | Query = Procedure | Query> = XrpcRequestOptions<M> & XrpcResponseOptions & RetryOptions;
64
- export type XrpcRequestOptions<M extends Procedure | Query = Procedure | Query> = XrpcRequestProcessingOptions & XrpcRequestHeadersOptions & XrpcRequestPayloadOptions<XrpcRequestPayload<M>> & XrpcRequestParamsOptions<XrpcRequestParams<M>>;
65
- export type XrpcRequestProcessingOptions = {
66
- /**
67
- * AbortSignal to cancel the request.
68
- */
69
- signal?: AbortSignal;
70
- /**
71
- * Whether to validate the request against the method's input schema. Enabling
72
- * this can help catch errors early but may have a performance cost. This
73
- * would typically only be set to `true` in development or debugging
74
- * scenarios.
75
- *
76
- * @default false
77
- */
78
- validateRequest?: boolean;
79
- };
80
- /**
81
- * Makes an XRPC request and throws on failure.
82
- *
83
- * This is the low-level function for making XRPC calls.
84
- *
85
- * @param agent - The {@link Agent} to use for making the request
86
- * @param ns - The lexicon method definition
87
- * @param options - Request {@link XrpcOptions options} (params, body, headers, etc.)
88
- * @returns The successful {@link XrpcResponse}
89
- * @throws {XrpcFailure} When the request fails
90
- *
91
- * @example
92
- * ```typescript
93
- * const response = await xrpc('https://bsky.network', com.atproto.identity.resolveHandle, {
94
- * params: { handle: "atproto.com" }
95
- * })
96
- * ```
97
- *
98
- * @example
99
- * ```typescript
100
- * const response = await xrpc(agent, app.bsky.feed.getTimeline.main, {
101
- * params: { limit: 50 }
102
- * })
103
- * ```
104
- */
105
- export declare function xrpc<const M extends Query | Procedure>(agentOpts: Agent | AgentOptions, ns: NonNullable<unknown> extends XrpcOptions<M> ? Main<M> : Restricted<'This XRPC method requires an "options" argument'>): Promise<XrpcResponse<M>>;
106
- export declare function xrpc<const M extends Query | Procedure>(agentOpts: Agent | AgentOptions, ns: Main<M>, options: XrpcOptions<M>): Promise<XrpcResponse<M>>;
107
- /**
108
- * Union type representing either a successful response or a failure.
109
- *
110
- * Both {@link XrpcResponse} and {@link XrpcFailure} have a `success` property
111
- * that can be used to discriminate between them.
112
- *
113
- * @typeParam M - The XRPC method type
114
- */
115
- export type XrpcResult<M extends Procedure | Query> = XrpcResponse<M> | XrpcFailure<M>;
116
- /**
117
- * Makes an XRPC request without throwing on failure.
118
- *
119
- * Returns a discriminated union that can be checked via the `success` property.
120
- * This is useful for handling errors without try/catch blocks. This also allows
121
- * failure results to be typed with the method schema, which can provide better
122
- * type safety when handling errors (e.g. checking for specific error codes).
123
- *
124
- * @param agent - The {@link Agent} to use for making the request
125
- * @param ns - The lexicon method definition
126
- * @param options - Request {@link XrpcOptions options} (params, body, headers, etc.)
127
- * @returns Either a successful {@link XrpcResponse} or an {@link XrpcFailure}
128
- *
129
- * @example
130
- * ```typescript
131
- * const result = await xrpcSafe('https://example.com', app.bsky.actor.getProfile, {
132
- * params: { actor: 'alice.bsky.social' }
133
- * })
134
- *
135
- * if (result.success) {
136
- * console.log(result.body.displayName)
137
- * } else {
138
- * console.error('Request failed:', result.error)
139
- * }
140
- * ```
141
- */
142
- export declare function xrpcSafe<const M extends Query | Procedure>(agentOpts: Agent | AgentOptions, ns: NonNullable<unknown> extends XrpcOptions<M> ? Main<M> : Restricted<'This XRPC method requires an "options" argument'>): Promise<XrpcResult<M>>;
143
- export declare function xrpcSafe<const M extends Query | Procedure>(agentOpts: Agent | AgentOptions, ns: Main<M>, options: XrpcOptions<M>): Promise<XrpcResult<M>>;
144
- /**
145
- * Extracts the root cause from an error, unwrapping common fetch-related errors
146
- * such as those from undici (Node's internal fetch implementation).
147
- *
148
- * @param err - The error to extract the root cause from
149
- * @returns The root cause error, or the original error if no specific pattern is matched
150
- * @remarks This is useful for getting more specific error information from fetch-related failures, especially in Node environments using undici.
151
- */
152
- export declare function extractFetchErrorCause(err: unknown): unknown;
153
- export type RetryOptions = {
154
- /**
155
- * Function to determine whether a request should be retried after a failure.
156
- *
157
- * @default `(failure) => failure.shouldRetry()`
158
- */
159
- retry?: (failure: XrpcFailure, context: {
160
- counter: number;
161
- }) => boolean;
162
- /**
163
- * Maximum number of retries to allow.
164
- *
165
- * @default 0 (no retries)
166
- */
167
- maxRetries?: number;
168
- /**
169
- * Max number of milliseconds allow between retries
170
- *
171
- * @default 30000
172
- */
173
- maxRetryTimeout?: number;
174
- /**
175
- * Initial number of milliseconds to wait before retrying for the first time.
176
- *
177
- * @default 500
178
- */
179
- minRetryTimeout?: number;
180
- /**
181
- * Factor to multiply the timeout factor between retries.
182
- *
183
- * @default 2
184
- */
185
- retryTimeoutFactor?: number;
186
- /**
187
- * Automatically infer timeout between retries based on header values (`Retry-After`, `RateLimit-Reset`).
188
- *
189
- * @default true
190
- */
191
- retryHeaders?: boolean;
192
- };
193
- export {};
194
- //# sourceMappingURL=xrpc.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"xrpc.d.ts","sourceRoot":"","sources":["../src/xrpc.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,IAAI,EAET,KAAK,MAAM,EAEX,KAAK,SAAS,EACd,KAAK,KAAK,EACV,KAAK,UAAU,EACf,KAAK,YAAY,EAElB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAErD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAChD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AAW1D;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,YAAY,IACtE,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAA;AAG7B,KAAK,wBAAwB,CAAC,CAAC,SAAS,MAAM,IAC5C,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,CAAC,CAAA;CAAE,CAAA;AAEjE,KAAK,kBAAkB,CAAC,CAAC,SAAS,SAAS,GAAG,KAAK,IAAI,CAAC,SAAS,SAAS,GACtE,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC,GACxC,SAAS,CAAA;AAEb,KAAK,yBAAyB,CAAC,QAAQ,IAAI,QAAQ,SAAS;IAC1D,IAAI,EAAE,MAAM,CAAC,CAAA;IACb,QAAQ,EAAE,MAAM,CAAC,CAAA;CAClB,GACG;IACE,IAAI,EAAE,CAAC,CAAA;IAEP;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,CAAC,CAAA;CACb,GACD;IAAE,IAAI,CAAC,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,CAAA;AAE9C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,IACrE,kBAAkB,CAAC,CAAC,CAAC,GAAG,mBAAmB,GAAG,YAAY,CAAA;AAE5D,MAAM,MAAM,kBAAkB,CAC5B,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,IAC7C,4BAA4B,GAC9B,yBAAyB,GACzB,yBAAyB,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,GAChD,wBAAwB,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAA;AAEhD,MAAM,MAAM,4BAA4B,GAAG;IACzC;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IAEpB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,KAAK,GAAG,SAAS,EAC1D,SAAS,EAAE,KAAK,GAAG,YAAY,EAC/B,EAAE,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,WAAW,CAAC,CAAC,CAAC,GAC3C,IAAI,CAAC,CAAC,CAAC,GACP,UAAU,CAAC,iDAAiD,CAAC,GAChE,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;AAC3B,wBAAsB,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,KAAK,GAAG,SAAS,EAC1D,SAAS,EAAE,KAAK,GAAG,YAAY,EAC/B,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,EACX,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GACtB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;AAW3B;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,SAAS,GAAG,KAAK,IAChD,YAAY,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,QAAQ,CAAC,KAAK,CAAC,CAAC,SAAS,KAAK,GAAG,SAAS,EAC9D,SAAS,EAAE,KAAK,GAAG,YAAY,EAC/B,EAAE,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,WAAW,CAAC,CAAC,CAAC,GAC3C,IAAI,CAAC,CAAC,CAAC,GACP,UAAU,CAAC,iDAAiD,CAAC,GAChE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;AACzB,wBAAsB,QAAQ,CAAC,KAAK,CAAC,CAAC,SAAS,KAAK,GAAG,SAAS,EAC9D,SAAS,EAAE,KAAK,GAAG,YAAY,EAC/B,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,EACX,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GACtB,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;AAsOzB;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAgB5D;AAED,MAAM,MAAM,YAAY,GAAG;IACzB;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAA;IACvE;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA"}
package/dist/xrpc.js DELETED
@@ -1,235 +0,0 @@
1
- import { isLexScalar, isPlainObject } from '@atproto/lex-data';
2
- import { lexStringify } from '@atproto/lex-json';
3
- import { getMain, } from '@atproto/lex-schema';
4
- import { buildAgent } from './agent.js';
5
- import { XrpcFetchError, XrpcResponseError, asXrpcFailure } from './errors.js';
6
- import { XrpcResponse } from './response.js';
7
- import { asUint8ArrayArrayBuffer, buildXrpcRequestHeaders, isAsyncIterable, isBlobLike, throwIfAborted, toReadableStream, wait, } from './util.js';
8
- export async function xrpc(agentOpts, ns, options = {}) {
9
- const response = await xrpcSafe(agentOpts, ns, options);
10
- if (response.success)
11
- return response;
12
- else
13
- throw response;
14
- }
15
- export async function xrpcSafe(agentOpts, ns, options = {}) {
16
- const method = getMain(ns);
17
- for (let counter = 1;; counter++) {
18
- throwIfAborted(options.signal);
19
- try {
20
- const agent = buildAgent(agentOpts);
21
- const url = xrpcRequestUrl(method, options);
22
- const request = xrpcRequestInit(method, options);
23
- const response = await agent.fetchHandler(url, request).catch((err) => {
24
- const cause = extractFetchErrorCause(err);
25
- throw new XrpcFetchError(method, cause);
26
- });
27
- return await XrpcResponse.fromFetchResponse(method, response, options);
28
- }
29
- catch (cause) {
30
- const failure = asXrpcFailure(method, cause);
31
- // Cannot retry a request with a consumable body
32
- if (options.body instanceof ReadableStream ||
33
- isAsyncIterable(options.body)) {
34
- return failure;
35
- }
36
- const waitTime = getRetryWaitTime(failure, options, counter);
37
- if (waitTime == null) {
38
- return failure;
39
- }
40
- await wait(waitTime, options);
41
- }
42
- }
43
- }
44
- function xrpcRequestUrl(method, options) {
45
- const path = `/xrpc/${method.nsid}`;
46
- // @NOTE param.toURLSearchParams() will always validate the params in order to
47
- // apply default values, so we can't disable it with options.validateRequest
48
- const queryString = method.parameters
49
- ?.toURLSearchParams(options.params ?? {})
50
- .toString();
51
- return queryString ? `${path}?${queryString}` : path;
52
- }
53
- function xrpcRequestInit(schema, options) {
54
- const headers = buildXrpcRequestHeaders(options);
55
- // Tell the server what type of response we're expecting
56
- if (schema.output.encoding) {
57
- headers.set('accept', schema.output.encoding);
58
- }
59
- // Caller should not set content-type header
60
- if (headers.has('content-type')) {
61
- const contentType = headers.get('content-type');
62
- throw new TypeError(`Unexpected content-type header (${contentType})`);
63
- }
64
- // Requests with body
65
- if ('input' in schema) {
66
- const encodingHint = options.encoding;
67
- const input = xrpcProcedureInput(schema, options, encodingHint);
68
- if (input) {
69
- headers.set('content-type', input.encoding);
70
- }
71
- else if (encodingHint != null) {
72
- throw new TypeError(`Unexpected encoding hint (${encodingHint})`);
73
- }
74
- return {
75
- duplex: 'half',
76
- redirect: 'follow',
77
- referrerPolicy: 'strict-origin-when-cross-origin', // (default)
78
- mode: 'cors', // (default)
79
- signal: options.signal,
80
- method: 'POST',
81
- headers,
82
- body: input?.body,
83
- };
84
- }
85
- // Requests without body
86
- return {
87
- duplex: 'half',
88
- redirect: 'follow',
89
- referrerPolicy: 'strict-origin-when-cross-origin', // (default)
90
- mode: 'cors', // (default)
91
- signal: options.signal,
92
- method: 'GET',
93
- headers,
94
- };
95
- }
96
- function xrpcProcedureInput(method, options, encodingHint) {
97
- const { input } = method;
98
- const { body } = options;
99
- if (options.validateRequest) {
100
- input.schema?.check(body);
101
- }
102
- // Special handling for endpoints expecting application/json input
103
- if (input.encoding === 'application/json') {
104
- // @NOTE **NOT** using isLexValue here to avoid deep checks in order to
105
- // distinguish between LexValue and BinaryBodyInit.
106
- if (!isLexScalar(body) && !isPlainObject(body) && !Array.isArray(body)) {
107
- throw new TypeError(`Expected LexValue body, got ${typeof body}`);
108
- }
109
- return buildPayload(input, lexStringify(body), encodingHint);
110
- }
111
- // Other encodings will be sent unaltered (ie. as binary data)
112
- switch (typeof body) {
113
- case 'undefined':
114
- case 'string':
115
- return buildPayload(input, body, encodingHint);
116
- case 'object': {
117
- if (body === null)
118
- break;
119
- if (ArrayBuffer.isView(body)) {
120
- return buildPayload(input, asUint8ArrayArrayBuffer(body), encodingHint);
121
- }
122
- else if (body instanceof ArrayBuffer ||
123
- body instanceof ReadableStream) {
124
- return buildPayload(input, body, encodingHint);
125
- }
126
- else if (isAsyncIterable(body)) {
127
- // @NOTE While fetch() does not allow SharedArrayBuffer-backed
128
- // Uint8Arrays as "body", it **does** allow using ReadableStreams made
129
- // of Uint8Arrays<SharedArrayBuffer> (tested on NodeJS 22) as "body".
130
- return buildPayload(input, toReadableStream(body), encodingHint);
131
- }
132
- else if (isBlobLike(body)) {
133
- return buildPayload(input, body, encodingHint || body.type);
134
- }
135
- }
136
- }
137
- throw new TypeError(`Invalid ${typeof body} body for ${input.encoding} encoding`);
138
- }
139
- function buildPayload(schema, body, encodingHint) {
140
- if (schema.encoding === undefined) {
141
- if (body !== undefined) {
142
- throw new TypeError(`Endpoint expects no payload`);
143
- }
144
- return null;
145
- }
146
- if (body === undefined) {
147
- // This error would be returned by the server, but we can catch it earlier
148
- // to avoid un-necessary requests. Note that a content-length of 0 does not
149
- // necessary mean that the body is "empty" (e.g. an empty txt file).
150
- throw new TypeError(`A request body is expected but none was provided`);
151
- }
152
- const encoding = buildEncoding(schema, encodingHint);
153
- return { encoding, body };
154
- }
155
- function buildEncoding(schema, encodingHint) {
156
- // Should never happen (required for type safety)
157
- if (!schema.encoding) {
158
- throw new TypeError('Unexpected payload');
159
- }
160
- if (encodingHint?.length) {
161
- if (!schema.matchesEncoding(encodingHint)) {
162
- throw new TypeError(`Cannot send a body with content-type "${encodingHint}" for "${schema.encoding}" encoding`);
163
- }
164
- return encodingHint;
165
- }
166
- // Fallback
167
- if (schema.encoding === '*/*') {
168
- return 'application/octet-stream';
169
- }
170
- if (schema.encoding.startsWith('text/')) {
171
- return schema.encoding.includes('*')
172
- ? 'text/plain; charset=utf-8'
173
- : `${schema.encoding}; charset=utf-8`;
174
- }
175
- if (!schema.encoding.includes('*')) {
176
- return schema.encoding;
177
- }
178
- throw new TypeError(`Unable to determine payload encoding. Please provide a 'content-type' header matching ${schema.encoding}.`);
179
- }
180
- /**
181
- * Extracts the root cause from an error, unwrapping common fetch-related errors
182
- * such as those from undici (Node's internal fetch implementation).
183
- *
184
- * @param err - The error to extract the root cause from
185
- * @returns The root cause error, or the original error if no specific pattern is matched
186
- * @remarks This is useful for getting more specific error information from fetch-related failures, especially in Node environments using undici.
187
- */
188
- export function extractFetchErrorCause(err) {
189
- // Unwrap the Network error from undici (i.e. Node's internal fetch() implementation)
190
- // https://github.com/nodejs/undici/blob/04cb77327f7ada95c2e5b67424cddcb22d7bf882/lib/web/fetch/index.js#L234-L239
191
- if (err instanceof TypeError &&
192
- err.message === 'fetch failed' &&
193
- err.cause !== undefined) {
194
- return err.cause;
195
- }
196
- // @TODO Add other unwrap patterns here as needed (e.g. for other fetch
197
- // implementations or common network libraries, like "node:http", or in other
198
- // environments like React Native, Deno, Bun, Browser, etc.)
199
- return err;
200
- }
201
- function getRetryWaitTime(failure, options, counter) {
202
- const { retry, maxRetries = 0, minRetryTimeout = 500, maxRetryTimeout = 30_000, retryTimeoutFactor = 2, retryHeaders = true, } = options;
203
- if (counter > maxRetries) {
204
- return undefined;
205
- }
206
- const shouldRetry = retry
207
- ? retry(failure, { counter })
208
- : failure.shouldRetry();
209
- if (!shouldRetry) {
210
- return undefined;
211
- }
212
- const waitTime = retryHeaders && failure instanceof XrpcResponseError
213
- ? getWaitTimeFromHeaders(failure.headers)
214
- : undefined;
215
- return Math.min(maxRetryTimeout, waitTime ?? minRetryTimeout * retryTimeoutFactor ** (counter - 1));
216
- }
217
- function getWaitTimeFromHeaders(headers) {
218
- const retryAfterHeader = headers.get('retry-after');
219
- if (retryAfterHeader) {
220
- const waitTime = /^\s*\d+\s*$/.test(retryAfterHeader)
221
- ? // Retry-After is in seconds
222
- Number(retryAfterHeader) * 1000
223
- : // Retry-After is an http-date
224
- new Date(retryAfterHeader).getTime() - Date.now();
225
- if (waitTime > 0)
226
- return waitTime;
227
- }
228
- const resetsAt = headers.get('RateLimit-Reset'); // epoch
229
- if (resetsAt) {
230
- const waitTime = Number(resetsAt) * 1000 - Date.now();
231
- if (waitTime > 0)
232
- return waitTime;
233
- }
234
- }
235
- //# sourceMappingURL=xrpc.js.map
package/dist/xrpc.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"xrpc.js","sourceRoot":"","sources":["../src/xrpc.ts"],"names":[],"mappings":"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","sourcesContent":["import type { LexValue } from '@atproto/lex-data'\nimport { isLexScalar, isPlainObject } from '@atproto/lex-data'\nimport { lexStringify } from '@atproto/lex-json'\nimport {\n type InferInput,\n type InferPayload,\n type Main,\n type NsidString,\n type Params,\n type Payload,\n type Procedure,\n type Query,\n type Restricted,\n type Subscription,\n getMain,\n} from '@atproto/lex-schema'\nimport type { Agent, AgentOptions } from './agent.js'\nimport { buildAgent } from './agent.js'\nimport type { XrpcFailure } from './errors.js'\nimport { XrpcFetchError, XrpcResponseError, asXrpcFailure } from './errors.js'\nimport type { XrpcResponseOptions } from './response.js'\nimport { XrpcResponse } from './response.js'\nimport type { BinaryBodyInit } from './types.js'\nimport type { XrpcRequestHeadersOptions } from './util.js'\nimport {\n asUint8ArrayArrayBuffer,\n buildXrpcRequestHeaders,\n isAsyncIterable,\n isBlobLike,\n throwIfAborted,\n toReadableStream,\n wait,\n} from './util.js'\n\n/**\n * The query/path parameters type for an XRPC method, inferred from its schema.\n *\n * @typeParam M - The XRPC method type (Procedure, Query, or Subscription)\n */\nexport type XrpcRequestParams<M extends Procedure | Query | Subscription> =\n InferInput<M['parameters']>\n\n// If all params are optional, allow omitting the params object\ntype XrpcRequestParamsOptions<P extends Params> =\n NonNullable<unknown> extends P ? { params?: P } : { params: P }\n\ntype XrpcRequestPayload<M extends Procedure | Query> = M extends Procedure\n ? InferPayload<M['input'], BinaryBodyInit>\n : undefined\n\ntype XrpcRequestPayloadOptions<TPayload> = TPayload extends {\n body: infer B\n encoding: infer E\n}\n ? {\n body: B\n\n /**\n * mime type hint for binary bodies\n *\n * Only needed for endpoints that accept binary input (e.g. file uploads)\n * when the body is a Blob-like object without a type (e.g. fetch-blob's\n * Blob). If the body is a Blob-like object with a type, that type will be\n * used as the content-type header instead of this option.\n *\n * @default \"application/octet-stream\"\n */\n encoding?: E\n }\n : { body?: undefined; encoding?: undefined }\n\n/**\n * Options for making an XRPC request, based on the method schema.\n *\n * Combines {@link XrpcRequestOptions} and {@link XrpcResponseOptions} with\n * method-specific params and body requirements. The type system ensures\n * required params/body are provided based on the method schema.\n *\n * @typeParam M - The XRPC method type (Procedure or Query)\n *\n * @example Query with params\n * ```typescript\n * const options: XrpcOptions<typeof app.bsky.feed.getTimeline.main> = {\n * params: { limit: 50 }\n * }\n * ```\n *\n * @example Procedure with body\n * ```typescript\n * const options: XrpcOptions<typeof com.atproto.repo.createRecord.main> = {\n * body: { repo: did, collection: 'app.bsky.feed.post', record: { ... } }\n * }\n * ```\n */\nexport type XrpcOptions<M extends Procedure | Query = Procedure | Query> =\n XrpcRequestOptions<M> & XrpcResponseOptions & RetryOptions\n\nexport type XrpcRequestOptions<\n M extends Procedure | Query = Procedure | Query,\n> = XrpcRequestProcessingOptions &\n XrpcRequestHeadersOptions &\n XrpcRequestPayloadOptions<XrpcRequestPayload<M>> &\n XrpcRequestParamsOptions<XrpcRequestParams<M>>\n\nexport type XrpcRequestProcessingOptions = {\n /**\n * AbortSignal to cancel the request.\n */\n signal?: AbortSignal\n\n /**\n * Whether to validate the request against the method's input schema. Enabling\n * this can help catch errors early but may have a performance cost. This\n * would typically only be set to `true` in development or debugging\n * scenarios.\n *\n * @default false\n */\n validateRequest?: boolean\n}\n\n/**\n * Makes an XRPC request and throws on failure.\n *\n * This is the low-level function for making XRPC calls.\n *\n * @param agent - The {@link Agent} to use for making the request\n * @param ns - The lexicon method definition\n * @param options - Request {@link XrpcOptions options} (params, body, headers, etc.)\n * @returns The successful {@link XrpcResponse}\n * @throws {XrpcFailure} When the request fails\n *\n * @example\n * ```typescript\n * const response = await xrpc('https://bsky.network', com.atproto.identity.resolveHandle, {\n * params: { handle: \"atproto.com\" }\n * })\n * ```\n *\n * @example\n * ```typescript\n * const response = await xrpc(agent, app.bsky.feed.getTimeline.main, {\n * params: { limit: 50 }\n * })\n * ```\n */\nexport async function xrpc<const M extends Query | Procedure>(\n agentOpts: Agent | AgentOptions,\n ns: NonNullable<unknown> extends XrpcOptions<M>\n ? Main<M>\n : Restricted<'This XRPC method requires an \"options\" argument'>,\n): Promise<XrpcResponse<M>>\nexport async function xrpc<const M extends Query | Procedure>(\n agentOpts: Agent | AgentOptions,\n ns: Main<M>,\n options: XrpcOptions<M>,\n): Promise<XrpcResponse<M>>\nexport async function xrpc<const M extends Query | Procedure>(\n agentOpts: Agent | AgentOptions,\n ns: Main<M>,\n options: XrpcOptions<M> = {} as XrpcOptions<M>,\n): Promise<XrpcResponse<M>> {\n const response = await xrpcSafe<M>(agentOpts, ns, options)\n if (response.success) return response\n else throw response\n}\n\n/**\n * Union type representing either a successful response or a failure.\n *\n * Both {@link XrpcResponse} and {@link XrpcFailure} have a `success` property\n * that can be used to discriminate between them.\n *\n * @typeParam M - The XRPC method type\n */\nexport type XrpcResult<M extends Procedure | Query> =\n XrpcResponse<M> | XrpcFailure<M>\n\n/**\n * Makes an XRPC request without throwing on failure.\n *\n * Returns a discriminated union that can be checked via the `success` property.\n * This is useful for handling errors without try/catch blocks. This also allows\n * failure results to be typed with the method schema, which can provide better\n * type safety when handling errors (e.g. checking for specific error codes).\n *\n * @param agent - The {@link Agent} to use for making the request\n * @param ns - The lexicon method definition\n * @param options - Request {@link XrpcOptions options} (params, body, headers, etc.)\n * @returns Either a successful {@link XrpcResponse} or an {@link XrpcFailure}\n *\n * @example\n * ```typescript\n * const result = await xrpcSafe('https://example.com', app.bsky.actor.getProfile, {\n * params: { actor: 'alice.bsky.social' }\n * })\n *\n * if (result.success) {\n * console.log(result.body.displayName)\n * } else {\n * console.error('Request failed:', result.error)\n * }\n * ```\n */\nexport async function xrpcSafe<const M extends Query | Procedure>(\n agentOpts: Agent | AgentOptions,\n ns: NonNullable<unknown> extends XrpcOptions<M>\n ? Main<M>\n : Restricted<'This XRPC method requires an \"options\" argument'>,\n): Promise<XrpcResult<M>>\nexport async function xrpcSafe<const M extends Query | Procedure>(\n agentOpts: Agent | AgentOptions,\n ns: Main<M>,\n options: XrpcOptions<M>,\n): Promise<XrpcResult<M>>\nexport async function xrpcSafe<const M extends Query | Procedure>(\n agentOpts: Agent | AgentOptions,\n ns: Main<M>,\n options: XrpcOptions<M> = {} as XrpcOptions<M>,\n): Promise<XrpcResult<M>> {\n const method: M = getMain(ns)\n\n for (let counter = 1; ; counter++) {\n throwIfAborted(options.signal)\n try {\n const agent = buildAgent(agentOpts)\n const url = xrpcRequestUrl(method, options)\n const request = xrpcRequestInit(method, options)\n const response = await agent.fetchHandler(url, request).catch((err) => {\n const cause = extractFetchErrorCause(err)\n throw new XrpcFetchError(method, cause)\n })\n return await XrpcResponse.fromFetchResponse<M>(method, response, options)\n } catch (cause) {\n const failure = asXrpcFailure(method, cause)\n\n // Cannot retry a request with a consumable body\n if (\n options.body instanceof ReadableStream ||\n isAsyncIterable(options.body)\n ) {\n return failure\n }\n\n const waitTime = getRetryWaitTime(failure, options, counter)\n if (waitTime == null) {\n return failure\n }\n\n await wait(waitTime, options)\n }\n }\n}\n\nfunction xrpcRequestUrl<M extends Procedure | Query | Subscription>(\n method: M,\n options: { params?: Params },\n): `/xrpc/${NsidString}${'' | `?${string}`}` {\n const path = `/xrpc/${method.nsid}` as const\n\n // @NOTE param.toURLSearchParams() will always validate the params in order to\n // apply default values, so we can't disable it with options.validateRequest\n\n const queryString = method.parameters\n ?.toURLSearchParams(options.params ?? {})\n .toString()\n\n return queryString ? (`${path}?${queryString}` as const) : path\n}\n\nfunction xrpcRequestInit<T extends Procedure | Query>(\n schema: T,\n options: XrpcRequestProcessingOptions &\n XrpcRequestHeadersOptions &\n XrpcProcedureInputOptions & {\n encoding?: string\n },\n): RequestInit & { duplex?: 'half' } {\n const headers = buildXrpcRequestHeaders(options)\n\n // Tell the server what type of response we're expecting\n if (schema.output.encoding) {\n headers.set('accept', schema.output.encoding)\n }\n\n // Caller should not set content-type header\n if (headers.has('content-type')) {\n const contentType = headers.get('content-type')\n throw new TypeError(`Unexpected content-type header (${contentType})`)\n }\n\n // Requests with body\n if ('input' in schema) {\n const encodingHint = options.encoding\n const input = xrpcProcedureInput(schema, options, encodingHint)\n\n if (input) {\n headers.set('content-type', input.encoding)\n } else if (encodingHint != null) {\n throw new TypeError(`Unexpected encoding hint (${encodingHint})`)\n }\n\n return {\n duplex: 'half',\n redirect: 'follow',\n referrerPolicy: 'strict-origin-when-cross-origin', // (default)\n mode: 'cors', // (default)\n signal: options.signal,\n method: 'POST',\n headers,\n body: input?.body,\n }\n }\n\n // Requests without body\n return {\n duplex: 'half',\n redirect: 'follow',\n referrerPolicy: 'strict-origin-when-cross-origin', // (default)\n mode: 'cors', // (default)\n signal: options.signal,\n method: 'GET',\n headers,\n }\n}\n\ntype XrpcProcedureInputOptions = {\n body?: LexValue | BinaryBodyInit\n validateRequest?: boolean\n}\n\nfunction xrpcProcedureInput(\n method: Procedure,\n options: XrpcProcedureInputOptions,\n encodingHint?: string,\n): null | { body: BodyInit; encoding: string } {\n const { input } = method\n const { body } = options\n\n if (options.validateRequest) {\n input.schema?.check(body)\n }\n\n // Special handling for endpoints expecting application/json input\n if (input.encoding === 'application/json') {\n // @NOTE **NOT** using isLexValue here to avoid deep checks in order to\n // distinguish between LexValue and BinaryBodyInit.\n if (!isLexScalar(body) && !isPlainObject(body) && !Array.isArray(body)) {\n throw new TypeError(`Expected LexValue body, got ${typeof body}`)\n }\n\n return buildPayload(input, lexStringify(body), encodingHint)\n }\n\n // Other encodings will be sent unaltered (ie. as binary data)\n switch (typeof body) {\n case 'undefined':\n case 'string':\n return buildPayload(input, body, encodingHint)\n case 'object': {\n if (body === null) break\n if (ArrayBuffer.isView(body)) {\n return buildPayload(input, asUint8ArrayArrayBuffer(body), encodingHint)\n } else if (\n body instanceof ArrayBuffer ||\n body instanceof ReadableStream\n ) {\n return buildPayload(input, body, encodingHint)\n } else if (isAsyncIterable(body)) {\n // @NOTE While fetch() does not allow SharedArrayBuffer-backed\n // Uint8Arrays as \"body\", it **does** allow using ReadableStreams made\n // of Uint8Arrays<SharedArrayBuffer> (tested on NodeJS 22) as \"body\".\n return buildPayload(input, toReadableStream(body), encodingHint)\n } else if (isBlobLike(body)) {\n return buildPayload(input, body, encodingHint || body.type)\n }\n }\n }\n\n throw new TypeError(\n `Invalid ${typeof body} body for ${input.encoding} encoding`,\n )\n}\n\nfunction buildPayload(\n schema: Payload,\n body: undefined | BodyInit,\n encodingHint?: string,\n): null | { body: BodyInit; encoding: string } {\n if (schema.encoding === undefined) {\n if (body !== undefined) {\n throw new TypeError(`Endpoint expects no payload`)\n }\n\n return null\n }\n\n if (body === undefined) {\n // This error would be returned by the server, but we can catch it earlier\n // to avoid un-necessary requests. Note that a content-length of 0 does not\n // necessary mean that the body is \"empty\" (e.g. an empty txt file).\n throw new TypeError(`A request body is expected but none was provided`)\n }\n\n const encoding = buildEncoding(schema, encodingHint)\n return { encoding, body }\n}\n\nfunction buildEncoding(schema: Payload, encodingHint?: string): string {\n // Should never happen (required for type safety)\n if (!schema.encoding) {\n throw new TypeError('Unexpected payload')\n }\n\n if (encodingHint?.length) {\n if (!schema.matchesEncoding(encodingHint)) {\n throw new TypeError(\n `Cannot send a body with content-type \"${encodingHint}\" for \"${schema.encoding}\" encoding`,\n )\n }\n return encodingHint\n }\n\n // Fallback\n\n if (schema.encoding === '*/*') {\n return 'application/octet-stream'\n }\n\n if (schema.encoding.startsWith('text/')) {\n return schema.encoding.includes('*')\n ? 'text/plain; charset=utf-8'\n : `${schema.encoding}; charset=utf-8`\n }\n\n if (!schema.encoding.includes('*')) {\n return schema.encoding\n }\n\n throw new TypeError(\n `Unable to determine payload encoding. Please provide a 'content-type' header matching ${schema.encoding}.`,\n )\n}\n\n/**\n * Extracts the root cause from an error, unwrapping common fetch-related errors\n * such as those from undici (Node's internal fetch implementation).\n *\n * @param err - The error to extract the root cause from\n * @returns The root cause error, or the original error if no specific pattern is matched\n * @remarks This is useful for getting more specific error information from fetch-related failures, especially in Node environments using undici.\n */\nexport function extractFetchErrorCause(err: unknown): unknown {\n // Unwrap the Network error from undici (i.e. Node's internal fetch() implementation)\n // https://github.com/nodejs/undici/blob/04cb77327f7ada95c2e5b67424cddcb22d7bf882/lib/web/fetch/index.js#L234-L239\n if (\n err instanceof TypeError &&\n err.message === 'fetch failed' &&\n err.cause !== undefined\n ) {\n return err.cause\n }\n\n // @TODO Add other unwrap patterns here as needed (e.g. for other fetch\n // implementations or common network libraries, like \"node:http\", or in other\n // environments like React Native, Deno, Bun, Browser, etc.)\n\n return err\n}\n\nexport type RetryOptions = {\n /**\n * Function to determine whether a request should be retried after a failure.\n *\n * @default `(failure) => failure.shouldRetry()`\n */\n retry?: (failure: XrpcFailure, context: { counter: number }) => boolean\n /**\n * Maximum number of retries to allow.\n *\n * @default 0 (no retries)\n */\n maxRetries?: number\n /**\n * Max number of milliseconds allow between retries\n *\n * @default 30000\n */\n maxRetryTimeout?: number\n /**\n * Initial number of milliseconds to wait before retrying for the first time.\n *\n * @default 500\n */\n minRetryTimeout?: number\n /**\n * Factor to multiply the timeout factor between retries.\n *\n * @default 2\n */\n retryTimeoutFactor?: number\n /**\n * Automatically infer timeout between retries based on header values (`Retry-After`, `RateLimit-Reset`).\n *\n * @default true\n */\n retryHeaders?: boolean\n}\n\nfunction getRetryWaitTime(\n failure: XrpcFailure,\n options: RetryOptions,\n counter: number,\n): number | undefined {\n const {\n retry,\n maxRetries = 0,\n minRetryTimeout = 500,\n maxRetryTimeout = 30_000,\n retryTimeoutFactor = 2,\n retryHeaders = true,\n } = options\n\n if (counter > maxRetries) {\n return undefined\n }\n\n const shouldRetry = retry\n ? retry(failure, { counter })\n : failure.shouldRetry()\n\n if (!shouldRetry) {\n return undefined\n }\n\n const waitTime =\n retryHeaders && failure instanceof XrpcResponseError\n ? getWaitTimeFromHeaders(failure.headers)\n : undefined\n\n return Math.min(\n maxRetryTimeout,\n waitTime ?? minRetryTimeout * retryTimeoutFactor ** (counter - 1),\n )\n}\n\nfunction getWaitTimeFromHeaders(headers: Headers): number | undefined {\n const retryAfterHeader = headers.get('retry-after')\n if (retryAfterHeader) {\n const waitTime = /^\\s*\\d+\\s*$/.test(retryAfterHeader)\n ? // Retry-After is in seconds\n Number(retryAfterHeader) * 1000\n : // Retry-After is an http-date\n new Date(retryAfterHeader).getTime() - Date.now()\n if (waitTime > 0) return waitTime\n }\n\n const resetsAt = headers.get('RateLimit-Reset') // epoch\n if (resetsAt) {\n const waitTime = Number(resetsAt) * 1000 - Date.now()\n if (waitTime > 0) return waitTime\n }\n}\n"]}