This repository has no description
0

Configure Feed

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

semble / src / modules / atproto / infrastructure / services / ATProtoAgentService.ts
3.6 kB 106 lines
1import { AtpAgent, Agent } from '@atproto/api'; 2import { NodeOAuthClient } from '@atproto/oauth-client-node'; 3import { Result, ok, err } from 'src/shared/core/Result'; 4import { IAgentService } from '../../application/IAgentService'; 5import { DID } from '../../domain/DID'; 6import { IAppPasswordSessionService } from '../../application/IAppPasswordSessionService'; 7import { ATPROTO_SERVICE_ENDPOINTS } from './ServiceEndpoints'; 8import { AuthenticationError } from 'src/shared/core/AuthenticationError'; 9 10export class ATProtoAgentService implements IAgentService { 11 constructor( 12 private readonly oauthClient: NodeOAuthClient, 13 private readonly appPasswordSessionService: IAppPasswordSessionService, 14 ) {} 15 getUnauthenticatedAgent(): Result<Agent, Error> { 16 return ok( 17 new Agent({ 18 service: ATPROTO_SERVICE_ENDPOINTS.UNAUTHENTICATED_BSKY_SERVICE, 19 }), 20 ); 21 } 22 async getAuthenticatedAgent(did: DID): Promise<Result<Agent, Error>> { 23 const oauthAgentResult = 24 await this.getAuthenticatedAgentByOAuthSession(did); 25 if (oauthAgentResult.isErr()) { 26 // If OAuth session fails, try App Password session 27 const appPasswordAgentResult = 28 await this.getAuthenticatedAgentByAppPasswordSession(did); 29 if (appPasswordAgentResult.isErr()) { 30 return err( 31 new AuthenticationError( 32 `Failed to authenticate: No valid OAuth or App Password session found. OAuth error: ${oauthAgentResult.error.message}. App Password error: ${appPasswordAgentResult.error.message}`, 33 ), 34 ); 35 } 36 return appPasswordAgentResult; 37 } 38 return oauthAgentResult; 39 } 40 async getAuthenticatedAgentByOAuthSession( 41 did: DID, 42 ): Promise<Result<Agent, Error>> { 43 try { 44 // Try to restore the session for the DID 45 const oauthSession = await this.oauthClient.restore(did.value); 46 47 // If we have a session, create and return an Agent 48 if (oauthSession) { 49 return ok(new Agent(oauthSession)); 50 } 51 52 // No session found 53 throw new AuthenticationError( 54 'No OAuth session found for the provided DID', 55 ); 56 } catch (error) { 57 return err( 58 new AuthenticationError( 59 `OAuth authentication failed: ${error instanceof Error ? error.message : String(error)}`, 60 ), 61 ); 62 } 63 } 64 async getAuthenticatedAgentByAppPasswordSession( 65 did: DID, 66 ): Promise<Result<Agent, Error>> { 67 try { 68 // Try to restore the session for the DID 69 const appPasswordSessionResult = 70 await this.appPasswordSessionService.getSession(did.value); 71 72 if (appPasswordSessionResult.isErr()) { 73 return err( 74 new AuthenticationError( 75 `App Password session failed: ${appPasswordSessionResult.error.message}`, 76 ), 77 ); 78 } 79 80 const session = appPasswordSessionResult.value; 81 if (session) { 82 // Create an Agent with the session 83 const agent = new AtpAgent({ 84 service: ATPROTO_SERVICE_ENDPOINTS.AUTHENTICATED_BSKY_SERVICE, 85 }); 86 87 // Resume the session 88 await agent.resumeSession(session); 89 90 // Return the authenticated agent 91 return ok(agent); 92 } 93 94 // No session found 95 throw new AuthenticationError( 96 'No App Password session found for the provided DID', 97 ); 98 } catch (error) { 99 return err( 100 new AuthenticationError( 101 `App Password authentication failed: ${error instanceof Error ? error.message : String(error)}`, 102 ), 103 ); 104 } 105 } 106}