fix: query all 3 Nostr relays in parallel, pick latest profile (BUG-F8)

fetchNostrProfile now uses Promise.allSettled to query all relays
concurrently. Aggregates results with latest-created_at-wins strategy
instead of stopping at the first relay that responds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-13 00:10:11 +00:00
co-authored by Claude Opus 4.6
parent c288b23c13
commit 8b72bef22e
+26 -16
View File
@@ -581,26 +581,33 @@ async function fetchNostrProfilePic(pk: string): Promise<string | null> {
return profile?.picture || null
}
/** Fetch full Nostr profile (kind:0 metadata) with caching */
/** Fetch full Nostr profile (kind:0 metadata) with caching.
* Queries all relays in parallel, picks result with latest created_at. */
async function fetchNostrProfile(pk: string): Promise<NostrProfile | null> {
const cached = profileCache.get(pk)
if (cached && Date.now() - cached.ts < PROFILE_TTL) return cached.data
for (const relay of RELAYS) {
try {
const profile = await queryRelayProfile(relay, pk)
if (profile) {
profileCache.set(pk, { data: profile, ts: Date.now() })
return profile
}
} catch {
continue
const results = await Promise.allSettled(
RELAYS.map(relay => queryRelayProfile(relay, pk))
)
// Pick the profile with the latest created_at (newest wins)
let best: { profile: NostrProfile; createdAt: number } | null = null
for (const r of results) {
if (r.status !== 'fulfilled' || !r.value) continue
if (!best || r.value.createdAt > best.createdAt) {
best = r.value
}
}
if (best) {
profileCache.set(pk, { data: best.profile, ts: Date.now() })
return best.profile
}
return null
}
function queryRelayProfile(url: string, pk: string): Promise<NostrProfile | null> {
function queryRelayProfile(url: string, pk: string): Promise<{ profile: NostrProfile; createdAt: number } | null> {
return new Promise((resolve) => {
let timedOut = false
const timeout = setTimeout(() => {
@@ -625,11 +632,14 @@ function queryRelayProfile(url: string, pk: string): Promise<NostrProfile | null
clearTimeout(timeout)
ws.close()
resolve({
displayName: meta.display_name || meta.name || null,
about: meta.about || null,
picture: meta.picture || null,
banner: meta.banner || null,
nip05: meta.nip05 || null,
profile: {
displayName: meta.display_name || meta.name || null,
about: meta.about || null,
picture: meta.picture || null,
banner: meta.banner || null,
nip05: meta.nip05 || null,
},
createdAt: data[2].created_at || 0,
})
} else if (data[0] === 'EOSE') {
clearTimeout(timeout)