@atcute/client 3.1.0 → 4.0.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.
package/lib/rpc.ts DELETED
@@ -1,298 +0,0 @@
1
- import type { At, Procedures, Queries } from './lexicons.js';
2
-
3
- import { buildFetchHandler, type FetchHandler, type FetchHandlerObject } from './fetch-handler.js';
4
- import { mergeHeaders } from './utils/http.js';
5
-
6
- /**
7
- * @deprecated
8
- */
9
- export type HeadersObject = Record<string, string>;
10
-
11
- /**
12
- * Response from XRPC service
13
- * @deprecated
14
- */
15
- export interface XRPCResponse<T = any> {
16
- data: T;
17
- headers: HeadersObject;
18
- }
19
-
20
- /**
21
- * Options for constructing an XRPC error
22
- * @deprecated
23
- */
24
- export interface XRPCErrorOptions {
25
- kind?: string;
26
- description?: string;
27
- headers?: HeadersObject;
28
- cause?: unknown;
29
- }
30
-
31
- /**
32
- * Error coming from the XRPC service
33
- * @deprecated
34
- */
35
- export class XRPCError extends Error {
36
- override name = 'XRPCError';
37
-
38
- /** Response status */
39
- status: number;
40
- /** Response headers */
41
- headers: HeadersObject;
42
- /** Error kind */
43
- kind?: string;
44
- /** Error description */
45
- description?: string;
46
-
47
- constructor(
48
- status: number,
49
- {
50
- kind = `HTTP error ${status}`,
51
- description = `Unspecified error description`,
52
- headers,
53
- cause,
54
- }: XRPCErrorOptions = {},
55
- ) {
56
- super(`${kind} > ${description}`, { cause });
57
-
58
- this.status = status;
59
- this.kind = kind;
60
- this.description = description;
61
- this.headers = headers || {};
62
- }
63
- }
64
-
65
- /**
66
- * Service proxy options
67
- * @deprecated
68
- */
69
- export interface XRPCProxyOptions {
70
- type: 'atproto_pds' | 'atproto_labeler' | 'bsky_fg' | 'bsky_notif' | ({} & string);
71
- service: At.Did;
72
- }
73
-
74
- /**
75
- * Options for constructing an XRPC
76
- * @deprecated
77
- */
78
- export interface XRPCOptions {
79
- handler: FetchHandler | FetchHandlerObject;
80
- proxy?: XRPCProxyOptions;
81
- }
82
-
83
- /**
84
- * XRPC request options
85
- * @deprecated
86
- */
87
- export interface XRPCRequestOptions {
88
- type: 'get' | 'post';
89
- nsid: string;
90
- headers?: HeadersInit;
91
- params?: Record<string, unknown>;
92
- data?: FormData | Blob | ArrayBufferView | Record<string, unknown>;
93
- signal?: AbortSignal;
94
- }
95
-
96
- /**
97
- * XRPC response
98
- * @deprecated
99
- */
100
- export interface XRPCResponse<T = any> {
101
- data: T;
102
- headers: HeadersObject;
103
- }
104
-
105
- /** Base options for the query/procedure request */
106
- interface BaseRPCOptions {
107
- /** Request headers to make */
108
- headers?: HeadersInit;
109
- /** Signal for aborting the request */
110
- signal?: AbortSignal;
111
- }
112
-
113
- /**
114
- * Options for the query/procedure request
115
- * @deprecated
116
- */
117
- export type RPCOptions<T> = BaseRPCOptions &
118
- (T extends { params: any } ? { params: T['params'] } : {}) &
119
- (T extends { input: any } ? { data: T['input'] } : {});
120
-
121
- type OutputOf<T> = T extends { output: any } ? T['output'] : never;
122
-
123
- /**
124
- * @deprecated
125
- */
126
- export class XRPC {
127
- handle: FetchHandler;
128
- proxy: XRPCProxyOptions | undefined;
129
-
130
- constructor({ handler, proxy }: XRPCOptions) {
131
- this.handle = buildFetchHandler(handler);
132
- this.proxy = proxy;
133
- }
134
-
135
- /**
136
- * Makes a query (GET) request
137
- * @param nsid Namespace ID of a query endpoint
138
- * @param options Options to include like parameters
139
- * @returns The response of the request
140
- */
141
- get<K extends keyof Queries>(
142
- nsid: K,
143
- options: RPCOptions<Queries[K]>,
144
- ): Promise<XRPCResponse<OutputOf<Queries[K]>>> {
145
- return this.request({ type: 'get', nsid: nsid, ...(options as any) });
146
- }
147
-
148
- /**
149
- * Makes a procedure (POST) request
150
- * @param nsid Namespace ID of a procedure endpoint
151
- * @param options Options to include like input body or parameters
152
- * @returns The response of the request
153
- */
154
- call<K extends keyof Procedures>(
155
- nsid: K,
156
- options: RPCOptions<Procedures[K]>,
157
- ): Promise<XRPCResponse<OutputOf<Procedures[K]>>> {
158
- return this.request({ type: 'post', nsid: nsid, ...(options as any) });
159
- }
160
-
161
- /** Makes a request to the XRPC service */
162
- async request(options: XRPCRequestOptions): Promise<XRPCResponse> {
163
- const data = options.data;
164
-
165
- const url = `/xrpc/${options.nsid}` + constructSearchParams(options.params);
166
- const isInputJson = isJsonValue(data);
167
-
168
- const response = await this.handle(url, {
169
- method: options.type,
170
- signal: options.signal,
171
- body: isInputJson ? JSON.stringify(data) : data,
172
- headers: mergeHeaders(options.headers, {
173
- 'content-type': isInputJson ? 'application/json' : null,
174
- 'atproto-proxy': constructProxyHeader(this.proxy),
175
- }),
176
- });
177
-
178
- const responseStatus = response.status;
179
- const responseHeaders = Object.fromEntries(response.headers);
180
- const responseType = responseHeaders['content-type'];
181
-
182
- let promise: Promise<unknown> | undefined;
183
- let ret: unknown;
184
-
185
- if (responseType) {
186
- if (responseType.startsWith('application/json')) {
187
- promise = response.json();
188
- } else if (responseType.startsWith('text/')) {
189
- promise = response.text();
190
- }
191
- }
192
-
193
- try {
194
- ret = await (promise || response.arrayBuffer().then((buffer) => new Uint8Array(buffer)));
195
- } catch (err) {
196
- throw new XRPCError(2, {
197
- cause: err,
198
- kind: 'InvalidResponse',
199
- description: `Failed to parse response body`,
200
- headers: responseHeaders,
201
- });
202
- }
203
-
204
- if (responseStatus === 200) {
205
- return {
206
- data: ret,
207
- headers: responseHeaders,
208
- };
209
- }
210
-
211
- if (isErrorResponse(ret)) {
212
- throw new XRPCError(responseStatus, {
213
- kind: ret.error,
214
- description: ret.message,
215
- headers: responseHeaders,
216
- });
217
- }
218
-
219
- throw new XRPCError(responseStatus, { headers: responseHeaders });
220
- }
221
- }
222
-
223
- const constructProxyHeader = (proxy: XRPCProxyOptions | undefined): string | null => {
224
- if (proxy) {
225
- return `${proxy.service}#${proxy.type}`;
226
- }
227
-
228
- return null;
229
- };
230
-
231
- const constructSearchParams = (params: Record<string, unknown> | undefined): string => {
232
- let searchParams: URLSearchParams | undefined;
233
-
234
- for (const key in params) {
235
- const value = params[key];
236
-
237
- if (value !== undefined) {
238
- searchParams ??= new URLSearchParams();
239
-
240
- if (Array.isArray(value)) {
241
- for (let idx = 0, len = value.length; idx < len; idx++) {
242
- const val = value[idx];
243
- searchParams.append(key, '' + val);
244
- }
245
- } else {
246
- searchParams.set(key, '' + value);
247
- }
248
- }
249
- }
250
-
251
- return searchParams ? `?` + searchParams.toString() : '';
252
- };
253
-
254
- const isJsonValue = (o: unknown): o is Record<string, unknown> => {
255
- if (typeof o !== 'object' || o === null) {
256
- return false;
257
- }
258
-
259
- if ('toJSON' in o) {
260
- return true;
261
- }
262
-
263
- const proto = Object.getPrototypeOf(o);
264
- return proto === null || proto === Object.prototype;
265
- };
266
-
267
- const isErrorResponse = (value: any): value is ErrorResponseBody => {
268
- if (typeof value !== 'object' || value === null) {
269
- return false;
270
- }
271
-
272
- const kindType = typeof value.error;
273
- const messageType = typeof value.message;
274
-
275
- return (
276
- (kindType === 'undefined' || kindType === 'string') &&
277
- (messageType === 'undefined' || messageType === 'string')
278
- );
279
- };
280
-
281
- interface ErrorResponseBody {
282
- error?: string;
283
- message?: string;
284
- }
285
-
286
- /**
287
- * @deprecated
288
- */
289
- export const clone = (rpc: XRPC): XRPC => {
290
- return new XRPC({ handler: rpc.handle, proxy: rpc.proxy });
291
- };
292
-
293
- /**
294
- * @deprecated
295
- */
296
- export const withProxy = (rpc: XRPC, options: XRPCProxyOptions) => {
297
- return new XRPC({ handler: rpc.handle, proxy: options });
298
- };
package/lib/utils/did.ts DELETED
@@ -1,73 +0,0 @@
1
- /**
2
- * @module
3
- * DID document-related functionalities.
4
- * This module is exported for convenience and is no way part of public API,
5
- * it can be removed at any time.
6
- */
7
-
8
- /**
9
- * Retrieves AT Protocol PDS endpoint from the DID document, if available
10
- * @param doc DID document
11
- * @returns The PDS endpoint, if available
12
- */
13
- export const getPdsEndpoint = (doc: DidDocument): string | undefined => {
14
- return getServiceEndpoint(doc, '#atproto_pds', 'AtprotoPersonalDataServer');
15
- };
16
-
17
- /**
18
- * Retrieve a service endpoint from the DID document, if available
19
- * @param doc DID document
20
- * @param serviceId Service ID
21
- * @param serviceType Service type
22
- * @returns The requested service endpoint, if available
23
- */
24
- export const getServiceEndpoint = (
25
- doc: DidDocument,
26
- serviceId: string,
27
- serviceType: string,
28
- ): string | undefined => {
29
- const did = doc.id;
30
-
31
- const didServiceId = did + serviceId;
32
- const found = doc.service?.find((service) => service.id === serviceId || service.id === didServiceId);
33
-
34
- if (!found || found.type !== serviceType || typeof found.serviceEndpoint !== 'string') {
35
- return undefined;
36
- }
37
-
38
- return validateUrl(found.serviceEndpoint);
39
- };
40
-
41
- const validateUrl = (urlStr: string): string | undefined => {
42
- let url;
43
- try {
44
- url = new URL(urlStr);
45
- } catch {
46
- return undefined;
47
- }
48
-
49
- const proto = url.protocol;
50
-
51
- if (url.hostname && (proto === 'http:' || proto === 'https:')) {
52
- return urlStr;
53
- }
54
- };
55
-
56
- /**
57
- * DID document
58
- */
59
- export interface DidDocument {
60
- id: string;
61
- alsoKnownAs?: string[];
62
- verificationMethod?: Array<{
63
- id: string;
64
- type: string;
65
- controller: string;
66
- publicKeyMultibase?: string;
67
- }>;
68
- service?: Array<{
69
- id: string;
70
- type: string;
71
- serviceEndpoint: string | Record<string, unknown>;
72
- }>;
73
- }
package/lib/utils/http.ts DELETED
@@ -1,27 +0,0 @@
1
- /**
2
- * @module
3
- * Assortment of HTTP utilities
4
- * This module is exported for convenience and is no way part of public API,
5
- * it can be removed at any time.
6
- */
7
-
8
- export const mergeHeaders = (
9
- init: HeadersInit | undefined,
10
- defaults: Record<string, string | null>,
11
- ): HeadersInit | undefined => {
12
- let headers: Headers | undefined;
13
-
14
- for (const name in defaults) {
15
- const value = defaults[name];
16
-
17
- if (value !== null) {
18
- headers ??= new Headers(init);
19
-
20
- if (!headers.has(name)) {
21
- headers.set(name, value);
22
- }
23
- }
24
- }
25
-
26
- return headers ?? init;
27
- };