mirror of
https://github.com/hoornet/vega.git
synced 2026-05-07 20:59:12 -07:00
Bump to v0.2.0 — Phase 2: Engagement & Reach
Four features shipped in this release: - Feed reply context: replies show "↩ replying to @name" above the note content; clicking fetches and opens the parent thread - NIP-65 outbox model: fetchUserRelayList + publishRelayList + fetchUserNotesNIP65 in client.ts; profile notes fetched via the author's write relays; "Publish relay list to Nostr" button in Settings (kind 10002) - Notifications: new store (notifications.ts) + NotificationsView; 🔔 sidebar nav item with unread badge; DM nav item also shows unread conversation count; badges clear on open/select - Keyboard shortcuts: useKeyboardShortcuts hook + HelpModal; n=compose, /=search, j/k=feed nav with ring highlight, Esc=back, ?=help overlay Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import NDK, { NDKEvent, NDKFilter, NDKKind, NDKRelay, NDKSubscriptionCacheUsage, nip19 } from "@nostr-dev-kit/ndk";
|
||||
import NDK, { NDKEvent, NDKFilter, NDKKind, NDKRelay, NDKRelaySet, NDKSubscriptionCacheUsage, nip19 } from "@nostr-dev-kit/ndk";
|
||||
|
||||
const RELAY_STORAGE_KEY = "wrystr_relays";
|
||||
|
||||
@@ -469,3 +469,59 @@ export async function fetchProfile(pubkey: string) {
|
||||
await user.fetchProfile();
|
||||
return user.profile;
|
||||
}
|
||||
|
||||
// ── NIP-65 Relay Lists ────────────────────────────────────────────────────────
|
||||
|
||||
export interface UserRelayList { read: string[]; write: string[]; }
|
||||
|
||||
export async function fetchUserRelayList(pubkey: string): Promise<UserRelayList> {
|
||||
const instance = getNDK();
|
||||
const filter: NDKFilter = { kinds: [10002 as NDKKind], authors: [pubkey], limit: 1 };
|
||||
const events = await instance.fetchEvents(filter, { cacheUsage: NDKSubscriptionCacheUsage.ONLY_RELAY });
|
||||
if (events.size === 0) return { read: [], write: [] };
|
||||
const event = Array.from(events).sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0))[0];
|
||||
const read: string[] = [], write: string[] = [];
|
||||
for (const tag of event.tags) {
|
||||
if (tag[0] !== "r" || !tag[1]) continue;
|
||||
const marker = tag[2];
|
||||
if (!marker || marker === "read") read.push(tag[1]);
|
||||
if (!marker || marker === "write") write.push(tag[1]);
|
||||
}
|
||||
return { read, write };
|
||||
}
|
||||
|
||||
export async function publishRelayList(relayUrls: string[]): Promise<void> {
|
||||
const instance = getNDK();
|
||||
if (!instance.signer) throw new Error("Not logged in");
|
||||
const event = new NDKEvent(instance);
|
||||
event.kind = 10002 as NDKKind;
|
||||
event.content = "";
|
||||
event.tags = relayUrls.map((url) => ["r", url]);
|
||||
await event.publish();
|
||||
}
|
||||
|
||||
export async function fetchUserNotesNIP65(pubkey: string, limit = 30): Promise<NDKEvent[]> {
|
||||
const instance = getNDK();
|
||||
const filter: NDKFilter = { kinds: [NDKKind.Text], authors: [pubkey], limit };
|
||||
try {
|
||||
const relayList = await fetchUserRelayList(pubkey);
|
||||
if (relayList.write.length > 0) {
|
||||
const merged = Array.from(new Set([...relayList.write, ...getStoredRelayUrls()]));
|
||||
const relaySet = NDKRelaySet.fromRelayUrls(merged, instance);
|
||||
const events = await instance.fetchEvents(filter, { cacheUsage: NDKSubscriptionCacheUsage.ONLY_RELAY }, relaySet);
|
||||
return Array.from(events).sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0));
|
||||
}
|
||||
} catch { /* fallthrough */ }
|
||||
return fetchUserNotes(pubkey, limit);
|
||||
}
|
||||
|
||||
// ── Notifications (mentions) ──────────────────────────────────────────────────
|
||||
|
||||
export async function fetchMentions(pubkey: string, since: number, limit = 50): Promise<NDKEvent[]> {
|
||||
const instance = getNDK();
|
||||
const events = await instance.fetchEvents(
|
||||
{ kinds: [NDKKind.Text], "#p": [pubkey], since, limit },
|
||||
{ cacheUsage: NDKSubscriptionCacheUsage.ONLY_RELAY }
|
||||
);
|
||||
return Array.from(events).sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0));
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export { getNDK, connectToRelays, fetchGlobalFeed, fetchFollowFeed, fetchReplies, publishNote, publishArticle, publishProfile, publishReaction, publishRepost, publishQuote, publishReply, publishContactList, fetchReactionCount, fetchZapCount, fetchNoteById, fetchUserNotes, fetchProfile, fetchArticle, fetchAuthorArticles, fetchZapsReceived, fetchZapsSent, fetchDMConversations, fetchDMThread, sendDM, decryptDM, fetchMuteList, publishMuteList, getStoredRelayUrls, addRelay, removeRelay, searchNotes, searchUsers } from "./client";
|
||||
export { getNDK, connectToRelays, fetchGlobalFeed, fetchFollowFeed, fetchReplies, publishNote, publishArticle, publishProfile, publishReaction, publishRepost, publishQuote, publishReply, publishContactList, fetchReactionCount, fetchZapCount, fetchNoteById, fetchUserNotes, fetchProfile, fetchArticle, fetchAuthorArticles, fetchZapsReceived, fetchZapsSent, fetchDMConversations, fetchDMThread, sendDM, decryptDM, fetchMuteList, publishMuteList, getStoredRelayUrls, addRelay, removeRelay, searchNotes, searchUsers, fetchUserRelayList, publishRelayList, fetchUserNotesNIP65, fetchMentions } from "./client";
|
||||
export type { UserRelayList } from "./client";
|
||||
|
||||
Reference in New Issue
Block a user