A social knowledge tool for researchers built on ATProto
at development 3.6 kB view raw
1import { err, ok, Result } from 'src/shared/core/Result'; 2import { IAppPasswordSessionRepository } from '../repositories/IAppPasswordSessionRepository'; 3import { AtpAgent, AtpSessionData } from '@atproto/api'; 4import { IAppPasswordSessionService } from '../../application/IAppPasswordSessionService'; 5import { ATPROTO_SERVICE_ENDPOINTS } from './ServiceEndpoints'; 6 7export class AppPasswordSessionService implements IAppPasswordSessionService { 8 constructor( 9 private readonly appPasswordSessionRepository: IAppPasswordSessionRepository, 10 ) {} 11 async getSession(did: string): Promise<Result<AtpSessionData>> { 12 const sessionResult = 13 await this.appPasswordSessionRepository.getSession(did); 14 if (sessionResult.isErr()) { 15 return err(sessionResult.error); 16 } 17 const agent = new AtpAgent({ 18 service: ATPROTO_SERVICE_ENDPOINTS.AUTHENTICATED_BSKY_SERVICE, 19 }); 20 21 const sessionWithAppPassword = sessionResult.value; 22 if (!sessionWithAppPassword) { 23 return err(new Error(`No session found for DID: ${did}`)); 24 } 25 try { 26 await agent.resumeSession(sessionResult.value.session); 27 const session = agent.session; 28 if (!session) { 29 return err(new Error(`Failed to resume session for DID: ${did}`)); 30 } 31 return ok(session); 32 } catch (error) { 33 try { 34 await agent.login({ 35 identifier: sessionWithAppPassword.session.did, 36 password: sessionWithAppPassword.appPassword, 37 }); 38 const updatedSession = agent.session; 39 if (!updatedSession) { 40 return err( 41 new Error(`Failed to login with app password for DID: ${did}`), 42 ); 43 } 44 const saveResult = await this.appPasswordSessionRepository.saveSession( 45 did, 46 { 47 session: updatedSession, 48 appPassword: sessionWithAppPassword.appPassword, 49 }, 50 ); 51 if (saveResult.isErr()) { 52 return err( 53 new Error( 54 `Failed to save session after login for DID: ${did}, error: ${saveResult.error.message}`, 55 ), 56 ); 57 } 58 return ok(updatedSession); 59 } catch (error) { 60 return err( 61 new Error( 62 `Failed to login with app password for DID: ${did}, error: ${ 63 error instanceof Error ? error.message : String(error) 64 }`, 65 ), 66 ); 67 } 68 } 69 } 70 async createSession( 71 identifier: string, 72 appPassword: string, 73 ): Promise<Result<AtpSessionData>> { 74 const agent = new AtpAgent({ 75 service: ATPROTO_SERVICE_ENDPOINTS.AUTHENTICATED_BSKY_SERVICE, 76 }); 77 78 try { 79 await agent.login({ 80 identifier, 81 password: appPassword, 82 }); 83 const session = agent.session; 84 if (!session) { 85 return err( 86 new Error(`Failed to create session for identifier: ${identifier}`), 87 ); 88 } 89 const saveResult = await this.appPasswordSessionRepository.saveSession( 90 session.did, 91 { session, appPassword }, 92 ); 93 if (saveResult.isErr()) { 94 return err( 95 new Error( 96 `Failed to save session after login for identifier: ${identifier}, error: ${saveResult.error.message}`, 97 ), 98 ); 99 } 100 return ok(session); 101 } catch (error) { 102 return err( 103 new Error( 104 `Failed to create session for identifier: ${identifier}, error: ${ 105 error instanceof Error ? error.message : String(error) 106 }`, 107 ), 108 ); 109 } 110 } 111}