import { type NostrEvent, type NostrMetadata, NSchema as n } from '@nostrify/nostrify'; import { useNostr } from '@nostrify/react'; import { useQuery } from '@tanstack/react-query'; // Fallback relays for profile aggregation — global indexers const FALLBACK_RELAYS = [ 'wss://purplepag.es', 'wss://relay.nostr.band', 'wss://nos.lol', 'wss://relay.damus.io', ]; export function useAuthor(pubkey: string | undefined) { const { nostr } = useNostr(); return useQuery<{ event?: NostrEvent; metadata?: NostrMetadata }>({ queryKey: ['author', pubkey ?? ''], queryFn: async ({ signal }) => { if (!pubkey) { return {}; } const querySignal = AbortSignal.any([signal, AbortSignal.timeout(15000)]); try { // Try main relays first let [event] = await nostr.query( [{ kinds: [0], authors: [pubkey], limit: 1 }], { signal: querySignal }, ); // If not found, try fallback profile aggregator relays if (!event) { try { const fallbackGroup = nostr.group(FALLBACK_RELAYS); [event] = await fallbackGroup.query( [{ kinds: [0], authors: [pubkey], limit: 1 }], { signal: AbortSignal.timeout(5000) }, ); } catch { // Fallback failed, continue with no event } } if (!event) { // No profile found - this is okay, user may not have published one yet return {}; } try { const metadata = n.json().pipe(n.metadata()).parse(event.content); return { metadata, event }; } catch { return { event }; } } catch (error) { // Network error or timeout - return empty to avoid breaking the UI console.warn('[useAuthor] Failed to fetch profile for', pubkey?.slice(0, 8), error); return {}; } }, staleTime: 60 * 1000, // 1 minute — allows NostrSync to invalidate and refetch quickly retry: 5, retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 10000), }); }