A social knowledge tool for researchers built on ATProto
1import { UseCase } from 'src/shared/core/UseCase';
2import { ICardQueryRepository } from '../../../domain/ICardQueryRepository';
3import { IProfileService } from '../../../domain/services/IProfileService';
4import { err, ok, Result } from 'src/shared/core/Result';
5
6export interface GetLibrariesForCardQuery {
7 cardId: string;
8}
9
10export interface LibraryUserDTO {
11 id: string;
12 name: string;
13 handle: string;
14 avatarUrl?: string;
15}
16
17export interface GetLibrariesForCardResult {
18 cardId: string;
19 users: LibraryUserDTO[];
20 totalCount: number;
21}
22
23export class ValidationError extends Error {
24 constructor(message: string) {
25 super(message);
26 this.name = 'ValidationError';
27 }
28}
29
30export class GetLibrariesForCardUseCase
31 implements
32 UseCase<GetLibrariesForCardQuery, Result<GetLibrariesForCardResult>>
33{
34 constructor(
35 private cardQueryRepo: ICardQueryRepository,
36 private profileService: IProfileService,
37 ) {}
38
39 async execute(
40 query: GetLibrariesForCardQuery,
41 ): Promise<Result<GetLibrariesForCardResult>> {
42 // Validate card ID
43 if (!query.cardId || query.cardId.trim().length === 0) {
44 return err(new ValidationError('Card ID is required'));
45 }
46
47 try {
48 // Get user IDs who have this card in their library
49 const userIds = await this.cardQueryRepo.getLibrariesForCard(
50 query.cardId,
51 );
52
53 // Fetch profiles for all users
54 const profilePromises = userIds.map((userId) =>
55 this.profileService.getProfile(userId),
56 );
57
58 const profileResults = await Promise.all(profilePromises);
59
60 // Filter out failed profile fetches and transform to DTOs
61 const users: LibraryUserDTO[] = [];
62 const errors: string[] = [];
63
64 for (let i = 0; i < profileResults.length; i++) {
65 const result = profileResults[i];
66 if (!result) {
67 errors.push(`No profile found for user ${userIds[i]}`);
68 continue;
69 }
70 if (result.isOk()) {
71 const profile = result.value;
72 users.push({
73 id: profile.id,
74 name: profile.name,
75 handle: profile.handle,
76 avatarUrl: profile.avatarUrl,
77 });
78 } else {
79 errors.push(
80 `Failed to fetch profile for user ${userIds[i]}: ${result.error.message}`,
81 );
82 }
83 }
84
85 // Log errors but don't fail the entire operation
86 if (errors.length > 0) {
87 console.warn('Some profile fetches failed:', errors);
88 }
89
90 return ok({
91 cardId: query.cardId,
92 users,
93 totalCount: users.length,
94 });
95 } catch (error) {
96 return err(
97 new Error(
98 `Failed to get libraries for card: ${error instanceof Error ? error.message : 'Unknown error'}`,
99 ),
100 );
101 }
102 }
103}