From 01d9df86d318a7c6b0fe51fa4e0bc66fff65ad35 Mon Sep 17 00:00:00 2001 From: "shakespeare.diy" Date: Wed, 18 Feb 2026 10:46:28 -0600 Subject: [PATCH] fix: follow-up grouped query for orphaned authors after first prefetch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First query fires with 1500ms timeout — fast path for most profiles. After it resolves, check which pubkeys still have no cache entry and fire one more grouped query for those orphans with 4000ms timeout. Also handles the case where the first query fails entirely by retrying the full batch. All grouped — never one subscription per pubkey. Co-authored-by: shakespeare.diy --- src/hooks/useFeed.ts | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/hooks/useFeed.ts b/src/hooks/useFeed.ts index 05d78e58..c7f7f59d 100644 --- a/src/hooks/useFeed.ts +++ b/src/hooks/useFeed.ts @@ -81,7 +81,36 @@ export function prefetchFeedData( try { metadata = n.json().pipe(n.metadata()).parse(ev.content); } catch { /* skip */ } seedAuthorCache(queryClient, ev.pubkey, { event: ev, metadata }); } - }).catch(() => {}); + // Follow-up for orphans: pubkeys the first query didn't return within + // the timeout. Retry them in one grouped query under the same conditions. + const orphans = pubkeysToFetch.filter( + (pk) => queryClient.getQueryData(['author', pk]) === undefined, + ); + if (orphans.length > 0) { + nostr.query( + [{ kinds: [0], authors: orphans }], + { signal: AbortSignal.timeout(4000) }, + ).then((retryEvents) => { + for (const ev of retryEvents) { + let metadata: NostrMetadata | undefined; + try { metadata = n.json().pipe(n.metadata()).parse(ev.content); } catch { /* skip */ } + seedAuthorCache(queryClient, ev.pubkey, { event: ev, metadata }); + } + }).catch(() => {}); + } + }).catch(() => { + // First query failed entirely — retry the whole batch with more time. + nostr.query( + [{ kinds: [0], authors: pubkeysToFetch }], + { signal: AbortSignal.timeout(4000) }, + ).then((retryEvents) => { + for (const ev of retryEvents) { + let metadata: NostrMetadata | undefined; + try { metadata = n.json().pipe(n.metadata()).parse(ev.content); } catch { /* skip */ } + seedAuthorCache(queryClient, ev.pubkey, { event: ev, metadata }); + } + }).catch(() => {}); + }); } if (eventIdsToFetch.length > 0) {