Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 140 lines 4.0 kB view raw
1import {Agent, type AtpSessionData} from '@atproto/api' 2import {type OutputSchema} from '@atproto/api/dist/client/types/com/atproto/server/getSession' 3import {type OAuthSession} from '@atproto/oauth-client-browser' 4 5import {BLUESKY_PROXY_HEADER, BSKY_SERVICE} from '#/lib/constants' 6import {logger} from '#/logger' 7import {sessionAccountToSession} from './agent' 8import {configureModerationForAccount} from './moderation' 9import {getWebOAuthClient} from './oauth-web-client' 10import {type SessionAccount} from './types' 11 12export async function oauthCreateAgent(session: OAuthSession) { 13 const agent = new OauthBskyAppAgent(session) 14 const account = await oauthAgentAndSessionToSessionAccountOrThrow( 15 agent, 16 session, 17 ) 18 const gates = Promise.resolve() 19 const moderation = configureModerationForAccount(agent, account) 20 return agent.prepare(account, gates, moderation) 21} 22 23const OAUTH_RESTORE_TIMEOUT_MS = 10_000 24 25export async function oauthResumeSession(account: SessionAccount) { 26 const client = getWebOAuthClient() 27 let session: OAuthSession 28 try { 29 session = await Promise.race([ 30 client.restore(account.did), 31 new Promise<never>((_, reject) => 32 setTimeout( 33 () => reject(new Error('OAuth session restore timed out')), 34 OAUTH_RESTORE_TIMEOUT_MS, 35 ), 36 ), 37 ]) 38 } catch (e) { 39 logger.error('oauthResumeSession: restore failed', { 40 did: account.did, 41 error: e instanceof Error ? e.message : String(e), 42 }) 43 throw e 44 } 45 return await oauthCreateAgent(session) 46} 47 48export async function oauthAgentAndSessionToSessionAccountOrThrow( 49 agent: Agent, 50 session: OAuthSession, 51): Promise<SessionAccount> { 52 const account = await oauthAgentAndSessionToSessionAccount(agent, session) 53 if (!account) { 54 throw Error('Expected an active session') 55 } 56 return account 57} 58 59export async function oauthAgentAndSessionToSessionAccount( 60 agent: Agent, 61 session: OAuthSession, 62): Promise<SessionAccount | undefined> { 63 let data: OutputSchema 64 try { 65 const res = await Promise.race([ 66 agent.com.atproto.server.getSession(), 67 new Promise<never>((_, reject) => 68 setTimeout( 69 () => reject(new Error('getSession timed out')), 70 OAUTH_RESTORE_TIMEOUT_MS, 71 ), 72 ), 73 ]) 74 data = res.data 75 } catch (e: any) { 76 logger.error('oauthAgentAndSessionToSessionAccount: getSession failed', e) 77 return undefined 78 } 79 let aud: string 80 try { 81 const tokenInfo = await Promise.race([ 82 session.getTokenInfo(false), 83 new Promise<never>((_, reject) => 84 setTimeout( 85 () => reject(new Error('getTokenInfo timed out')), 86 OAUTH_RESTORE_TIMEOUT_MS, 87 ), 88 ), 89 ]) 90 aud = tokenInfo.aud 91 } catch (e: any) { 92 logger.error('oauthAgentAndSessionToSessionAccount: getTokenInfo failed', e) 93 return undefined 94 } 95 return { 96 service: session.serverMetadata.issuer, 97 did: session.did, 98 handle: data.handle, 99 email: data.email, 100 emailConfirmed: data.emailConfirmed, 101 emailAuthFactor: data.emailAuthFactor, 102 active: data.active, 103 status: data.status, 104 pdsUrl: aud, 105 isSelfHosted: !session.server.issuer.startsWith(BSKY_SERVICE), 106 isOauthSession: true, 107 } 108} 109 110export class OauthBskyAppAgent extends Agent { 111 session?: AtpSessionData 112 dispatchUrl?: string 113 114 constructor(session: OAuthSession) { 115 super(session) 116 } 117 118 async prepare( 119 account: SessionAccount, 120 gates: Promise<void>, 121 moderation: Promise<void>, 122 ) { 123 this.session = sessionAccountToSession(account) 124 this.dispatchUrl = account.pdsUrl 125 this.configureProxy(BLUESKY_PROXY_HEADER.get()) 126 127 await Promise.all([gates, moderation]) 128 129 return {account, agent: this} 130 } 131 132 dispose() {} 133 134 cloneWithoutProxy(): OauthBskyAppAgent { 135 const cloned = new OauthBskyAppAgent(this.sessionManager as OAuthSession) 136 cloned.session = this.session 137 cloned.configureProxy(null) 138 return cloned 139 } 140}