@atproto/lex-client 0.0.10 → 0.0.12

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 (48) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/agent.d.ts +72 -0
  3. package/dist/agent.d.ts.map +1 -1
  4. package/dist/agent.js +46 -1
  5. package/dist/agent.js.map +1 -1
  6. package/dist/client.d.ts +442 -46
  7. package/dist/client.d.ts.map +1 -1
  8. package/dist/client.js +145 -1
  9. package/dist/client.js.map +1 -1
  10. package/dist/errors.d.ts +202 -48
  11. package/dist/errors.d.ts.map +1 -1
  12. package/dist/errors.js +208 -65
  13. package/dist/errors.js.map +1 -1
  14. package/dist/lexicons/com/atproto/repo/createRecord.defs.d.ts +20 -20
  15. package/dist/lexicons/com/atproto/repo/deleteRecord.defs.d.ts +12 -12
  16. package/dist/lexicons/com/atproto/repo/getRecord.defs.d.ts +6 -6
  17. package/dist/lexicons/com/atproto/repo/listRecords.defs.d.ts +6 -6
  18. package/dist/lexicons/com/atproto/repo/putRecord.defs.d.ts +22 -22
  19. package/dist/lexicons/com/atproto/repo/uploadBlob.defs.d.ts +2 -2
  20. package/dist/response.d.ts +17 -6
  21. package/dist/response.d.ts.map +1 -1
  22. package/dist/response.js +45 -32
  23. package/dist/response.js.map +1 -1
  24. package/dist/types.d.ts +51 -0
  25. package/dist/types.d.ts.map +1 -1
  26. package/dist/types.js.map +1 -1
  27. package/dist/util.d.ts +40 -5
  28. package/dist/util.d.ts.map +1 -1
  29. package/dist/util.js +22 -0
  30. package/dist/util.js.map +1 -1
  31. package/dist/www-authenticate.d.ts +35 -0
  32. package/dist/www-authenticate.d.ts.map +1 -0
  33. package/dist/www-authenticate.js +57 -0
  34. package/dist/www-authenticate.js.map +1 -0
  35. package/dist/xrpc.d.ts +82 -10
  36. package/dist/xrpc.d.ts.map +1 -1
  37. package/dist/xrpc.js +15 -28
  38. package/dist/xrpc.js.map +1 -1
  39. package/package.json +7 -7
  40. package/src/agent.ts +101 -1
  41. package/src/client.ts +428 -15
  42. package/src/errors.ts +308 -120
  43. package/src/response.ts +68 -63
  44. package/src/types.ts +52 -0
  45. package/src/util.ts +50 -5
  46. package/src/www-authenticate.test.ts +227 -0
  47. package/src/www-authenticate.ts +101 -0
  48. package/src/xrpc.ts +100 -53
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # @atproto/lex-client
2
2
 
