@atcute/client 2.0.3 → 2.0.5

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/README.md CHANGED
@@ -2,11 +2,9 @@
2
2
 
3
3
  lightweight and cute API client for AT Protocol.
4
4
 
5
- - Small, the bare minimum is ~1 kB gzipped with the full package at ~2.4 kB gzipped.
6
- - No validations, type definitions match actual HTTP responses.
7
-
8
- This package only contains the base AT Protocol lexicons and endpoints, along with an authentication middleware.
9
- For Bluesky-related lexicons, see `@atcute/bluesky` package.
5
+ - **small**, the bare minimum is ~1 kB gzipped with the full package at ~2.4 kB gzipped.
6
+ - **no runtime validation**, type definitions match actual HTTP responses, the server is assumed to
7
+ be trusted in returning valid responses.
10
8
 
11
9
  ```ts
12
10
  import { XRPC, CredentialManager } from '@atcute/client';
@@ -28,3 +26,12 @@ const { data } = await rpc.get('com.atproto.identity.resolveHandle', {
28
26
  console.log(data.did);
29
27
  // -> did:plc:ragtjsm2j2vknwkz3zp4oxrd
30
28
  ```
29
+
30
+ by default, the API client only ships with the base AT Protocol (`com.atproto.*`) lexicons and
31
+ endpoints , along with a middleware for doing a (legacy) authentication with a PDS. you can extend
32
+ these with optional definition packages:
33
+
34
+ - [`@atcute/bluemoji`](../../definitions/bluemoji): adds `blue.moji.*` definitions
35
+ - [`@atcute/bluesky`](../../definitions/bluesky): adds `app.bsky.*` and `chat.bsky.*` definitions
36
+ - [`@atcute/ozone`](../../definitions/ozone): adds `tools.ozone.*` definitions
37
+ - [`@atcute/whitewind`](../../definitions/whitewind): adds `com.whtwnd.*` definitions
@@ -627,6 +627,9 @@ export declare namespace ComAtprotoRepoGetRecord {
627
627
  value: unknown;
628
628
  cid?: At.CID;
629
629
  }
630
+ interface Errors {
631
+ RecordNotFound: {};
632
+ }
630
633
  }
631
634
  /** Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set. */
