+41
-17
src/components/GuestbookEntries.tsx
+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