mirror of
https://github.com/hoornet/vega.git
synced 2026-05-07 04:39:12 -07:00
Add live feed subscription, timeouts on all relay fetches
Global feed now uses a persistent live subscription (closeOnEose: false) so new notes stream in real-time instead of requiring manual refresh. Inspired by Wisp's streaming architecture. Every fetchEvents call across the entire codebase now uses fetchWithTimeout with groupable: false — prevents NDK from batching/reusing stale subscriptions. This fixes Articles, DMs, Notifications, Zaps, and Trending hanging indefinitely. Also adds since filters on global (2h) and follow (24h) feeds to ensure relay freshness, and fixes ArticleFeed re-fetch bug where follows changes wiped latest tab results.
This commit is contained in:
@@ -14,14 +14,20 @@ export function ArticleFeed() {
|
||||
const [articles, setArticles] = useState<NDKEvent[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
// Track follows length to avoid re-fetching latest when follows change
|
||||
const followsKey = tab === "following" ? follows.join(",") : "latest";
|
||||
|
||||
useEffect(() => {
|
||||
if (tab === "following" && follows.length === 0) return;
|
||||
let cancelled = false;
|
||||
setLoading(true);
|
||||
const authors = tab === "following" ? follows : undefined;
|
||||
fetchArticleFeed(40, authors)
|
||||
.then(setArticles)
|
||||
.catch(() => setArticles([]))
|
||||
.finally(() => setLoading(false));
|
||||
}, [tab, follows]);
|
||||
.then((result) => { if (!cancelled) setArticles(result); })
|
||||
.catch(() => { if (!cancelled) setArticles([]); })
|
||||
.finally(() => { if (!cancelled) setLoading(false); });
|
||||
return () => { cancelled = true; };
|
||||
}, [followsKey]);
|
||||
|
||||
return (
|
||||
<div className="h-full flex flex-col">
|
||||
|
||||
@@ -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 } from "../../lib/nostr";
|
||||
import { getNDK, fetchNoteById, ensureConnected } from "../../lib/nostr";
|
||||
import { getParentEventId } from "../../lib/threadTree";
|
||||
import { NoteContent } from "./NoteContent";
|
||||
import { NoteActions, LoggedOutStats } from "./NoteActions";
|
||||
@@ -132,6 +132,7 @@ export function NoteCard({ event, focused, onReplyInThread }: NoteCardProps) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
await ensureConnected();
|
||||
const parent = await fetchNoteById(parentEventId);
|
||||
if (parent) openThread(parent);
|
||||
}}
|
||||
|
||||
@@ -107,11 +107,11 @@ export function ZapHistoryView() {
|
||||
const [tab, setTab] = useState<Tab>("received");
|
||||
const [received, setReceived] = useState<NDKEvent[]>([]);
|
||||
const [sent, setSent] = useState<NDKEvent[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!pubkey) return;
|
||||
if (!pubkey) { setLoading(false); return; }
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
Promise.all([
|
||||
|
||||
Reference in New Issue
Block a user