From d13a7016a298f1f3129212068fc5935a047b5f8e Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Sun, 31 May 2026 21:49:08 -0400 Subject: [PATCH] =?UTF-8?q?Linked=20Designs:=20Credits=20=E2=80=94=20broad?= =?UTF-8?q?en=20profile=20lookup=20to=20relay=20union?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hydrator was relying on populateCommunityProfiles, which only queries state.community.relays. Linked-design contributors are arbitrary pubkeys whose kind-0 metadata typically lives on the popular default relays (damus, nos.lol, primal, nostr.band), not necessarily on the host author's narrow relay list — so the lookup silently came back empty and the UI fell back to short-pubkey labels. Switch to the same _vaultRelayUnion() the linked-design resolver already uses (user relays ∪ DEFAULT_NOSTR_RELAYS). Pick the latest kind-0 per pubkey when multiple relays return different versions. Write into both state.community.profiles and _feedCache.profiles so all downstream profile-display surfaces (including the existing "by Author" link in the preview header) benefit from the fetch. --- src/index.html | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/index.html b/src/index.html index b05c1e4..0b19ae4 100644 --- a/src/index.html +++ b/src/index.html @@ -6758,7 +6758,8 @@ // collectLinkedCredits walker only knows pubkeys (parsed from // the address coord) — display names come from kind-0 events // that aren't always cached. Fetch any uncached contributors - // in the background, then call onUpdate so callers can rebuild + // in the background using the same user-relay-∪-defaults union + // the resolver uses, then call onUpdate so callers can rebuild // their UI with the freshly-resolved names. Per-pubkey inflight // tracking prevents duplicate relay round-trips when render() // fires repeatedly during the same fetch. @@ -6774,7 +6775,29 @@ if (!uncached.length) return; for (const pk of uncached) _creditsProfileInflight.add(pk); try { - await populateCommunityProfiles(uncached); + const relays = typeof _vaultRelayUnion === 'function' + ? _vaultRelayUnion() + : splitRelayList(state.community?.relays || ''); + const events = await queryRelays( + relays, + { kinds: [0], authors: uncached }, + { timeoutMs: 3500 } + ); + // Keep the latest kind-0 per pubkey when multiple relays + // return different versions. + const latestByPk = new Map(); + for (const ev of (events || [])) { + const prev = latestByPk.get(ev.pubkey); + if (!prev || (ev.created_at || 0) > (prev.created_at || 0)) { + latestByPk.set(ev.pubkey, ev); + } + } + for (const [pk, ev] of latestByPk) { + const parsed = safeJsonParse(ev.content, {}) || {}; + const profile = { pubkey: pk, ...parsed, created_at: ev.created_at }; + if (state.community?.profiles) state.community.profiles[pk] = profile; + if (_feedCache?.profiles) _feedCache.profiles[pk] = profile; + } } catch (err) { console.warn('[credits] profile fetch failed', err); } finally {