632
635
  export declare namespace ComAtprotoRepoImportRepo {
package/dist/rpc.d.ts CHANGED
@@ -24,7 +24,7 @@ export declare class XRPCError extends Error {
24
24
  kind?: string;
25
25
  /** Error description */
26
26
  description?: string;
27
- constructor(status: number, { kind, description, headers, cause }?: XRPCErrorOptions);
27
+ constructor(status: number, { kind, description, headers, cause, }?: XRPCErrorOptions);
28
28
  }
29
29
  /** Service proxy options */
30
30
  export interface XRPCProxyOptions {
package/dist/rpc.js CHANGED
@@ -2,8 +2,8 @@ import { buildFetchHandler } from './fetch-handler.js';
2
2
  import { mergeHeaders } from './utils/http.js';
3
3
  /** Error coming from the XRPC service */
4
4
  export class XRPCError extends Error {
5
- constructor(status, { kind, description, headers, cause } = {}) {
6
- super(`${kind || 'UnspecifiedKind'} > ${description || `Unspecified error description`}`, { cause });
5
+ constructor(status, { kind = `HTTP error ${status}`, description = `Unspecified error description`, headers, cause, } = {}) {
6
+ super(`${kind} > ${description}`, { cause });
7
7
  this.name = 'XRPCError';
8
8
  this.status = status;
9
9
  this.kind = kind;
package/dist/rpc.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"rpc.js","sourceRoot":"","sources":["../lib/rpc.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rpc.js","sourceRoot":"","sources":["../lib/rpc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,312 @@
1
+ import type { At, ComAtprotoServerCreateSession } from './lexicons.js';
2
+
3
+ import { simpleFetchHandler, type FetchHandlerObject } from './fetch-handler.js';
4
+ import { XRPC, XRPCError } from './rpc.js';
5
+
6
+ import { getPdsEndpoint, type DidDocument } from './utils/did.js';
7
+ import { decodeJwt } from './utils/jwt.js';
8
+
9
+ /** Interface for the decoded access token, for convenience */
10
+ export interface AtpAccessJwt {
11
+ /** Access token scope, app password returns a different scope. */
12
+ scope: 'com.atproto.access' | 'com.atproto.appPass' | 'com.atproto.appPassPrivileged';
13
+ /** Account DID */
14
+ sub: At.DID;
15
+ /** Expiration time */
16
+ exp: number;
17
+ /** Creation/issued time */
18
+ iat: number;
19
+ }
20
+
21
+ /** Interface for the decoded refresh token, for convenience */
22
+ export interface AtpRefreshJwt {
23
+ /** Refresh token scope */
24
+ scope: 'com.atproto.refresh';
25
+ /** ID of this refresh token */
26
+ jti: string;
27
+ /** Account DID */
28
+ sub: At.DID;
29
+ /** Intended audience of this refresh token, in DID */
30
+ aud: At.DID;
31
+ /** Expiration time */
32
+ exp: number;
33
+ /** Creation/issued time */
34
+ iat: number;
35
+ }
36
+
37
+ /** Saved session data, this can be reused again for next time. */
38
+ export interface AtpSessionData {
39
+ /** Refresh token */
40
+ refreshJwt: string;
41
+ /** Access token */
42
+ accessJwt: string;
43
+ /** Account handle */
44
+ handle: string;
45
+ /** Account DID */
46
+ did: At.DID;
47
+ /** PDS endpoint found in the DID document, this will be used as the service URI if provided */
48
+ pdsUri?: string;
49
+ /** Email address of the account, might not be available if on app password */
50
+ email?: string;
51
+ /** If the email address has been confirmed or not */
52
+ emailConfirmed?: boolean;
53
+ /** If the account has email-based two-factor authentication enabled */
54
+ emailAuthFactor?: boolean;
55
+ /** Whether the account is active (not deactivated, taken down, or suspended) */
56
+ active: boolean;
57
+ /** Possible reason for why the account is inactive */
58
+ inactiveStatus?: string;
59
+ }
60
+
61
+ export interface CredentialManagerOptions {
62
+ /** PDS server URL */
63
+ service: string;
64
+
65
+ /** Custom fetch function */
66
+ fetch?: typeof globalThis.fetch;
67
+
68
+ /** Function that gets called if the session turned out to have expired during an XRPC request */
69
+ onExpired?: (session: AtpSessionData) => void;
70
+ /** Function that gets called if the session has been refreshed during an XRPC request */
71
+ onRefresh?: (session: AtpSessionData) => void;
72
+ /** Function that gets called if the session object has been refreshed */
73
+ onSessionUpdate?: (session: AtpSessionData) => void;
74
+ }
75
+
76
+ export class CredentialManager implements FetchHandlerObject {
77
+ readonly serviceUrl: string;
78
+ fetch: typeof fetch;
79
+
80
+ #server: XRPC;
81
+ #refreshSessionPromise: Promise<void> | undefined;
82
+
83
+ #onExpired: CredentialManagerOptions['onExpired'];
84
+ #onRefresh: CredentialManagerOptions['onRefresh'];
85
+ #onSessionUpdate: CredentialManagerOptions['onSessionUpdate'];
86
+
87
+ /** Current session state */
88
+ session?: AtpSessionData;
89
+
90
+ constructor({
91
+ service,
92
+ onExpired,
93
+ onRefresh,
94
+ onSessionUpdate,
95
+ fetch: _fetch = fetch,
96
+ }: CredentialManagerOptions) {
97
+ this.serviceUrl = service;
98
+ this.fetch = _fetch;
99
+
100
+ this.#server = new XRPC({ handler: simpleFetchHandler({ service: service, fetch: _fetch }) });
101
+
102
+ this.#onRefresh = onRefresh;
103
+ this.#onExpired = onExpired;
104
+ this.#onSessionUpdate = onSessionUpdate;
105
+ }
106
+
107
+ get dispatchUrl() {
108
+ return this.session?.pdsUri ?? this.serviceUrl;
109
+ }
110
+
111
+ async handle(pathname: string, init: RequestInit): Promise<Response> {
112
+ await this.#refreshSessionPromise;
113
+
114
+ const url = new URL(pathname, this.dispatchUrl);
115
+ const headers = new Headers(init.headers);
116
+
117
+ if (!this.session || headers.has('authorization')) {
118
+ return (0, this.fetch)(url, init);
119
+ }
120
+
121
+ headers.set('authorization', `Bearer ${this.session.accessJwt}`);
122
+
123
+ const initialResponse = await (0, this.fetch)(url, { ...init, headers });
124
+ const isExpired = await isExpiredTokenResponse(initialResponse);
125
+
126
+ if (!isExpired) {
127
+ return initialResponse;
128
+ }
129
+
130
+ try {
131
+ await this.#refreshSession();
132
+ } catch {
133
+ return initialResponse;
134
+ }
135
+
136
+ // Return initial response if:
137
+ // - refreshSession returns expired
138
+ // - Body stream has been consumed
139
+ if (!this.session || init.body instanceof ReadableStream) {
140
+ return initialResponse;
141
+ }
142
+
143
+ headers.set('authorization', `Bearer ${this.session.accessJwt}`);
144
+
145
+ return await (0, this.fetch)(url, { ...init, headers });
146
+ }
147
+
148
+ #refreshSession() {
149
+ return (this.#refreshSessionPromise ||= this.#refreshSessionInner().finally(
150
+ () => (this.#refreshSessionPromise = undefined),
151
+ ));
152
+ }
153
+
154
+ async #refreshSessionInner(): Promise<void> {
155
+ const currentSession = this.session;
156
+
157
+ if (!currentSession) {
158
+ return;
159
+ }
160
+
161
+ try {
162
+ const { data } = await this.#server.call('com.atproto.server.refreshSession', {
163
+ headers: {
164
+ authorization: `Bearer ${currentSession.refreshJwt}`,
165
+ },
166
+ });
167
+
168
+ this.#updateSession({ ...currentSession, ...data });
169
+ this.#onRefresh?.(this.session!);
170
+ } catch (err) {
171
+ if (err instanceof XRPCError) {
172
+ const kind = err.kind;
173
+
174
+ if (kind === 'ExpiredToken' || kind === 'InvalidToken') {
175
+ this.session = undefined;
176
+ this.#onExpired?.(currentSession);
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+ #updateSession(raw: ComAtprotoServerCreateSession.Output): AtpSessionData {
183
+ const didDoc = raw.didDoc as DidDocument | undefined;
184
+
185
+ let pdsUri: string | undefined;
186
+ if (didDoc) {
187
+ pdsUri = getPdsEndpoint(didDoc);
188
+ }
189
+
190
+ const newSession = {
191
+ accessJwt: raw.accessJwt,
192
+ refreshJwt: raw.refreshJwt,
193
+ handle: raw.handle,
194
+ did: raw.did,
195
+ pdsUri: pdsUri,
196
+ email: raw.email,
197
+ emailConfirmed: raw.emailConfirmed,
198
+ emailAuthFactor: raw.emailConfirmed,
199
+ active: raw.active ?? true,
200
+ inactiveStatus: raw.status,
201
+ };
202
+
203
+ this.session = newSession;
204
+ this.#onSessionUpdate?.(newSession);
205
+
206
+ return newSession;
207
+ }
208
+
209
+ /**
210
+ * Resume a saved session
211
+ * @param session Session information, taken from `AtpAuth#session` after login
212
+ */
213
+ async resume(session: AtpSessionData): Promise<AtpSessionData> {
214
+ const now = Date.now() / 1000 + 60 * 5;
215
+
216
+ const refreshToken = decodeJwt(session.refreshJwt) as AtpRefreshJwt;
217
+
218
+ if (now >= refreshToken.exp) {
219
+ throw new XRPCError(401, { kind: 'InvalidToken' });
220
+ }
221
+
222
+ const accessToken = decodeJwt(session.accessJwt) as AtpAccessJwt;
223
+ this.session = session;
224
+
225
+ if (now >= accessToken.exp) {
226
+ await this.#refreshSession();
227
+ } else {
228
+ const promise = this.#server.get('com.atproto.server.getSession', {
229
+ headers: {
230
+ authorization: `Bearer ${session.accessJwt}`,
231
+ },
232
+ });
233
+
234
+ promise.then((response) => {
235
+ const existing = this.session;
236
+ const next = response.data;
237
+
238
+ if (!existing) {
239
+ return;
240
+ }
241
+
242
+ this.#updateSession({ ...existing, ...next });
243
+ });
244
+ }
245
+
246
+ if (!this.session) {
247
+ throw new XRPCError(401, { kind: 'InvalidToken' });
248
+ }
249
+
250
+ return this.session;
251
+ }
252
+
253
+ /**
254
+ * Perform a login operation
255
+ * @param options Login options
256
+ * @returns Session data that can be saved for later
257
+ */
258
+ async login(options: AuthLoginOptions): Promise<AtpSessionData> {
259
+ // Reset the session
260
+ this.session = undefined;
261
+
262
+ const res = await this.#server.call('com.atproto.server.createSession', {
263
+ data: {
264
+ identifier: options.identifier,
265
+ password: options.password,
266
+ authFactorToken: options.code,
267
+ },
268
+ });
269
+
270
+ return this.#updateSession(res.data);
271
+ }
272
+ }
273
+
274
+ /** Login options */
275
+ export interface AuthLoginOptions {
276
+ /** What account to login as, this could be domain handle, DID, or email address */
277
+ identifier: string;
278
+ /** Account password */
279
+ password: string;
280
+ /** Two-factor authentication code */
281
+ code?: string;
282
+ }
283
+
284
+ const isExpiredTokenResponse = async (response: Response): Promise<boolean> => {
285
+ if (response.status !== 400) {
286
+ return false;
287
+ }
288
+
289
+ if (extractContentType(response.headers) !== 'application/json') {
290
+ return false;
291
+ }
292
+
293
+ // {"error":"ExpiredToken","message":"Token has expired"}
294
+ // {"error":"ExpiredToken","message":"Token is expired"}
295
+ if (extractContentLength(response.headers) > 54 * 1.5) {
296
+ return false;
297
+ }
298
+
299
+ try {
300
+ const { error, message } = await response.clone().json();
301
+ return error === 'ExpiredToken' && (typeof message === 'string' || message === undefined);
302
+ } catch {}
303
+
304
+ return false;
305
+ };
306
+
307
+ const extractContentType = (headers: Headers) => {
308
+ return headers.get('content-type')?.split(';')[0]?.trim();
309
+ };
310
+ const extractContentLength = (headers: Headers) => {
311
+ return Number(headers.get('content-length') ?? ';');
312
+ };
@@ -0,0 +1,30 @@
1
+ /** Fetch handler function */
2
+ export type FetchHandler = (pathname: string, init: RequestInit) => Promise<Response>;
3
+
4
+ /** Fetch handler in an object */
5
+ export interface FetchHandlerObject {
6
+ handle(this: FetchHandlerObject, pathname: string, init: RequestInit): Promise<Response>;
7
+ }
8
+
9
+ export const buildFetchHandler = (handler: FetchHandler | FetchHandlerObject): FetchHandler => {
10
+ if (typeof handler === 'object') {
11
+ return handler.handle.bind(handler);
12
+ }
13
+
14
+ return handler;
15
+ };
16
+
17
+ export interface SimpleFetchHandlerOptions {
18
+ service: string | URL;
19
+ fetch?: typeof globalThis.fetch;
20
+ }
21
+
22
+ export const simpleFetchHandler = ({
23
+ service,
24
+ fetch: _fetch = fetch,
25
+ }: SimpleFetchHandlerOptions): FetchHandler => {
26
+ return async (pathname, init) => {
27
+ const url = new URL(pathname, service);
28
+ return _fetch(url, init);
29
+ };
30
+ };
package/lib/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './rpc.js';
2
+ export * from './fetch-handler.js';
3
+ export * from './credential-manager.js';