This repository has no description
1import { Result, ok, err } from 'src/shared/core/Result';
2import { IAgentService } from '../../application/IAgentService';
3import { DID } from '../../domain/DID';
4import { Agent, AtpAgent } from '@atproto/api';
5import { ATPROTO_SERVICE_ENDPOINTS } from './ServiceEndpoints';
6
7export class FakeAgentService implements IAgentService {
8 getUnauthenticatedAgent(): Result<Agent, Error> {
9 try {
10 // Create a mock agent - in a real implementation this would be a proper Agent instance
11 const mockAgent = {
12 getProfile: async ({ actor }: { actor: string }) => {
13 const mockData = this.getMockDataForUserId(actor);
14 return {
15 success: true,
16 data: {
17 did: actor,
18 handle: mockData.handle,
19 displayName: mockData.name,
20 description: mockData.bio,
21 avatar: mockData.avatarUrl,
22 },
23 };
24 },
25 resolveHandle: async ({ handle }: { handle: string }) => {
26 const mockData = this.getMockDataForHandle(handle);
27 return {
28 success: true,
29 data: {
30 did: mockData.did,
31 },
32 };
33 },
34 } as Agent;
35
36 return ok(mockAgent);
37 } catch (error: any) {
38 return err(error);
39 }
40 }
41
42 async getUnauthenticatedAgentForDid(did: DID): Promise<Result<Agent, Error>> {
43 try {
44 // For the fake service, just return the same mock agent as getUnauthenticatedAgent
45 return this.getUnauthenticatedAgent();
46 } catch (error: any) {
47 return err(error);
48 }
49 }
50
51 async getAuthenticatedAgent(did: DID): Promise<Result<Agent, Error>> {
52 try {
53 // Return the same mock agent for authenticated requests
54 // uncomment the line below to test error handling
55 // throw new Error('Not implemented in FakeAgentService');
56 return this.getUnauthenticatedAgent();
57 } catch (error: any) {
58 return err(error);
59 }
60 }
61
62 async getAuthenticatedServiceAccountAgent(): Promise<Result<Agent, Error>> {
63 try {
64 const serviceAccountIdentifier =
65 process.env.BSKY_SERVICE_ACCOUNT_IDENTIFIER;
66 const serviceAccountAppPassword =
67 process.env.BSKY_SERVICE_ACCOUNT_APP_PASSWORD;
68
69 if (!serviceAccountIdentifier || !serviceAccountAppPassword) {
70 return err(
71 new Error(
72 'Service account credentials not configured. Please set BSKY_SERVICE_ACCOUNT_IDENTIFIER and BSKY_SERVICE_ACCOUNT_APP_PASSWORD environment variables.',
73 ),
74 );
75 }
76
77 const agent = new AtpAgent({
78 service: ATPROTO_SERVICE_ENDPOINTS.AUTHENTICATED_BSKY_SERVICE,
79 });
80
81 await agent.login({
82 identifier: serviceAccountIdentifier,
83 password: serviceAccountAppPassword,
84 });
85
86 return ok(agent);
87 } catch (error: any) {
88 return err(
89 new Error(
90 `Failed to authenticate service account: ${
91 error instanceof Error ? error.message : String(error)
92 }`,
93 ),
94 );
95 }
96 }
97
98 private getMockDataForUserId(userId: string): {
99 name: string;
100 handle: string;
101 avatarUrl: string;
102 bio: string;
103 did: string;
104 bannerUrl: string;
105 } {
106 const did2 = process.env.BSKY_DID_2 || 'did:plc:mock456';
107
108 if (userId === did2) {
109 return {
110 name: 'Mock User Bob',
111 handle: process.env.BSKY_HANDLE_2 || 'bob.bsky.social',
112 avatarUrl:
113 'https://cdn.bsky.app/img/avatar/plain/did:plc:rlknsba2qldjkicxsmni3vyn/bafkreid4nmxspygkftep5b3m2wlcm3xvnwefkswzej7dhipojjxylkzfby@jpeg',
114 bio: 'This is Bob - a second mock profile for testing purposes (https://semble.so/), made by @cosmik.network.',
115 did: did2,
116 bannerUrl:
117 'https://cdn.bsky.app/img/banner/plain/did:plc:rlknsba2qldjkicxsmni3vyn/bafkreicgrrurfx5uicisd4nuqhbgn5pihlth5ssjzyl2egg32rxvjvtory@jpeg',
118 };
119 }
120
121 // Default to account 1
122 const did1 = process.env.BSKY_DID_1 || 'did:plc:mock123';
123 return {
124 name: 'Mock User Alice',
125 handle: process.env.BSKY_HANDLE_1 || 'alice.bsky.social',
126 avatarUrl:
127 'https://cdn.bsky.app/img/avatar/plain/did:plc:rlknsba2qldjkicxsmni3vyn/bafkreid4nmxspygkftep5b3m2wlcm3xvnwefkswzej7dhipojjxylkzfby@jpeg',
128 bio: 'This is Alice - a mock profile for testing purposes (https://semble.so/), made by @cosmik.network.',
129 did: did1,
130 bannerUrl:
131 'https://cdn.bsky.app/img/banner/plain/did:plc:rlknsba2qldjkicxsmni3vyn/bafkreicgrrurfx5uicisd4nuqhbgn5pihlth5ssjzyl2egg32rxvjvtory@jpeg',
132 };
133 }
134
135 private getMockDataForHandle(handle: string): {
136 did: string;
137 handle: string;
138 } {
139 // Check if handle matches account 2
140 const handle2 = process.env.BSKY_HANDLE_2 || 'bob.bsky.social';
141 if (handle === handle2 || handle.includes('bob')) {
142 return {
143 did: process.env.BSKY_DID_2 || 'did:plc:mock456',
144 handle: handle2,
145 };
146 }
147
148 // Default to account 1
149 return {
150 did: process.env.BSKY_DID_1 || 'did:plc:mock123',
151 handle: process.env.BSKY_HANDLE_1 || 'alice.bsky.social',
152 };
153 }
154}