getProfiles

nekomimi.pet 9ee5ecf1 145279c6

verified
Changed files
+41 -17
src
+41 -17
src/components/GuestbookEntries.tsx
··· 61 61 } 62 62 63 63 const fetchedEntries: GuestbookEntry[] = [] 64 + const recordMap = new Map<string, any>() 65 + const authorDids: string[] = [] 64 66 67 + // First pass: fetch all records and collect author DIDs 65 68 for (const record of data.records as ConstellationRecord[]) { 66 69 try { 67 70 const recordUrl = new URL('/xrpc/com.atproto.repo.getRecord', 'https://slingshot.wisp.place') ··· 79 82 recordData.value.$type === 'pet.nkp.guestbook.sign' && 80 83 typeof recordData.value.message === 'string' 81 84 ) { 82 - let authorHandle: string | undefined 83 - try { 84 - const profileResponse = await fetch( 85 - `https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${record.did}` 86 - ) 87 - if (profileResponse.ok) { 88 - const profileData = await profileResponse.json() 89 - authorHandle = profileData.handle 90 - } 91 - } catch {} 85 + recordMap.set(record.did, recordData) 86 + authorDids.push(record.did) 87 + } 88 + } catch {} 89 + } 92 90 93 - fetchedEntries.push({ 94 - uri: recordData.uri, 95 - author: record.did, 96 - authorHandle, 97 - message: recordData.value.message, 98 - createdAt: recordData.value.createdAt, 99 - }) 91 + // Second pass: batch fetch all profiles at once 92 + const authorHandles = new Map<string, string>() 93 + if (authorDids.length > 0) { 94 + try { 95 + // Batch fetch profiles up to 25 at a time (API limit) 96 + for (let i = 0; i < authorDids.length; i += 25) { 97 + const batch = authorDids.slice(i, i + 25) 98 + const profileUrl = new URL('/xrpc/app.bsky.actor.getProfiles', 'https://public.api.bsky.app') 99 + batch.forEach(did => profileUrl.searchParams.append('actors', did)) 100 + 101 + const profileResponse = await fetch(profileUrl.toString()) 102 + if (profileResponse.ok) { 103 + const profilesData = await profileResponse.json() 104 + if (profilesData.profiles && Array.isArray(profilesData.profiles)) { 105 + profilesData.profiles.forEach((profile: any) => { 106 + if (profile.handle) { 107 + authorHandles.set(profile.did, profile.handle) 108 + } 109 + }) 110 + } 111 + } 100 112 } 101 113 } catch {} 114 + } 115 + 116 + // Third pass: create entries with fetched profile data 117 + for (const [did, recordData] of recordMap) { 118 + const authorHandle = authorHandles.get(did) 119 + fetchedEntries.push({ 120 + uri: recordData.uri, 121 + author: did, 122 + authorHandle, 123 + message: recordData.value.message, 124 + createdAt: recordData.value.createdAt, 125 + }) 102 126 } 103 127 104 128 // Sort by date, newest first