From cb819e811f16b4ca77b5dda5e94fc0487a18625f Mon Sep 17 00:00:00 2001 From: "shakespeare.diy" Date: Wed, 18 Feb 2026 15:39:11 -0600 Subject: [PATCH] Use app relays for loser's race instead of separate profile relays - Removed hardcoded PROFILE_RELAYS list - Loser's race now queries the same relays as the pool - Gets effective relays from app config (user relays + app relays) - Queries each relay individually with 5000ms timeout (vs 500ms EOSE in pool) - Solves issue where profiles exist on app relays (like nos.lol) but not on hardcoded profile relays - Now covers all relays user has configured instead of arbitrary subset Co-authored-by: shakespeare.diy --- src/hooks/useAuthor.ts | 26 ++++++++++++++------------ src/hooks/useAuthors.ts | 21 ++++++++++++++------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/hooks/useAuthor.ts b/src/hooks/useAuthor.ts index bbc07c86..ed3066d0 100644 --- a/src/hooks/useAuthor.ts +++ b/src/hooks/useAuthor.ts @@ -1,15 +1,8 @@ import { type NostrEvent, type NostrMetadata, NSchema as n } from '@nostrify/nostrify'; import { useNostr } from '@nostrify/react'; import { useQuery } from '@tanstack/react-query'; - -/** Profile relay URLs used as fallback when the pool's EOSE timeout returns empty. */ -export const PROFILE_RELAYS = [ - 'wss://relay.primal.net', - 'wss://relay.damus.io', - 'wss://relay.ditto.pub', - 'wss://ditto.pub/relay', - 'wss://purplepag.es', -]; +import { useAppContext } from '@/hooks/useAppContext'; +import { getEffectiveRelays } from '@/lib/appRelays'; /** Parse a kind-0 event into metadata + event, or return just the event on parse failure. */ export function parseAuthorEvent(event: NostrEvent): { event: NostrEvent; metadata?: NostrMetadata } { @@ -23,6 +16,11 @@ export function parseAuthorEvent(event: NostrEvent): { event: NostrEvent; metada export function useAuthor(pubkey: string | undefined) { const { nostr } = useNostr(); + const { config } = useAppContext(); + + // Get the effective relays (same ones used by the pool) + const effectiveRelays = getEffectiveRelays(config.relayMetadata, config.useAppRelays); + const readRelayUrls = effectiveRelays.relays.filter(r => r.read).map(r => r.url); return useQuery<{ event?: NostrEvent; metadata?: NostrMetadata }>({ queryKey: ['author', pubkey ?? ''], @@ -44,12 +42,16 @@ export function useAuthor(pubkey: string | undefined) { } // Slow path: pool returned empty (EOSE timeout may have cut off slower relays). - // Query each relay individually and resolve on first hit. + // Query each relay individually (same relays as pool, but with more time). + if (readRelayUrls.length === 0) { + return {}; + } + return new Promise<{ event?: NostrEvent; metadata?: NostrMetadata }>((resolve) => { let settled = false; - let pending = PROFILE_RELAYS.length; + let pending = readRelayUrls.length; - for (const url of PROFILE_RELAYS) { + for (const url of readRelayUrls) { nostr.relay(url).query( [{ kinds: [0], authors: [pubkey!], limit: 1 }], { signal: combinedSignal }, diff --git a/src/hooks/useAuthors.ts b/src/hooks/useAuthors.ts index 8a981f82..dd41dbf3 100644 --- a/src/hooks/useAuthors.ts +++ b/src/hooks/useAuthors.ts @@ -1,7 +1,9 @@ import { type NostrEvent, type NostrMetadata } from '@nostrify/nostrify'; import { useNostr } from '@nostrify/react'; import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { parseAuthorEvent, PROFILE_RELAYS } from '@/hooks/useAuthor'; +import { parseAuthorEvent } from '@/hooks/useAuthor'; +import { useAppContext } from '@/hooks/useAppContext'; +import { getEffectiveRelays } from '@/lib/appRelays'; export interface AuthorData { pubkey: string; @@ -21,6 +23,11 @@ export interface AuthorData { export function useAuthors(pubkeys: string[]) { const { nostr } = useNostr(); const queryClient = useQueryClient(); + const { config } = useAppContext(); + + // Get the effective relays (same ones used by the pool) + const effectiveRelays = getEffectiveRelays(config.relayMetadata, config.useAppRelays); + const readRelayUrls = effectiveRelays.relays.filter(r => r.read).map(r => r.url); // Deduplicate and sort for a stable query key const uniquePubkeys = [...new Set(pubkeys)].sort(); @@ -56,16 +63,16 @@ export function useAuthors(pubkeys: string[]) { found.add(event.pubkey); } - // Slow path: for any pubkeys not found by the pool, query relays individually. - // This is the "loser's race" - we query specific profile relays that may have - // been cut off by the pool's EOSE timeout. + // Slow path: for any pubkeys not found by the pool, query each relay individually. + // This is the "loser's race" - we query the same relays from the pool, but + // individually with more time (5000ms vs 500ms EOSE timeout). const missing = uniquePubkeys.filter(pk => !found.has(pk)); - if (missing.length > 0) { + if (missing.length > 0 && readRelayUrls.length > 0) { await new Promise((resolve) => { const needed = new Set(missing); - let pending = PROFILE_RELAYS.length; + let pending = readRelayUrls.length; - for (const url of PROFILE_RELAYS) { + for (const url of readRelayUrls) { nostr.relay(url).query( [{ kinds: [0], authors: missing, limit: missing.length }], { signal: combinedSignal },