3
+ ## 0.0.12
4
+
5
+ ### Patch Changes
6
+
7
+ - [#4601](https://github.com/bluesky-social/atproto/pull/4601) [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add missing exports
8
+
9
+ - [#4601](https://github.com/bluesky-social/atproto/pull/4601) [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Fix `exports` field in package.json
10
+
11
+ - [#4601](https://github.com/bluesky-social/atproto/pull/4601) [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add JSDoc
12
+
13
+ - [#4601](https://github.com/bluesky-social/atproto/pull/4601) [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add JSDoc to `Client` class properties and methods
14
+
15
+ - Updated dependencies [[`7b9a98a`](https://github.com/bluesky-social/atproto/commit/7b9a98a763636c5f66a06da11fe6013f29dd9157), [`7b9a98a`](https://github.com/bluesky-social/atproto/commit/7b9a98a763636c5f66a06da11fe6013f29dd9157), [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015), [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015), [`7b9a98a`](https://github.com/bluesky-social/atproto/commit/7b9a98a763636c5f66a06da11fe6013f29dd9157), [`7b9a98a`](https://github.com/bluesky-social/atproto/commit/7b9a98a763636c5f66a06da11fe6013f29dd9157), [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015)]:
16
+ - @atproto/lex-schema@0.0.12
17
+ - @atproto/lex-json@0.0.11
18
+ - @atproto/lex-data@0.0.11
19
+
20
+ ## 0.0.11
21
+
22
+ ### Patch Changes
23
+
24
+ - [#4589](https://github.com/bluesky-social/atproto/pull/4589) [`369bb02`](https://github.com/bluesky-social/atproto/commit/369bb02b9f80f0e15e5242e54f09bd4e01117f3a) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add ability to set default `headers` when creating XRPC agent
25
+
26
+ - [#4589](https://github.com/bluesky-social/atproto/pull/4589) [`369bb02`](https://github.com/bluesky-social/atproto/commit/369bb02b9f80f0e15e5242e54f09bd4e01117f3a) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Improve typing of error responses
27
+
28
+ - [#4589](https://github.com/bluesky-social/atproto/pull/4589) [`369bb02`](https://github.com/bluesky-social/atproto/commit/369bb02b9f80f0e15e5242e54f09bd4e01117f3a) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Allow omitting `rkey` for record definition usin `any`as record key
29
+
30
+ - Updated dependencies [[`369bb02`](https://github.com/bluesky-social/atproto/commit/369bb02b9f80f0e15e5242e54f09bd4e01117f3a)]:
31
+ - @atproto/lex-data@0.0.10
32
+ - @atproto/lex-json@0.0.10
33
+ - @atproto/lex-schema@0.0.11
34
+
3
35
  ## 0.0.10
4
36
 
5
37
  ### Patch Changes
package/dist/agent.d.ts CHANGED
@@ -1,4 +1,16 @@
1
1
  import { DidString } from '@atproto/lex-schema';
2
+ /**
3
+ * A function that performs HTTP requests towards a service endpoint.
4
+ *
5
+ * The handler is responsible for adding the origin (protocol, hostname, and
6
+ * port) to the provided path, typically based on authentication or service
7
+ * configuration. The handler are also responsible for adding any necessary
8
+ * headers, such as authorization tokens.
9
+ *
10
+ * @param path - The URL path (pathname + query parameters) without the origin
11
+ * @param init - Standard fetch RequestInit options
12
+ * @returns A Promise resolving to the HTTP Response
13
+ */
2
14
  export type FetchHandler = (
3
15
  /**
4
16
  * The URL (pathname + query parameters) to make the request to, without the
@@ -6,8 +18,27 @@ export type FetchHandler = (
6
18
  * {@link FetchHandler}, typically based on authentication or other factors.
7
19
  */
8
20
  path: string, init: RequestInit) => Promise<Response>;
21
+ /**
22
+ * Core interface for making XRPC requests.
23
+ *
24
+ * An Agent encapsulates an identity and request handling for AT Protocol
25
+ * operations. It can represent an authenticated user session or an
26
+ * unauthenticated service client.
27
+ *
28
+ * @see {@link buildAgent} for creating (simple) Agent instances.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const agent: Agent = {
33
+ * did: 'did:plc:example123',
34
+ * fetchHandler: (path, init) => fetch(new URL(path, 'https://bsky.social'), init)
35
+ * }
36
+ * ```
37
+ */
9
38
  export interface Agent {
39
+ /** The DID of the authenticated user, or `undefined` if unauthenticated. */
10
40
  readonly did?: DidString;
41
+ /** The fetch handler used to make HTTP requests. */
11
42
  fetchHandler: FetchHandler;
12
43
  }
13
44
  export type AgentConfig = {
@@ -21,6 +52,11 @@ export type AgentConfig = {
21
52
  * such as a service URL that changes based on authentication.
22
53
  */
23
54
  service: string | URL;
55
+ /**
56
+ * Optional headers to include with every request made by this agent, unless
57
+ * overridden by the request-specific headers provided to the fetch handler.
58
+ */
59
+ headers?: HeadersInit;
24
60
  /**
25
61
  * Bring your own fetch implementation. Typically useful for testing, logging,
26
62
  * mocking, or adding retries, session management, signatures, proof of
@@ -29,6 +65,42 @@ export type AgentConfig = {
29
65
  */
30
66
  fetch?: typeof globalThis.fetch;
31
67
  };
68
+ /**
69
+ * Options for creating an Agent.
70
+ *
71
+ * Can be a full {@link AgentConfig} object, or a simple service URL string/{@link URL}.
72
+ */
32
73
  export type AgentOptions = AgentConfig | string | URL;
74
+ /**
75
+ * Creates an {@link Agent} from various input types.
76
+ *
77
+ * This factory function accepts an existing Agent (returned as-is), a service URL,
78
+ * or a full configuration object. It handles the common case of creating an
79
+ * unauthenticated agent from just a service URL.
80
+ *
81
+ * @param options - Agent instance, configuration object, or service URL
82
+ * @returns A configured Agent ready for making requests
83
+ * @throws {TypeError} If fetch() is not available in the environment
84
+ *
85
+ * @example From URL string
86
+ * ```typescript
87
+ * const agent = buildAgent('https://public.api.bsky.app')
88
+ * ```
89
+ *
90
+ * @example From configuration
91
+ * ```typescript
92
+ * const agent = buildAgent({
93
+ * did: 'did:plc:example',
94
+ * service: 'https://bsky.social',
95
+ * headers: { 'Authorization': 'Bearer ...' }
96
+ * })
97
+ * ```
98
+ *
99
+ * @example Pass-through existing agent
100
+ * ```typescript
101
+ * const existing: Agent = { ... }
102
+ * const agent = buildAgent(existing) // Returns existing unchanged
103
+ * ```
104
+ */
33
105
  export declare function buildAgent(options: Agent | AgentOptions): Agent;
34
106
  //# sourceMappingURL=agent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C,MAAM,MAAM,YAAY,GAAG;AACzB;;;;GAIG;AACH,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,WAAW,KACd,OAAO,CAAC,QAAQ,CAAC,CAAA;AAEtB,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAA;IACxB,YAAY,EAAE,YAAY,CAAA;CAC3B;AAED,MAAM,MAAM,WAAW,GAAG;IACxB;;OAEG;IACH,GAAG,CAAC,EAAE,SAAS,CAAA;IAEf;;;;OAIG;IACH,OAAO,EAAE,MAAM,GAAG,GAAG,CAAA;IAErB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,MAAM,GAAG,GAAG,CAAA;AAErD,wBAAgB,UAAU,CAAC,OAAO,EAAE,KAAK,GAAG,YAAY,GAAG,KAAK,CAyB/D"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GAAG;AACzB;;;;GAIG;AACH,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,WAAW,KACd,OAAO,CAAC,QAAQ,CAAC,CAAA;AAEtB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,KAAK;IACpB,4EAA4E;IAC5E,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAA;IACxB,oDAAoD;IACpD,YAAY,EAAE,YAAY,CAAA;CAC3B;AAED,MAAM,MAAM,WAAW,GAAG;IACxB;;OAEG;IACH,GAAG,CAAC,EAAE,SAAS,CAAA;IAEf;;;;OAIG;IACH,OAAO,EAAE,MAAM,GAAG,GAAG,CAAA;IAErB;;;OAGG;IACH,OAAO,CAAC,EAAE,WAAW,CAAA;IAErB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CAChC,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,MAAM,GAAG,GAAG,CAAA;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,KAAK,GAAG,YAAY,GAAG,KAAK,CAiC/D"}
package/dist/agent.js CHANGED
@@ -1,6 +1,37 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildAgent = buildAgent;
4
+ /**
5
+ * Creates an {@link Agent} from various input types.
6
+ *
7
+ * This factory function accepts an existing Agent (returned as-is), a service URL,
8
+ * or a full configuration object. It handles the common case of creating an
9
+ * unauthenticated agent from just a service URL.
10
+ *
11
+ * @param options - Agent instance, configuration object, or service URL
12
+ * @returns A configured Agent ready for making requests
13
+ * @throws {TypeError} If fetch() is not available in the environment
14
+ *
15
+ * @example From URL string
16
+ * ```typescript
17
+ * const agent = buildAgent('https://public.api.bsky.app')
18
+ * ```
19
+ *
20
+ * @example From configuration
21
+ * ```typescript
22
+ * const agent = buildAgent({
23
+ * did: 'did:plc:example',
24
+ * service: 'https://bsky.social',
25
+ * headers: { 'Authorization': 'Bearer ...' }
26
+ * })
27
+ * ```
28
+ *
29
+ * @example Pass-through existing agent
30
+ * ```typescript
31
+ * const existing: Agent = { ... }
32
+ * const agent = buildAgent(existing) // Returns existing unchanged
33
+ * ```
34
+ */
4
35
  function buildAgent(options) {
5
36
  if (typeof options === 'object' && 'fetchHandler' in options) {
6
37
  return options;
@@ -17,8 +48,22 @@ function buildAgent(options) {
17
48
  return config.did;
18
49
  },
19
50
  async fetchHandler(path, init) {
20
- return fetch(new URL(path, service), init);
51
+ const headers = config.headers != null && init.headers != null
52
+ ? mergeHeaders(config.headers, init.headers)
53
+ : config.headers || init.headers;
54
+ return fetch(new URL(path, service), headers !== init.headers ? { ...init, headers } : init);
21
55
  },
22
56
  };
23
57
  }
58
+ function mergeHeaders(defaultHeaders, requestHeaders) {
59
+ // We don't want to alter the original Headers objects, so we create a new one
60
+ const result = new Headers(defaultHeaders);
61
+ const overrides = requestHeaders instanceof Headers
62
+ ? requestHeaders
63
+ : new Headers(requestHeaders);
64
+ for (const [key, value] of overrides.entries()) {
65
+ result.set(key, value);
66
+ }
67
+ return result;
68
+ }
24
69
  //# sourceMappingURL=agent.js.map
package/dist/agent.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":";;AAyCA,gCAyBC;AAzBD,SAAgB,UAAU,CAAC,OAA6B;IACtD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,cAAc,IAAI,OAAO,EAAE,CAAC;QAC7D,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,MAAM,MAAM,GACV,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,YAAY,GAAG;QACnD,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE;QACtC,CAAC,CAAC,OAAO,CAAA;IAEb,MAAM,EAAE,OAAO,EAAE,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,GAAG,MAAM,CAAA;IAEpD,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,MAAM,IAAI,SAAS,CAAC,8CAA8C,CAAC,CAAA;IACrE,CAAC;IAED,OAAO;QACL,IAAI,GAAG;YACL,OAAO,MAAM,CAAC,GAAG,CAAA;QACnB,CAAC;QAED,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI;YAC3B,OAAO,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,CAAA;QAC5C,CAAC;KACF,CAAA;AACH,CAAC","sourcesContent":["import { DidString } from '@atproto/lex-schema'\n\nexport type FetchHandler = (\n /**\n * The URL (pathname + query parameters) to make the request to, without the\n * origin. The origin (protocol, hostname, and port) must be added by this\n * {@link FetchHandler}, typically based on authentication or other factors.\n */\n path: string,\n init: RequestInit,\n) => Promise<Response>\n\nexport interface Agent {\n readonly did?: DidString\n fetchHandler: FetchHandler\n}\n\nexport type AgentConfig = {\n /**\n * The identifier (DID) of the user represented by this agent.\n */\n did?: DidString\n\n /**\n * The service URL to make requests to. This can be a string, URL, or a\n * function that returns a string or URL. This is useful for dynamic URLs,\n * such as a service URL that changes based on authentication.\n */\n service: string | URL\n\n /**\n * Bring your own fetch implementation. Typically useful for testing, logging,\n * mocking, or adding retries, session management, signatures, proof of\n * possession (DPoP), SSRF protection, etc. Defaults to the global `fetch`\n * function.\n */\n fetch?: typeof globalThis.fetch\n}\n\nexport type AgentOptions = AgentConfig | string | URL\n\nexport function buildAgent(options: Agent | AgentOptions): Agent {\n if (typeof options === 'object' && 'fetchHandler' in options) {\n return options\n }\n\n const config: Agent | AgentConfig =\n typeof options === 'string' || options instanceof URL\n ? { did: undefined, service: options }\n : options\n\n const { service, fetch = globalThis.fetch } = config\n\n if (typeof fetch !== 'function') {\n throw new TypeError('fetch() is not available in this environment')\n }\n\n return {\n get did() {\n return config.did\n },\n\n async fetchHandler(path, init) {\n return fetch(new URL(path, service), init)\n },\n }\n}\n"]}
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":";;AAkHA,gCAiCC;AAhED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,SAAgB,UAAU,CAAC,OAA6B;IACtD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,cAAc,IAAI,OAAO,EAAE,CAAC;QAC7D,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,MAAM,MAAM,GACV,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,YAAY,GAAG;QACnD,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE;QACtC,CAAC,CAAC,OAAO,CAAA;IAEb,MAAM,EAAE,OAAO,EAAE,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,GAAG,MAAM,CAAA;IAEpD,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,MAAM,IAAI,SAAS,CAAC,8CAA8C,CAAC,CAAA;IACrE,CAAC;IAED,OAAO;QACL,IAAI,GAAG;YACL,OAAO,MAAM,CAAC,GAAG,CAAA;QACnB,CAAC;QAED,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI;YAC3B,MAAM,OAAO,GACX,MAAM,CAAC,OAAO,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI;gBAC5C,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC;gBAC5C,CAAC,CAAC,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAA;YAEpC,OAAO,KAAK,CACV,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,EACtB,OAAO,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CACvD,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CACnB,cAA2B,EAC3B,cAA2B;IAE3B,8EAA8E;IAC9E,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC,cAAc,CAAC,CAAA;IAE1C,MAAM,SAAS,GACb,cAAc,YAAY,OAAO;QAC/B,CAAC,CAAC,cAAc;QAChB,CAAC,CAAC,IAAI,OAAO,CAAC,cAAc,CAAC,CAAA;IAEjC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/C,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACxB,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC","sourcesContent":["import { DidString } from '@atproto/lex-schema'\n\n/**\n * A function that performs HTTP requests towards a service endpoint.\n *\n * The handler is responsible for adding the origin (protocol, hostname, and\n * port) to the provided path, typically based on authentication or service\n * configuration. The handler are also responsible for adding any necessary\n * headers, such as authorization tokens.\n *\n * @param path - The URL path (pathname + query parameters) without the origin\n * @param init - Standard fetch RequestInit options\n * @returns A Promise resolving to the HTTP Response\n */\nexport type FetchHandler = (\n /**\n * The URL (pathname + query parameters) to make the request to, without the\n * origin. The origin (protocol, hostname, and port) must be added by this\n * {@link FetchHandler}, typically based on authentication or other factors.\n */\n path: string,\n init: RequestInit,\n) => Promise<Response>\n\n/**\n * Core interface for making XRPC requests.\n *\n * An Agent encapsulates an identity and request handling for AT Protocol\n * operations. It can represent an authenticated user session or an\n * unauthenticated service client.\n *\n * @see {@link buildAgent} for creating (simple) Agent instances.\n *\n * @example\n * ```typescript\n * const agent: Agent = {\n * did: 'did:plc:example123',\n * fetchHandler: (path, init) => fetch(new URL(path, 'https://bsky.social'), init)\n * }\n * ```\n */\nexport interface Agent {\n /** The DID of the authenticated user, or `undefined` if unauthenticated. */\n readonly did?: DidString\n /** The fetch handler used to make HTTP requests. */\n fetchHandler: FetchHandler\n}\n\nexport type AgentConfig = {\n /**\n * The identifier (DID) of the user represented by this agent.\n */\n did?: DidString\n\n /**\n * The service URL to make requests to. This can be a string, URL, or a\n * function that returns a string or URL. This is useful for dynamic URLs,\n * such as a service URL that changes based on authentication.\n */\n service: string | URL\n\n /**\n * Optional headers to include with every request made by this agent, unless\n * overridden by the request-specific headers provided to the fetch handler.\n */\n headers?: HeadersInit\n\n /**\n * Bring your own fetch implementation. Typically useful for testing, logging,\n * mocking, or adding retries, session management, signatures, proof of\n * possession (DPoP), SSRF protection, etc. Defaults to the global `fetch`\n * function.\n */\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Options for creating an Agent.\n *\n * Can be a full {@link AgentConfig} object, or a simple service URL string/{@link URL}.\n */\nexport type AgentOptions = AgentConfig | string | URL\n\n/**\n * Creates an {@link Agent} from various input types.\n *\n * This factory function accepts an existing Agent (returned as-is), a service URL,\n * or a full configuration object. It handles the common case of creating an\n * unauthenticated agent from just a service URL.\n *\n * @param options - Agent instance, configuration object, or service URL\n * @returns A configured Agent ready for making requests\n * @throws {TypeError} If fetch() is not available in the environment\n *\n * @example From URL string\n * ```typescript\n * const agent = buildAgent('https://public.api.bsky.app')\n * ```\n *\n * @example From configuration\n * ```typescript\n * const agent = buildAgent({\n * did: 'did:plc:example',\n * service: 'https://bsky.social',\n * headers: { 'Authorization': 'Bearer ...' }\n * })\n * ```\n *\n * @example Pass-through existing agent\n * ```typescript\n * const existing: Agent = { ... }\n * const agent = buildAgent(existing) // Returns existing unchanged\n * ```\n */\nexport function buildAgent(options: Agent | AgentOptions): Agent {\n if (typeof options === 'object' && 'fetchHandler' in options) {\n return options\n }\n\n const config: Agent | AgentConfig =\n typeof options === 'string' || options instanceof URL\n ? { did: undefined, service: options }\n : options\n\n const { service, fetch = globalThis.fetch } = config\n\n if (typeof fetch !== 'function') {\n throw new TypeError('fetch() is not available in this environment')\n }\n\n return {\n get did() {\n return config.did\n },\n\n async fetchHandler(path, init) {\n const headers =\n config.headers != null && init.headers != null\n ? mergeHeaders(config.headers, init.headers)\n : config.headers || init.headers\n\n return fetch(\n new URL(path, service),\n headers !== init.headers ? { ...init, headers } : init,\n )\n },\n }\n}\n\nfunction mergeHeaders(\n defaultHeaders: HeadersInit,\n requestHeaders: HeadersInit,\n): Headers {\n // We don't want to alter the original Headers objects, so we create a new one\n const result = new Headers(defaultHeaders)\n\n const overrides =\n requestHeaders instanceof Headers\n ? requestHeaders\n : new Headers(requestHeaders)\n\n for (const [key, value] of overrides.entries()) {\n result.set(key, value)\n }\n\n return result\n}\n"]}