mirror of
https://github.com/hoornet/vega.git
synced 2026-06-08 14:11:55 -07:00
Fix profile fetch architecture: batch kind-0 queries, restore NDK pooling
This commit is contained in:
@@ -4,7 +4,7 @@ import { useUserStore } from "../../stores/user";
|
||||
import { useMuteStore } from "../../stores/mute";
|
||||
import { useUIStore } from "../../stores/ui";
|
||||
import { useWoTStore } from "../../stores/wot";
|
||||
import { fetchFollowFeed, getNDK, ensureConnected } from "../../lib/nostr";
|
||||
import { fetchFollowFeed, getNDK, ensureConnected, batchFetchProfileAges } from "../../lib/nostr";
|
||||
import { diagWrapFetch, logDiag } from "../../lib/feedDiagnostics";
|
||||
import { detectScript, getEventLanguageTag, FILTER_SCRIPTS } from "../../lib/language";
|
||||
import { NoteCard } from "./NoteCard";
|
||||
@@ -63,7 +63,10 @@ export function Feed() {
|
||||
useEffect(() => {
|
||||
// Show cached notes immediately, then fetch fresh ones once connected
|
||||
loadCachedFeed();
|
||||
connect().then(() => loadFeed());
|
||||
connect().then(() => loadFeed().then(() => {
|
||||
const pubkeys = [...new Set(useFeedStore.getState().notes.map((e) => e.pubkey))];
|
||||
batchFetchProfileAges(pubkeys);
|
||||
}));
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useUserStore } from "../../stores/user";
|
||||
import { useMuteStore } from "../../stores/mute";
|
||||
import { useUIStore } from "../../stores/ui";
|
||||
import { timeAgo, shortenPubkey } from "../../lib/utils";
|
||||
import { getNDK, fetchNoteById, ensureConnected } from "../../lib/nostr";
|
||||
import { getNDK, fetchNoteById, ensureConnected, getProfileAge } from "../../lib/nostr";
|
||||
import { getParentEventId } from "../../lib/threadTree";
|
||||
import { NoteContent } from "./NoteContent";
|
||||
import { NoteActions, LoggedOutStats } from "./NoteActions";
|
||||
@@ -34,7 +34,7 @@ export const NoteCard = memo(function NoteCard({ event, focused, onReplyInThread
|
||||
const nip05 = typeof profile?.nip05 === "string" ? profile.nip05 : null;
|
||||
const verified = useNip05Verified(event.pubkey, nip05);
|
||||
const time = event.created_at ? timeAgo(event.created_at) : "";
|
||||
const profileCreatedAt = typeof profile?._createdAt === "number" ? profile._createdAt : null;
|
||||
const profileCreatedAt = getProfileAge(event.pubkey);
|
||||
const isNewAccount = profileCreatedAt !== null && (Date.now() / 1000 - profileCreatedAt) < 60 * 24 * 3600;
|
||||
|
||||
const loggedIn = useUserStore((s) => s.loggedIn);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useAutoResize } from "../../hooks/useAutoResize";
|
||||
import { useUIStore } from "../../stores/ui";
|
||||
import { useUserStore } from "../../stores/user";
|
||||
import { useMuteStore } from "../../stores/mute";
|
||||
import { fetchNoteById, fetchThreadEvents, fetchAncestors, publishReply, getNDK, ensureConnected } from "../../lib/nostr";
|
||||
import { fetchNoteById, fetchThreadEvents, fetchAncestors, publishReply, getNDK, ensureConnected, batchFetchProfileAges } from "../../lib/nostr";
|
||||
import { buildThreadTree, getRootEventId } from "../../lib/threadTree";
|
||||
import type { ThreadNode } from "../../lib/threadTree";
|
||||
import { debug } from "../../lib/debug";
|
||||
@@ -99,6 +99,7 @@ export function ThreadView() {
|
||||
|
||||
const built = buildThreadTree(root.id, allEvents);
|
||||
setTree(built);
|
||||
batchFetchProfileAges([...new Set(allEvents.map((e) => e.pubkey))]);
|
||||
} catch (err) {
|
||||
debug.error("Failed to load thread:", err);
|
||||
if (!cancelled) setLoadError(`Failed to load: ${err}`);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export { getNDK, getNDKUptimeMs, connectToRelays, ensureConnected, resetNDK, getStoredRelayUrls, normalizeRelayUrl, addRelay, removeRelay, fetchWithTimeout, withTimeout, FEED_TIMEOUT, THREAD_TIMEOUT, SINGLE_TIMEOUT } from "./core";
|
||||
export { fetchGlobalFeed, fetchMediaFeed, fetchFollowFeed, fetchUserNotes, fetchUserNotesNIP65, fetchNoteById, fetchReplies, publishNote, publishReply, publishRepost, publishQuote, fetchHashtagFeed, fetchThreadEvents, fetchAncestors } from "./notes";
|
||||
export { publishProfile, publishContactList, fetchProfile, fetchFollowSuggestions, fetchMentions, fetchFollowers, fetchNewFollowers } from "./social";
|
||||
export { publishProfile, publishContactList, fetchProfile, fetchFollowSuggestions, fetchMentions, fetchFollowers, fetchNewFollowers, batchFetchProfileAges, getProfileAge } from "./social";
|
||||
export { publishArticle, fetchArticle, fetchAuthorArticles, fetchArticleFeed, searchArticles, fetchByAddr } from "./articles";
|
||||
export { publishReaction, fetchReplyCount, fetchZapCount, fetchReactions, groupReactions, fetchBatchEngagement, fetchZapsReceived, fetchZapsSent } from "./engagement";
|
||||
export type { GroupedReactions, BatchEngagement } from "./engagement";
|
||||
|
||||
+20
-8
@@ -33,14 +33,26 @@ export async function publishContactList(pubkeys: string[]): Promise<void> {
|
||||
|
||||
export async function fetchProfile(pubkey: string) {
|
||||
const instance = getNDK();
|
||||
const events = await fetchWithTimeout(instance, { kinds: [0], authors: [pubkey] }, FEED_TIMEOUT);
|
||||
const event = [...events].sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0))[0];
|
||||
if (!event) return null;
|
||||
try {
|
||||
const content = JSON.parse(event.content) as Record<string, unknown>;
|
||||
return { ...content, _createdAt: event.created_at ?? null };
|
||||
} catch {
|
||||
return null;
|
||||
const user = instance.getUser({ pubkey });
|
||||
await user.fetchProfile();
|
||||
return user.profile ?? null;
|
||||
}
|
||||
|
||||
// Bulk-fetch kind-0 events for many pubkeys in one relay query and populate
|
||||
// the profile-age cache. Called once per feed/thread load — not per note.
|
||||
const profileAgeCache = new Map<string, number>();
|
||||
|
||||
export function getProfileAge(pubkey: string): number | null {
|
||||
return profileAgeCache.get(pubkey) ?? null;
|
||||
}
|
||||
|
||||
export async function batchFetchProfileAges(pubkeys: string[]): Promise<void> {
|
||||
const needed = pubkeys.filter((pk) => !profileAgeCache.has(pk));
|
||||
if (needed.length === 0) return;
|
||||
const instance = getNDK();
|
||||
const events = await fetchWithTimeout(instance, { kinds: [0], authors: needed }, FEED_TIMEOUT);
|
||||
for (const event of events) {
|
||||
if (event.created_at) profileAgeCache.set(event.pubkey, event.created_at);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user