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:
co-authored by
Claude Opus 4.6
parent
c288b23c13
commit
8b72bef22e
@@ -581,26 +581,33 @@ async function fetchNostrProfilePic(pk: string): Promise<string | null> {
|
|||||||
return profile?.picture || 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> {
|
async function fetchNostrProfile(pk: string): Promise<NostrProfile | null> {
|
||||||
const cached = profileCache.get(pk)
|
const cached = profileCache.get(pk)
|
||||||
if (cached && Date.now() - cached.ts < PROFILE_TTL) return cached.data
|
if (cached && Date.now() - cached.ts < PROFILE_TTL) return cached.data
|
||||||
|
|
||||||
for (const relay of RELAYS) {
|
const results = await Promise.allSettled(
|
||||||
try {
|
RELAYS.map(relay => queryRelayProfile(relay, pk))
|
||||||
const profile = await queryRelayProfile(relay, pk)
|
)
|
||||||
if (profile) {
|
|
||||||
profileCache.set(pk, { data: profile, ts: Date.now() })
|
// Pick the profile with the latest created_at (newest wins)
|
||||||
return profile
|
let best: { profile: NostrProfile; createdAt: number } | null = null
|
||||||
}
|
for (const r of results) {
|
||||||
} catch {
|
if (r.status !== 'fulfilled' || !r.value) continue
|
||||||
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
|
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) => {
|
return new Promise((resolve) => {
|
||||||
let timedOut = false
|
let timedOut = false
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
@@ -625,11 +632,14 @@ function queryRelayProfile(url: string, pk: string): Promise<NostrProfile | null
|
|||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
ws.close()
|
ws.close()
|
||||||
resolve({
|
resolve({
|
||||||
displayName: meta.display_name || meta.name || null,
|
profile: {
|
||||||
about: meta.about || null,
|
displayName: meta.display_name || meta.name || null,
|
||||||
picture: meta.picture || null,
|
about: meta.about || null,
|
||||||
banner: meta.banner || null,
|
picture: meta.picture || null,
|
||||||
nip05: meta.nip05 || null,
|
banner: meta.banner || null,
|
||||||
|
nip05: meta.nip05 || null,
|
||||||
|
},
|
||||||
|
createdAt: data[2].created_at || 0,
|
||||||
})
|
})
|
||||||
} else if (data[0] === 'EOSE') {
|
} else if (data[0] === 'EOSE') {
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
|
|||||||
Reference in New Issue
Block a user