@atproto/api 0.18.8 → 0.18.10
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/CHANGELOG.md +17 -0
- package/dist/atp-agent.d.ts +8 -2
- package/dist/atp-agent.d.ts.map +1 -1
- package/dist/atp-agent.js +115 -80
- package/dist/atp-agent.js.map +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +6 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/lexicons.d.ts +60 -8
- package/dist/client/lexicons.d.ts.map +1 -1
- package/dist/client/lexicons.js +35 -4
- package/dist/client/lexicons.js.map +1 -1
- package/dist/client/types/app/bsky/unspecced/getSuggestedUsers.d.ts +2 -0
- package/dist/client/types/app/bsky/unspecced/getSuggestedUsers.d.ts.map +1 -1
- package/dist/client/types/app/bsky/unspecced/getSuggestedUsers.js.map +1 -1
- package/dist/client/types/app/bsky/unspecced/getSuggestedUsersSkeleton.d.ts +2 -0
- package/dist/client/types/app/bsky/unspecced/getSuggestedUsersSkeleton.d.ts.map +1 -1
- package/dist/client/types/app/bsky/unspecced/getSuggestedUsersSkeleton.js.map +1 -1
- package/dist/client/types/com/atproto/server/deleteSession.d.ts +7 -1
- package/dist/client/types/com/atproto/server/deleteSession.d.ts.map +1 -1
- package/dist/client/types/com/atproto/server/deleteSession.js +23 -0
- package/dist/client/types/com/atproto/server/deleteSession.js.map +1 -1
- package/dist/client/types/com/atproto/server/getSession.d.ts +3 -3
- package/dist/client/types/com/atproto/server/getSession.d.ts.map +1 -1
- package/dist/client/types/com/atproto/server/getSession.js.map +1 -1
- package/dist/client/types/com/atproto/server/refreshSession.d.ts +9 -0
- package/dist/client/types/com/atproto/server/refreshSession.d.ts.map +1 -1
- package/dist/client/types/com/atproto/server/refreshSession.js +17 -1
- package/dist/client/types/com/atproto/server/refreshSession.js.map +1 -1
- package/package.json +2 -2
- package/src/atp-agent.ts +147 -99
- package/src/client/index.ts +5 -6
- package/src/client/lexicons.ts +38 -4
- package/src/client/types/app/bsky/unspecced/getSuggestedUsers.ts +2 -0
- package/src/client/types/app/bsky/unspecced/getSuggestedUsersSkeleton.ts +2 -0
- package/src/client/types/com/atproto/server/deleteSession.ts +17 -0
- package/src/client/types/com/atproto/server/getSession.ts +1 -1
- package/src/client/types/com/atproto/server/refreshSession.ts +17 -0
- package/tests/dispatcher.test.ts +13 -10
- package/tsconfig.tests.tsbuildinfo +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @atproto/api
|
|
2
2
|
|
|
3
|
+
## 0.18.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#4440](https://github.com/bluesky-social/atproto/pull/4440) [`63f97ae`](https://github.com/bluesky-social/atproto/commit/63f97ae9c1f57def2d489ab8ce7f83a84a7d1ba1) Thanks [@iwsmith](https://github.com/iwsmith)! - Add `recID` field to `getSuggestedUsers` and `getSuggestedUsersSkeleton`
|
|
8
|
+
|
|
9
|
+
## 0.18.9
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#4470](https://github.com/bluesky-social/atproto/pull/4470) [`10cf1c1`](https://github.com/bluesky-social/atproto/commit/10cf1c10188596724b0c38a5af507d95a382a164) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Use 401 status code as signal that the credentials are invalid and should no longer be used.
|
|
14
|
+
|
|
15
|
+
- [#4470](https://github.com/bluesky-social/atproto/pull/4470) [`10cf1c1`](https://github.com/bluesky-social/atproto/commit/10cf1c10188596724b0c38a5af507d95a382a164) Thanks [@matthieusieben](https://github.com/matthieusieben)! - The `CredentialSession.resumeSession()` method now leverages full session data to restore user sessions in a single HTTP call (instead of up to three before). Servers that do not return `email` and `emailConfirmed` session fields will still be supported, but will cause an additional request to `com.atproto.server.getSession` to fetch the missing data.
|
|
16
|
+
|
|
17
|
+
- Updated dependencies []:
|
|
18
|
+
- @atproto/common-web@0.4.8
|
|
19
|
+
|
|
3
20
|
## 0.18.8
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/dist/atp-agent.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Gettable } from '@atproto/xrpc';
|
|
2
2
|
import { Agent } from './agent';
|
|
3
|
-
import { ComAtprotoServerCreateAccount, ComAtprotoServerCreateSession, ComAtprotoServerGetSession, ComAtprotoServerNS } from './client';
|
|
3
|
+
import { ComAtprotoServerCreateAccount, ComAtprotoServerCreateSession, ComAtprotoServerGetSession, ComAtprotoServerNS, ComAtprotoServerRefreshSession } from './client';
|
|
4
4
|
import { SessionManager } from './session-manager';
|
|
5
5
|
import { AtpAgentLoginOpts, AtpPersistSessionHandler, AtpSessionData } from './types';
|
|
6
6
|
export type AtpAgentOptions = {
|
|
@@ -86,8 +86,14 @@ export declare class CredentialSession implements SessionManager {
|
|
|
86
86
|
logout(): Promise<void>;
|
|
87
87
|
/**
|
|
88
88
|
* Resume a pre-existing session with this agent.
|
|
89
|
+
*
|
|
90
|
+
* @note that a rejected promise from this method indicates a failure to
|
|
91
|
+
* refresh the session after resuming it but does not indicate a failure to
|
|
92
|
+
* set the session itself. In case of rejection, check the presence of
|
|
93
|
+
* {@link CredentialSession.session} after calling this method to ensure the
|
|
94
|
+
* session was set.
|
|
89
95
|
*/
|
|
90
|
-
resumeSession(session: AtpSessionData): Promise<ComAtprotoServerGetSession.Response>;
|
|
96
|
+
resumeSession(session: AtpSessionData): Promise<ComAtprotoServerGetSession.Response | ComAtprotoServerRefreshSession.Response>;
|
|
91
97
|
/**
|
|
92
98
|
* Internal helper to refresh sessions
|
|
93
99
|
* - Wraps the actual implementation in a promise-guard to ensure only
|
package/dist/atp-agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atp-agent.d.ts","sourceRoot":"","sources":["../src/atp-agent.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,QAAQ,EAKT,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,OAAO,EACL,6BAA6B,EAC7B,6BAA6B,EAC7B,0BAA0B,EAC1B,kBAAkB,
|
|
1
|
+
{"version":3,"file":"atp-agent.d.ts","sourceRoot":"","sources":["../src/atp-agent.ts"],"names":[],"mappings":"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"}
|
package/dist/atp-agent.js
CHANGED
|
@@ -189,7 +189,8 @@ class CredentialSession {
|
|
|
189
189
|
if (!this.session?.refreshJwt) {
|
|
190
190
|
return initialRes;
|
|
191
191
|
}
|
|
192
|
-
const isExpiredToken =
|
|
192
|
+
const isExpiredToken = initialRes.status === 401 ||
|
|
193
|
+
(await isErrorResponse(initialRes, [400], ['ExpiredToken']));
|
|
193
194
|
if (!isExpiredToken) {
|
|
194
195
|
return initialRes;
|
|
195
196
|
}
|
|
@@ -227,6 +228,9 @@ class CredentialSession {
|
|
|
227
228
|
* Create a new account and hydrate its session in this agent.
|
|
228
229
|
*/
|
|
229
230
|
async createAccount(data, opts) {
|
|
231
|
+
// Clear any existing session
|
|
232
|
+
this.session = undefined;
|
|
233
|
+
this.refreshSessionPromise = undefined;
|
|
230
234
|
try {
|
|
231
235
|
const res = await this.server.createAccount(data, opts);
|
|
232
236
|
this.session = {
|
|
@@ -253,6 +257,9 @@ class CredentialSession {
|
|
|
253
257
|
* Start a new session with this agent.
|
|
254
258
|
*/
|
|
255
259
|
async login(opts) {
|
|
260
|
+
// Clear any existing session
|
|
261
|
+
this.session = undefined;
|
|
262
|
+
this.refreshSessionPromise = undefined;
|
|
256
263
|
try {
|
|
257
264
|
const res = await this.server.createSession({
|
|
258
265
|
identifier: opts.identifier,
|
|
@@ -260,6 +267,9 @@ class CredentialSession {
|
|
|
260
267
|
authFactorToken: opts.authFactorToken,
|
|
261
268
|
allowTakendown: opts.allowTakendown,
|
|
262
269
|
});
|
|
270
|
+
if (this.session) {
|
|
271
|
+
throw new Error('Concurrent login detected');
|
|
272
|
+
}
|
|
263
273
|
this.session = {
|
|
264
274
|
accessJwt: res.data.accessJwt,
|
|
265
275
|
refreshJwt: res.data.refreshJwt,
|
|
@@ -301,66 +311,42 @@ class CredentialSession {
|
|
|
301
311
|
}
|
|
302
312
|
/**
|
|
303
313
|
* Resume a pre-existing session with this agent.
|
|
314
|
+
*
|
|
315
|
+
* @note that a rejected promise from this method indicates a failure to
|
|
316
|
+
* refresh the session after resuming it but does not indicate a failure to
|
|
317
|
+
* set the session itself. In case of rejection, check the presence of
|
|
318
|
+
* {@link CredentialSession.session} after calling this method to ensure the
|
|
319
|
+
* session was set.
|
|
304
320
|
*/
|
|
305
321
|
async resumeSession(session) {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
const res = await this.server.refreshSession(undefined, {
|
|
318
|
-
headers: { authorization: `Bearer ${session.refreshJwt}` },
|
|
319
|
-
});
|
|
320
|
-
session.accessJwt = res.data.accessJwt;
|
|
321
|
-
session.refreshJwt = res.data.refreshJwt;
|
|
322
|
-
return this.server.getSession(undefined, {
|
|
323
|
-
headers: { authorization: `Bearer ${session.accessJwt}` },
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
catch {
|
|
327
|
-
// Noop, we'll throw the original error
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
throw err;
|
|
331
|
-
});
|
|
332
|
-
if (res.data.did !== session.did) {
|
|
333
|
-
throw new xrpc_1.XRPCError(xrpc_1.ResponseType.InvalidRequest, 'Invalid session', 'InvalidDID');
|
|
334
|
-
}
|
|
335
|
-
session.email = res.data.email;
|
|
336
|
-
session.handle = res.data.handle;
|
|
337
|
-
session.emailConfirmed = res.data.emailConfirmed;
|
|
338
|
-
session.emailAuthFactor = res.data.emailAuthFactor;
|
|
339
|
-
session.active = res.data.active ?? true;
|
|
340
|
-
session.status = res.data.status;
|
|
341
|
-
// protect against concurrent session updates
|
|
342
|
-
if (this.session === session) {
|
|
343
|
-
this._updateApiEndpoint(res.data.didDoc);
|
|
344
|
-
this.persistSession?.('update', session);
|
|
345
|
-
}
|
|
346
|
-
return res;
|
|
347
|
-
}
|
|
348
|
-
catch (err) {
|
|
349
|
-
// protect against concurrent session updates
|
|
350
|
-
if (this.session === session) {
|
|
351
|
-
if (err instanceof xrpc_1.XRPCError &&
|
|
352
|
-
['ExpiredToken', 'InvalidToken'].includes(err.error)) {
|
|
353
|
-
this.session = undefined;
|
|
354
|
-
this.persistSession?.('expired', undefined);
|
|
355
|
-
}
|
|
356
|
-
else {
|
|
357
|
-
// Assume the problem is transient and the session can be reused later.
|
|
358
|
-
this.session = session;
|
|
359
|
-
this.persistSession?.('network-error', session);
|
|
360
|
-
}
|
|
322
|
+
// Protect against multiple calls to resumeSession that would trigger a
|
|
323
|
+
// refresh for the same session simultaneously.
|
|
324
|
+
// Ideally, this check would be based on a session identifier, but since
|
|
325
|
+
// we don't have one, we will just check the refresh token.
|
|
326
|
+
if (session.refreshJwt === this.session?.refreshJwt) {
|
|
327
|
+
// Protect against refreshes in progress
|
|
328
|
+
await this.refreshSessionPromise;
|
|
329
|
+
// Another concurrent operation may have replaced the session while we
|
|
330
|
+
// were waiting for the refresh to complete.
|
|
331
|
+
if (session.did !== this.session?.did) {
|
|
332
|
+
throw new Error('DID mismatch on resumeSession');
|
|
361
333
|
}
|
|
362
|
-
|
|
334
|
+
return this.server.getSession(undefined, {
|
|
335
|
+
headers: { authorization: `Bearer ${this.session.accessJwt}` },
|
|
336
|
+
});
|
|
363
337
|
}
|
|
338
|
+
// Set the current session, then force a refresh, replacing any pending
|
|
339
|
+
// refresh operation.
|
|
340
|
+
this.session = session;
|
|
341
|
+
this.refreshSessionPromise = undefined;
|
|
342
|
+
const promise = this._refreshSessionInner();
|
|
343
|
+
// Discard any concurrent refresh, replacing it with this one.
|
|
344
|
+
this.refreshSessionPromise = promise
|
|
345
|
+
.then(() => { }, () => { })
|
|
346
|
+
.finally(() => {
|
|
347
|
+
this.refreshSessionPromise = undefined;
|
|
348
|
+
});
|
|
349
|
+
return promise;
|
|
364
350
|
}
|
|
365
351
|
/**
|
|
366
352
|
* Internal helper to refresh sessions
|
|
@@ -368,7 +354,12 @@ class CredentialSession {
|
|
|
368
354
|
* one refresh is attempted at a time.
|
|
369
355
|
*/
|
|
370
356
|
async refreshSession() {
|
|
371
|
-
|
|
357
|
+
if (!this.session)
|
|
358
|
+
return;
|
|
359
|
+
// Do not refresh if we already have a refresh in progress
|
|
360
|
+
return (this.refreshSessionPromise || (this.refreshSessionPromise = this._refreshSessionInner()
|
|
361
|
+
.then(() => { }, () => { })
|
|
362
|
+
.finally(() => {
|
|
372
363
|
this.refreshSessionPromise = undefined;
|
|
373
364
|
})));
|
|
374
365
|
}
|
|
@@ -376,35 +367,76 @@ class CredentialSession {
|
|
|
376
367
|
* Internal helper to refresh sessions (actual behavior)
|
|
377
368
|
*/
|
|
378
369
|
async _refreshSessionInner() {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
370
|
+
const { session } = this;
|
|
371
|
+
// Should never happen
|
|
372
|
+
if (!session)
|
|
373
|
+
throw new Error('No session to refresh');
|
|
382
374
|
try {
|
|
383
375
|
const res = await this.server.refreshSession(undefined, {
|
|
384
|
-
headers: { authorization: `Bearer ${
|
|
376
|
+
headers: { authorization: `Bearer ${session.refreshJwt}` },
|
|
385
377
|
});
|
|
378
|
+
const { data } = res;
|
|
379
|
+
// Something is very wrong if the DID changes during a refresh
|
|
380
|
+
if (data.did !== session.did) {
|
|
381
|
+
throw new xrpc_1.XRPCError(xrpc_1.ResponseType.InvalidRequest, 'Invalid session', 'InvalidDID');
|
|
382
|
+
}
|
|
383
|
+
// Historically, refreshSession did not return all the fields from
|
|
384
|
+
// getSession. In particular, email, emailConfirmed and emailAuthFactor
|
|
385
|
+
// were missing. Similarly, some servers might not return the didDoc in
|
|
386
|
+
// refreshSession. We fetch them via getSession if missing, allowing to
|
|
387
|
+
// ensure that we are always talking with the right PDS.
|
|
388
|
+
if (data.emailConfirmed == null || data.didDoc == null) {
|
|
389
|
+
try {
|
|
390
|
+
const res = await this.server.getSession(undefined, {
|
|
391
|
+
headers: { authorization: `Bearer ${data.accessJwt}` },
|
|
392
|
+
});
|
|
393
|
+
// Fool proofing (should always match)
|
|
394
|
+
if (res.data.did === data.did) {
|
|
395
|
+
Object.assign(data, res.data);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
// Noop, we'll keep the current values we have
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
// protect against concurrent session updates
|
|
403
|
+
if (this.session !== session) {
|
|
404
|
+
return Promise.reject(new Error('Concurrent session update detected'));
|
|
405
|
+
}
|
|
386
406
|
// succeeded, update the session
|
|
387
407
|
this.session = {
|
|
388
|
-
|
|
389
|
-
accessJwt:
|
|
390
|
-
refreshJwt:
|
|
391
|
-
handle:
|
|
392
|
-
|
|
408
|
+
did: data.did,
|
|
409
|
+
accessJwt: data.accessJwt,
|
|
410
|
+
refreshJwt: data.refreshJwt,
|
|
411
|
+
handle: data.handle ?? session.handle,
|
|
412
|
+
email: data.email ?? session.email,
|
|
413
|
+
emailConfirmed: data.emailConfirmed ?? session.emailConfirmed,
|
|
414
|
+
emailAuthFactor: data.emailAuthFactor ?? session.emailAuthFactor,
|
|
415
|
+
active: data.active ?? session.active ?? true,
|
|
416
|
+
status: data.status ?? session.status,
|
|
393
417
|
};
|
|
394
418
|
this._updateApiEndpoint(res.data.didDoc);
|
|
395
419
|
this.persistSession?.('update', this.session);
|
|
420
|
+
return res;
|
|
396
421
|
}
|
|
397
422
|
catch (err) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
423
|
+
// protect against concurrent session updates
|
|
424
|
+
if (this.session === session) {
|
|
425
|
+
if (err instanceof xrpc_1.XRPCError &&
|
|
426
|
+
(err.status === 401 ||
|
|
427
|
+
err.error === 'InvalidDID' ||
|
|
428
|
+
['ExpiredToken', 'InvalidToken'].includes(err.error))) {
|
|
429
|
+
// failed due to a bad refresh token
|
|
430
|
+
this.session = undefined;
|
|
431
|
+
this.persistSession?.('expired', undefined);
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
// Assume the problem is transient and the session can be reused later.
|
|
435
|
+
this.session = session;
|
|
436
|
+
this.persistSession?.('network-error', session);
|
|
437
|
+
}
|
|
404
438
|
}
|
|
405
|
-
|
|
406
|
-
// propagate in the _dispatch() second attempt to run
|
|
407
|
-
// the request
|
|
439
|
+
throw err;
|
|
408
440
|
}
|
|
409
441
|
}
|
|
410
442
|
/**
|
|
@@ -418,12 +450,15 @@ class CredentialSession {
|
|
|
418
450
|
* when the PDSes are operated by a single org.)
|
|
419
451
|
*/
|
|
420
452
|
_updateApiEndpoint(didDoc) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
this.pdsUrl =
|
|
453
|
+
const endpoint = (0, common_web_1.isValidDidDoc)(didDoc) ? (0, common_web_1.getPdsEndpoint)(didDoc) : undefined;
|
|
454
|
+
if (endpoint) {
|
|
455
|
+
this.pdsUrl = new URL(endpoint);
|
|
424
456
|
}
|
|
425
457
|
else {
|
|
426
|
-
// If the did doc is invalid, we clear the pdsUrl (should
|
|
458
|
+
// If the did doc is invalid (or missing), we clear the pdsUrl (should
|
|
459
|
+
// never happen). This is fine if the auth server and PDS are the same
|
|
460
|
+
// service, or if the auth server will proxy requests to the right PDS
|
|
461
|
+
// (which is the case for Bluesky's "entryway").
|
|
427
462
|
this.pdsUrl = undefined;
|
|
428
463
|
}
|
|
429
464
|
}
|
package/dist/atp-agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atp-agent.js","sourceRoot":"","sources":["../src/atp-agent.ts"],"names":[],"mappings":"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","sourcesContent":["import { getPdsEndpoint, isValidDidDoc } from '@atproto/common-web'\nimport {\n ErrorResponseBody,\n Gettable,\n ResponseType,\n XRPCError,\n XrpcClient,\n errorResponseBody,\n} from '@atproto/xrpc'\nimport { Agent } from './agent'\nimport {\n ComAtprotoServerCreateAccount,\n ComAtprotoServerCreateSession,\n ComAtprotoServerGetSession,\n ComAtprotoServerNS,\n} from './client'\nimport { schemas } from './client/lexicons'\nimport { SessionManager } from './session-manager'\nimport {\n AtpAgentLoginOpts,\n AtpPersistSessionHandler,\n AtpSessionData,\n} from './types'\n\nconst ReadableStream = globalThis.ReadableStream as\n | typeof globalThis.ReadableStream\n | undefined\n\nexport type AtpAgentOptions = {\n service: string | URL\n persistSession?: AtpPersistSessionHandler\n fetch?: typeof globalThis.fetch\n headers?: Iterable<[string, Gettable<null | string>]>\n}\n\n/**\n * A wrapper around the {@link Agent} class that uses credential based session\n * management. This class also exposes most of the session management methods\n * directly.\n *\n * This class will be deprecated in the near future. Use {@link Agent} directly\n * with a {@link CredentialSession} instead:\n *\n * ```ts\n * const session = new CredentialSession({\n * service: new URL('https://example.com'),\n * })\n *\n * const agent = new Agent(session)\n * ```\n */\nexport class AtpAgent extends Agent {\n readonly sessionManager: CredentialSession\n\n constructor(options: AtpAgentOptions | CredentialSession) {\n const sessionManager =\n options instanceof CredentialSession\n ? options\n : new CredentialSession(\n new URL(options.service),\n options.fetch,\n options.persistSession,\n )\n\n super(sessionManager)\n\n // This assignment is already being done in the super constructor, but we\n // need to do it here to make TypeScript happy.\n this.sessionManager = sessionManager\n\n if (!(options instanceof CredentialSession) && options.headers) {\n for (const [key, value] of options.headers) {\n this.setHeader(key, value)\n }\n }\n }\n\n clone(): AtpAgent {\n return this.copyInto(new AtpAgent(this.sessionManager))\n }\n\n get session() {\n return this.sessionManager.session\n }\n\n get hasSession() {\n return this.sessionManager.hasSession\n }\n\n get did() {\n return this.sessionManager.did\n }\n\n get serviceUrl() {\n return this.sessionManager.serviceUrl\n }\n\n get pdsUrl() {\n return this.sessionManager.pdsUrl\n }\n\n get dispatchUrl() {\n return this.sessionManager.dispatchUrl\n }\n\n /** @deprecated use {@link serviceUrl} instead */\n get service() {\n return this.serviceUrl\n }\n\n get persistSession() {\n throw new Error(\n 'Cannot set persistSession directly. \"persistSession\" is defined through the constructor and will be invoked automatically when session data changes.',\n )\n }\n\n set persistSession(v: unknown) {\n throw new Error(\n 'Cannot set persistSession directly. \"persistSession\" must be defined in the constructor and can no longer be changed.',\n )\n }\n\n /** @deprecated use {@link AtpAgent.serviceUrl} instead */\n getServiceUrl() {\n return this.serviceUrl\n }\n\n async resumeSession(\n session: AtpSessionData,\n ): Promise<ComAtprotoServerGetSession.Response> {\n return this.sessionManager.resumeSession(session)\n }\n\n async createAccount(\n data: ComAtprotoServerCreateAccount.InputSchema,\n opts?: ComAtprotoServerCreateAccount.CallOptions,\n ): Promise<ComAtprotoServerCreateAccount.Response> {\n return this.sessionManager.createAccount(data, opts)\n }\n\n async login(\n opts: AtpAgentLoginOpts,\n ): Promise<ComAtprotoServerCreateSession.Response> {\n return this.sessionManager.login(opts)\n }\n\n async logout(): Promise<void> {\n return this.sessionManager.logout()\n }\n}\n\n/**\n * Credentials (username / password) based session manager. Instances of this\n * class will typically be used as the session manager for an {@link AtpAgent}.\n * They can also be used with an {@link XrpcClient}, if you want to use you\n * own Lexicons.\n */\nexport class CredentialSession implements SessionManager {\n public pdsUrl?: URL // The PDS URL, driven by the did doc\n public session?: AtpSessionData\n public refreshSessionPromise: Promise<void> | undefined\n\n /**\n * Private {@link ComAtprotoServerNS} used to perform session management API\n * calls on the service endpoint. Calls performed by this agent will not be\n * authenticated using the user's session to allow proper manual configuration\n * of the headers when performing session management operations.\n */\n protected server = new ComAtprotoServerNS(\n // Note that the use of the codegen \"schemas\" (to instantiate `this.api`),\n // as well as the use of `ComAtprotoServerNS` will cause this class to\n // reference (way) more code than it actually needs. It is not possible,\n // with the current state of the codegen, to generate a client that only\n // includes the methods that are actually used by this class. This is a\n // known limitation that should be addressed in a future version of the\n // codegen.\n new XrpcClient((url, init) => {\n return (0, this.fetch)(new URL(url, this.serviceUrl), init)\n }, schemas),\n )\n\n constructor(\n public readonly serviceUrl: URL,\n public fetch = globalThis.fetch,\n protected readonly persistSession?: AtpPersistSessionHandler,\n ) {}\n\n get did() {\n return this.session?.did\n }\n\n get dispatchUrl() {\n return this.pdsUrl || this.serviceUrl\n }\n\n get hasSession() {\n return !!this.session\n }\n\n /**\n * Sets a WhatWG \"fetch()\" function to be used for making HTTP requests.\n */\n setFetch(fetch = globalThis.fetch) {\n this.fetch = fetch\n }\n\n async fetchHandler(url: string, init?: RequestInit): Promise<Response> {\n // wait for any active session-refreshes to finish\n await this.refreshSessionPromise\n\n const initialUri = new URL(url, this.dispatchUrl)\n const initialReq = new Request(initialUri, init)\n\n const initialToken = this.session?.accessJwt\n if (!initialToken || initialReq.headers.has('authorization')) {\n return (0, this.fetch)(initialReq)\n }\n\n initialReq.headers.set('authorization', `Bearer ${initialToken}`)\n const initialRes = await (0, this.fetch)(initialReq)\n\n if (!this.session?.refreshJwt) {\n return initialRes\n }\n const isExpiredToken = await isErrorResponse(\n initialRes,\n [400],\n ['ExpiredToken'],\n )\n\n if (!isExpiredToken) {\n return initialRes\n }\n\n try {\n await this.refreshSession()\n } catch {\n return initialRes\n }\n\n if (init?.signal?.aborted) {\n return initialRes\n }\n\n // The stream was already consumed. We cannot retry the request. A solution\n // would be to tee() the input stream but that would bufferize the entire\n // stream in memory which can lead to memory starvation. Instead, we will\n // return the original response and let the calling code handle retries.\n if (ReadableStream && init?.body instanceof ReadableStream) {\n return initialRes\n }\n\n // Return initial \"ExpiredToken\" response if the session was not refreshed.\n const updatedToken = this.session?.accessJwt\n if (!updatedToken || updatedToken === initialToken) {\n return initialRes\n }\n\n // Make sure the initial request is cancelled to avoid leaking resources\n // (NodeJS 👀): https://undici.nodejs.org/#/?id=garbage-collection\n await initialRes.body?.cancel()\n\n // We need to re-compute the URI in case the PDS endpoint has changed\n const updatedUri = new URL(url, this.dispatchUrl)\n const updatedReq = new Request(updatedUri, init)\n\n updatedReq.headers.set('authorization', `Bearer ${updatedToken}`)\n\n return await (0, this.fetch)(updatedReq)\n }\n\n /**\n * Create a new account and hydrate its session in this agent.\n */\n async createAccount(\n data: ComAtprotoServerCreateAccount.InputSchema,\n opts?: ComAtprotoServerCreateAccount.CallOptions,\n ): Promise<ComAtprotoServerCreateAccount.Response> {\n try {\n const res = await this.server.createAccount(data, opts)\n this.session = {\n accessJwt: res.data.accessJwt,\n refreshJwt: res.data.refreshJwt,\n handle: res.data.handle,\n did: res.data.did,\n email: data.email,\n emailConfirmed: false,\n emailAuthFactor: false,\n active: true,\n }\n this.persistSession?.('create', this.session)\n this._updateApiEndpoint(res.data.didDoc)\n return res\n } catch (e) {\n this.session = undefined\n this.persistSession?.('create-failed', undefined)\n throw e\n }\n }\n\n /**\n * Start a new session with this agent.\n */\n async login(\n opts: AtpAgentLoginOpts,\n ): Promise<ComAtprotoServerCreateSession.Response> {\n try {\n const res = await this.server.createSession({\n identifier: opts.identifier,\n password: opts.password,\n authFactorToken: opts.authFactorToken,\n allowTakendown: opts.allowTakendown,\n })\n this.session = {\n accessJwt: res.data.accessJwt,\n refreshJwt: res.data.refreshJwt,\n handle: res.data.handle,\n did: res.data.did,\n email: res.data.email,\n emailConfirmed: res.data.emailConfirmed,\n emailAuthFactor: res.data.emailAuthFactor,\n active: res.data.active ?? true,\n status: res.data.status,\n }\n this._updateApiEndpoint(res.data.didDoc)\n this.persistSession?.('create', this.session)\n return res\n } catch (e) {\n this.session = undefined\n this.persistSession?.('create-failed', undefined)\n throw e\n }\n }\n\n async logout(): Promise<void> {\n if (this.session) {\n try {\n await this.server.deleteSession(undefined, {\n headers: {\n authorization: `Bearer ${this.session.refreshJwt}`,\n },\n })\n } catch {\n // Ignore errors\n } finally {\n this.session = undefined\n this.persistSession?.('expired', undefined)\n }\n }\n }\n\n /**\n * Resume a pre-existing session with this agent.\n */\n async resumeSession(\n session: AtpSessionData,\n ): Promise<ComAtprotoServerGetSession.Response> {\n this.session = session\n\n try {\n const res = await this.server\n .getSession(undefined, {\n headers: { authorization: `Bearer ${session.accessJwt}` },\n })\n .catch(async (err) => {\n if (\n err instanceof XRPCError &&\n ['ExpiredToken', 'InvalidToken'].includes(err.error) &&\n session.refreshJwt\n ) {\n try {\n const res = await this.server.refreshSession(undefined, {\n headers: { authorization: `Bearer ${session.refreshJwt}` },\n })\n\n session.accessJwt = res.data.accessJwt\n session.refreshJwt = res.data.refreshJwt\n\n return this.server.getSession(undefined, {\n headers: { authorization: `Bearer ${session.accessJwt}` },\n })\n } catch {\n // Noop, we'll throw the original error\n }\n }\n throw err\n })\n\n if (res.data.did !== session.did) {\n throw new XRPCError(\n ResponseType.InvalidRequest,\n 'Invalid session',\n 'InvalidDID',\n )\n }\n\n session.email = res.data.email\n session.handle = res.data.handle\n session.emailConfirmed = res.data.emailConfirmed\n session.emailAuthFactor = res.data.emailAuthFactor\n session.active = res.data.active ?? true\n session.status = res.data.status\n\n // protect against concurrent session updates\n if (this.session === session) {\n this._updateApiEndpoint(res.data.didDoc)\n this.persistSession?.('update', session)\n }\n\n return res\n } catch (err) {\n // protect against concurrent session updates\n if (this.session === session) {\n if (\n err instanceof XRPCError &&\n ['ExpiredToken', 'InvalidToken'].includes(err.error)\n ) {\n this.session = undefined\n this.persistSession?.('expired', undefined)\n } else {\n // Assume the problem is transient and the session can be reused later.\n this.session = session\n this.persistSession?.('network-error', session)\n }\n }\n\n throw err\n }\n }\n\n /**\n * Internal helper to refresh sessions\n * - Wraps the actual implementation in a promise-guard to ensure only\n * one refresh is attempted at a time.\n */\n async refreshSession(): Promise<void> {\n return (this.refreshSessionPromise ||= this._refreshSessionInner().finally(\n () => {\n this.refreshSessionPromise = undefined\n },\n ))\n }\n\n /**\n * Internal helper to refresh sessions (actual behavior)\n */\n private async _refreshSessionInner() {\n if (!this.session?.refreshJwt) {\n return\n }\n\n try {\n const res = await this.server.refreshSession(undefined, {\n headers: { authorization: `Bearer ${this.session.refreshJwt}` },\n })\n // succeeded, update the session\n this.session = {\n ...this.session,\n accessJwt: res.data.accessJwt,\n refreshJwt: res.data.refreshJwt,\n handle: res.data.handle,\n did: res.data.did,\n }\n this._updateApiEndpoint(res.data.didDoc)\n this.persistSession?.('update', this.session)\n } catch (err) {\n if (\n err instanceof XRPCError &&\n err.error &&\n ['ExpiredToken', 'InvalidToken'].includes(err.error)\n ) {\n // failed due to a bad refresh token\n this.session = undefined\n this.persistSession?.('expired', undefined)\n }\n // else: other failures should be ignored - the issue will\n // propagate in the _dispatch() second attempt to run\n // the request\n }\n }\n\n /**\n * Helper to update the pds endpoint dynamically.\n *\n * The session methods (create, resume, refresh) may respond with the user's\n * did document which contains the user's canonical PDS endpoint. That endpoint\n * may differ from the endpoint used to contact the server. We capture that\n * PDS endpoint and update the client to use that given endpoint for future\n * requests. (This helps ensure smooth migrations between PDSes, especially\n * when the PDSes are operated by a single org.)\n */\n private _updateApiEndpoint(didDoc: unknown) {\n if (isValidDidDoc(didDoc)) {\n const endpoint = getPdsEndpoint(didDoc)\n this.pdsUrl = endpoint ? new URL(endpoint) : undefined\n } else {\n // If the did doc is invalid, we clear the pdsUrl (should never happen)\n this.pdsUrl = undefined\n }\n }\n}\n\nfunction isErrorObject(v: unknown): v is ErrorResponseBody {\n return errorResponseBody.safeParse(v).success\n}\n\nasync function isErrorResponse(\n response: Response,\n status: number[],\n errorNames: string[],\n): Promise<boolean> {\n if (!status.includes(response.status)) return false\n // Some engines (react-native 👀) don't expose a response.body property...\n // if (!response.body) return false\n try {\n const json = await peekJson(response, 10 * 1024)\n return isErrorObject(json) && (errorNames as any[]).includes(json.error)\n } catch (err) {\n return false\n }\n}\n\nasync function peekJson(\n response: Response,\n maxSize = Infinity,\n): Promise<unknown> {\n if (extractType(response) !== 'application/json') throw new Error('Not JSON')\n if (extractLength(response) > maxSize) throw new Error('Response too large')\n return response.clone().json()\n}\n\nfunction extractLength({ headers }: Response) {\n return headers.get('Content-Length')\n ? Number(headers.get('Content-Length'))\n : NaN\n}\n\nfunction extractType({ headers }: Response) {\n return headers.get('Content-Type')?.split(';')[0]?.trim()\n}\n"]}
|
|
1
|
+
{"version":3,"file":"atp-agent.js","sourceRoot":"","sources":["../src/atp-agent.ts"],"names":[],"mappings":"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","sourcesContent":["import { getPdsEndpoint, isValidDidDoc } from '@atproto/common-web'\nimport {\n ErrorResponseBody,\n Gettable,\n ResponseType,\n XRPCError,\n XrpcClient,\n errorResponseBody,\n} from '@atproto/xrpc'\nimport { Agent } from './agent'\nimport {\n ComAtprotoServerCreateAccount,\n ComAtprotoServerCreateSession,\n ComAtprotoServerGetSession,\n ComAtprotoServerNS,\n ComAtprotoServerRefreshSession,\n} from './client'\nimport { schemas } from './client/lexicons'\nimport { SessionManager } from './session-manager'\nimport {\n AtpAgentLoginOpts,\n AtpPersistSessionHandler,\n AtpSessionData,\n} from './types'\n\nconst ReadableStream = globalThis.ReadableStream as\n | typeof globalThis.ReadableStream\n | undefined\n\nexport type AtpAgentOptions = {\n service: string | URL\n persistSession?: AtpPersistSessionHandler\n fetch?: typeof globalThis.fetch\n headers?: Iterable<[string, Gettable<null | string>]>\n}\n\n/**\n * A wrapper around the {@link Agent} class that uses credential based session\n * management. This class also exposes most of the session management methods\n * directly.\n *\n * This class will be deprecated in the near future. Use {@link Agent} directly\n * with a {@link CredentialSession} instead:\n *\n * ```ts\n * const session = new CredentialSession({\n * service: new URL('https://example.com'),\n * })\n *\n * const agent = new Agent(session)\n * ```\n */\nexport class AtpAgent extends Agent {\n readonly sessionManager: CredentialSession\n\n constructor(options: AtpAgentOptions | CredentialSession) {\n const sessionManager =\n options instanceof CredentialSession\n ? options\n : new CredentialSession(\n new URL(options.service),\n options.fetch,\n options.persistSession,\n )\n\n super(sessionManager)\n\n // This assignment is already being done in the super constructor, but we\n // need to do it here to make TypeScript happy.\n this.sessionManager = sessionManager\n\n if (!(options instanceof CredentialSession) && options.headers) {\n for (const [key, value] of options.headers) {\n this.setHeader(key, value)\n }\n }\n }\n\n clone(): AtpAgent {\n return this.copyInto(new AtpAgent(this.sessionManager))\n }\n\n get session() {\n return this.sessionManager.session\n }\n\n get hasSession() {\n return this.sessionManager.hasSession\n }\n\n get did() {\n return this.sessionManager.did\n }\n\n get serviceUrl() {\n return this.sessionManager.serviceUrl\n }\n\n get pdsUrl() {\n return this.sessionManager.pdsUrl\n }\n\n get dispatchUrl() {\n return this.sessionManager.dispatchUrl\n }\n\n /** @deprecated use {@link serviceUrl} instead */\n get service() {\n return this.serviceUrl\n }\n\n get persistSession() {\n throw new Error(\n 'Cannot set persistSession directly. \"persistSession\" is defined through the constructor and will be invoked automatically when session data changes.',\n )\n }\n\n set persistSession(v: unknown) {\n throw new Error(\n 'Cannot set persistSession directly. \"persistSession\" must be defined in the constructor and can no longer be changed.',\n )\n }\n\n /** @deprecated use {@link AtpAgent.serviceUrl} instead */\n getServiceUrl() {\n return this.serviceUrl\n }\n\n async resumeSession(\n session: AtpSessionData,\n ): Promise<ComAtprotoServerGetSession.Response> {\n return this.sessionManager.resumeSession(session)\n }\n\n async createAccount(\n data: ComAtprotoServerCreateAccount.InputSchema,\n opts?: ComAtprotoServerCreateAccount.CallOptions,\n ): Promise<ComAtprotoServerCreateAccount.Response> {\n return this.sessionManager.createAccount(data, opts)\n }\n\n async login(\n opts: AtpAgentLoginOpts,\n ): Promise<ComAtprotoServerCreateSession.Response> {\n return this.sessionManager.login(opts)\n }\n\n async logout(): Promise<void> {\n return this.sessionManager.logout()\n }\n}\n\n/**\n * Credentials (username / password) based session manager. Instances of this\n * class will typically be used as the session manager for an {@link AtpAgent}.\n * They can also be used with an {@link XrpcClient}, if you want to use you\n * own Lexicons.\n */\nexport class CredentialSession implements SessionManager {\n public pdsUrl?: URL // The PDS URL, driven by the did doc\n public session?: AtpSessionData\n public refreshSessionPromise: Promise<void> | undefined\n\n /**\n * Private {@link ComAtprotoServerNS} used to perform session management API\n * calls on the service endpoint. Calls performed by this agent will not be\n * authenticated using the user's session to allow proper manual configuration\n * of the headers when performing session management operations.\n */\n protected server = new ComAtprotoServerNS(\n // Note that the use of the codegen \"schemas\" (to instantiate `this.api`),\n // as well as the use of `ComAtprotoServerNS` will cause this class to\n // reference (way) more code than it actually needs. It is not possible,\n // with the current state of the codegen, to generate a client that only\n // includes the methods that are actually used by this class. This is a\n // known limitation that should be addressed in a future version of the\n // codegen.\n new XrpcClient((url, init) => {\n return (0, this.fetch)(new URL(url, this.serviceUrl), init)\n }, schemas),\n )\n\n constructor(\n public readonly serviceUrl: URL,\n public fetch = globalThis.fetch,\n protected readonly persistSession?: AtpPersistSessionHandler,\n ) {}\n\n get did() {\n return this.session?.did\n }\n\n get dispatchUrl() {\n return this.pdsUrl || this.serviceUrl\n }\n\n get hasSession() {\n return !!this.session\n }\n\n /**\n * Sets a WhatWG \"fetch()\" function to be used for making HTTP requests.\n */\n setFetch(fetch = globalThis.fetch) {\n this.fetch = fetch\n }\n\n async fetchHandler(url: string, init?: RequestInit): Promise<Response> {\n // wait for any active session-refreshes to finish\n await this.refreshSessionPromise\n\n const initialUri = new URL(url, this.dispatchUrl)\n const initialReq = new Request(initialUri, init)\n\n const initialToken = this.session?.accessJwt\n if (!initialToken || initialReq.headers.has('authorization')) {\n return (0, this.fetch)(initialReq)\n }\n\n initialReq.headers.set('authorization', `Bearer ${initialToken}`)\n const initialRes = await (0, this.fetch)(initialReq)\n\n if (!this.session?.refreshJwt) {\n return initialRes\n }\n const isExpiredToken =\n initialRes.status === 401 ||\n (await isErrorResponse(initialRes, [400], ['ExpiredToken']))\n\n if (!isExpiredToken) {\n return initialRes\n }\n\n try {\n await this.refreshSession()\n } catch {\n return initialRes\n }\n\n if (init?.signal?.aborted) {\n return initialRes\n }\n\n // The stream was already consumed. We cannot retry the request. A solution\n // would be to tee() the input stream but that would bufferize the entire\n // stream in memory which can lead to memory starvation. Instead, we will\n // return the original response and let the calling code handle retries.\n if (ReadableStream && init?.body instanceof ReadableStream) {\n return initialRes\n }\n\n // Return initial \"ExpiredToken\" response if the session was not refreshed.\n const updatedToken = this.session?.accessJwt\n if (!updatedToken || updatedToken === initialToken) {\n return initialRes\n }\n\n // Make sure the initial request is cancelled to avoid leaking resources\n // (NodeJS 👀): https://undici.nodejs.org/#/?id=garbage-collection\n await initialRes.body?.cancel()\n\n // We need to re-compute the URI in case the PDS endpoint has changed\n const updatedUri = new URL(url, this.dispatchUrl)\n const updatedReq = new Request(updatedUri, init)\n\n updatedReq.headers.set('authorization', `Bearer ${updatedToken}`)\n\n return await (0, this.fetch)(updatedReq)\n }\n\n /**\n * Create a new account and hydrate its session in this agent.\n */\n async createAccount(\n data: ComAtprotoServerCreateAccount.InputSchema,\n opts?: ComAtprotoServerCreateAccount.CallOptions,\n ): Promise<ComAtprotoServerCreateAccount.Response> {\n // Clear any existing session\n this.session = undefined\n this.refreshSessionPromise = undefined\n\n try {\n const res = await this.server.createAccount(data, opts)\n this.session = {\n accessJwt: res.data.accessJwt,\n refreshJwt: res.data.refreshJwt,\n handle: res.data.handle,\n did: res.data.did,\n email: data.email,\n emailConfirmed: false,\n emailAuthFactor: false,\n active: true,\n }\n this.persistSession?.('create', this.session)\n this._updateApiEndpoint(res.data.didDoc)\n return res\n } catch (e) {\n this.session = undefined\n this.persistSession?.('create-failed', undefined)\n throw e\n }\n }\n\n /**\n * Start a new session with this agent.\n */\n async login(\n opts: AtpAgentLoginOpts,\n ): Promise<ComAtprotoServerCreateSession.Response> {\n // Clear any existing session\n this.session = undefined\n this.refreshSessionPromise = undefined\n\n try {\n const res = await this.server.createSession({\n identifier: opts.identifier,\n password: opts.password,\n authFactorToken: opts.authFactorToken,\n allowTakendown: opts.allowTakendown,\n })\n\n if (this.session) {\n throw new Error('Concurrent login detected')\n }\n\n this.session = {\n accessJwt: res.data.accessJwt,\n refreshJwt: res.data.refreshJwt,\n handle: res.data.handle,\n did: res.data.did,\n email: res.data.email,\n emailConfirmed: res.data.emailConfirmed,\n emailAuthFactor: res.data.emailAuthFactor,\n active: res.data.active ?? true,\n status: res.data.status,\n }\n this._updateApiEndpoint(res.data.didDoc)\n this.persistSession?.('create', this.session)\n return res\n } catch (e) {\n this.session = undefined\n this.persistSession?.('create-failed', undefined)\n throw e\n }\n }\n\n async logout(): Promise<void> {\n if (this.session) {\n try {\n await this.server.deleteSession(undefined, {\n headers: {\n authorization: `Bearer ${this.session.refreshJwt}`,\n },\n })\n } catch {\n // Ignore errors\n } finally {\n this.session = undefined\n this.persistSession?.('expired', undefined)\n }\n }\n }\n\n /**\n * Resume a pre-existing session with this agent.\n *\n * @note that a rejected promise from this method indicates a failure to\n * refresh the session after resuming it but does not indicate a failure to\n * set the session itself. In case of rejection, check the presence of\n * {@link CredentialSession.session} after calling this method to ensure the\n * session was set.\n */\n async resumeSession(\n session: AtpSessionData,\n ): Promise<\n | ComAtprotoServerGetSession.Response\n | ComAtprotoServerRefreshSession.Response\n > {\n // Protect against multiple calls to resumeSession that would trigger a\n // refresh for the same session simultaneously.\n // Ideally, this check would be based on a session identifier, but since\n // we don't have one, we will just check the refresh token.\n if (session.refreshJwt === this.session?.refreshJwt) {\n // Protect against refreshes in progress\n await this.refreshSessionPromise\n\n // Another concurrent operation may have replaced the session while we\n // were waiting for the refresh to complete.\n if (session.did !== this.session?.did) {\n throw new Error('DID mismatch on resumeSession')\n }\n\n return this.server.getSession(undefined, {\n headers: { authorization: `Bearer ${this.session.accessJwt}` },\n })\n }\n\n // Set the current session, then force a refresh, replacing any pending\n // refresh operation.\n this.session = session\n this.refreshSessionPromise = undefined\n\n const promise = this._refreshSessionInner()\n\n // Discard any concurrent refresh, replacing it with this one.\n this.refreshSessionPromise = promise\n .then(\n (): void => {},\n (): void => {},\n )\n .finally(() => {\n this.refreshSessionPromise = undefined\n })\n\n return promise\n }\n\n /**\n * Internal helper to refresh sessions\n * - Wraps the actual implementation in a promise-guard to ensure only\n * one refresh is attempted at a time.\n */\n async refreshSession(): Promise<void> {\n if (!this.session) return\n\n // Do not refresh if we already have a refresh in progress\n return (this.refreshSessionPromise ||= this._refreshSessionInner()\n .then(\n (): void => {},\n (): void => {},\n )\n .finally(() => {\n this.refreshSessionPromise = undefined\n }))\n }\n\n /**\n * Internal helper to refresh sessions (actual behavior)\n */\n private async _refreshSessionInner(): Promise<ComAtprotoServerRefreshSession.Response> {\n const { session } = this\n\n // Should never happen\n if (!session) throw new Error('No session to refresh')\n\n try {\n const res = await this.server.refreshSession(undefined, {\n headers: { authorization: `Bearer ${session.refreshJwt}` },\n })\n\n const { data } = res\n\n // Something is very wrong if the DID changes during a refresh\n if (data.did !== session.did) {\n throw new XRPCError(\n ResponseType.InvalidRequest,\n 'Invalid session',\n 'InvalidDID',\n )\n }\n\n // Historically, refreshSession did not return all the fields from\n // getSession. In particular, email, emailConfirmed and emailAuthFactor\n // were missing. Similarly, some servers might not return the didDoc in\n // refreshSession. We fetch them via getSession if missing, allowing to\n // ensure that we are always talking with the right PDS.\n if (data.emailConfirmed == null || data.didDoc == null) {\n try {\n const res = await this.server.getSession(undefined, {\n headers: { authorization: `Bearer ${data.accessJwt}` },\n })\n\n // Fool proofing (should always match)\n if (res.data.did === data.did) {\n Object.assign(data, res.data)\n }\n } catch {\n // Noop, we'll keep the current values we have\n }\n }\n\n // protect against concurrent session updates\n if (this.session !== session) {\n return Promise.reject(new Error('Concurrent session update detected'))\n }\n\n // succeeded, update the session\n this.session = {\n did: data.did,\n accessJwt: data.accessJwt,\n refreshJwt: data.refreshJwt,\n handle: data.handle ?? session.handle,\n email: data.email ?? session.email,\n emailConfirmed: data.emailConfirmed ?? session.emailConfirmed,\n emailAuthFactor: data.emailAuthFactor ?? session.emailAuthFactor,\n active: data.active ?? session.active ?? true,\n status: data.status ?? session.status,\n }\n\n this._updateApiEndpoint(res.data.didDoc)\n this.persistSession?.('update', this.session)\n\n return res\n } catch (err) {\n // protect against concurrent session updates\n if (this.session === session) {\n if (\n err instanceof XRPCError &&\n (err.status === 401 ||\n err.error === 'InvalidDID' ||\n ['ExpiredToken', 'InvalidToken'].includes(err.error))\n ) {\n // failed due to a bad refresh token\n this.session = undefined\n this.persistSession?.('expired', undefined)\n } else {\n // Assume the problem is transient and the session can be reused later.\n this.session = session\n this.persistSession?.('network-error', session)\n }\n }\n\n throw err\n }\n }\n\n /**\n * Helper to update the pds endpoint dynamically.\n *\n * The session methods (create, resume, refresh) may respond with the user's\n * did document which contains the user's canonical PDS endpoint. That endpoint\n * may differ from the endpoint used to contact the server. We capture that\n * PDS endpoint and update the client to use that given endpoint for future\n * requests. (This helps ensure smooth migrations between PDSes, especially\n * when the PDSes are operated by a single org.)\n */\n private _updateApiEndpoint(didDoc: unknown) {\n const endpoint = isValidDidDoc(didDoc) ? getPdsEndpoint(didDoc) : undefined\n if (endpoint) {\n this.pdsUrl = new URL(endpoint)\n } else {\n // If the did doc is invalid (or missing), we clear the pdsUrl (should\n // never happen). This is fine if the auth server and PDS are the same\n // service, or if the auth server will proxy requests to the right PDS\n // (which is the case for Bluesky's \"entryway\").\n this.pdsUrl = undefined\n }\n }\n}\n\nfunction isErrorObject(v: unknown): v is ErrorResponseBody {\n return errorResponseBody.safeParse(v).success\n}\n\nasync function isErrorResponse(\n response: Response,\n status: number[],\n errorNames: string[],\n): Promise<boolean> {\n if (!status.includes(response.status)) return false\n // Some engines (react-native 👀) don't expose a response.body property...\n // if (!response.body) return false\n try {\n const json = await peekJson(response, 10 * 1024)\n return isErrorObject(json) && (errorNames as any[]).includes(json.error)\n } catch (err) {\n return false\n }\n}\n\nasync function peekJson(\n response: Response,\n maxSize = Infinity,\n): Promise<unknown> {\n if (extractType(response) !== 'application/json') throw new Error('Not JSON')\n if (extractLength(response) > maxSize) throw new Error('Response too large')\n return response.clone().json()\n}\n\nfunction extractLength({ headers }: Response) {\n return headers.get('Content-Length')\n ? Number(headers.get('Content-Length'))\n : NaN\n}\n\nfunction extractType({ headers }: Response) {\n return headers.get('Content-Type')?.split(';')[0]?.trim()\n}\n"]}
|