diff --git a/src/components/QuoteList/index.tsx b/src/components/QuoteList/index.tsx index 37f6eec..e732a3b 100644 --- a/src/components/QuoteList/index.tsx +++ b/src/components/QuoteList/index.tsx @@ -14,7 +14,7 @@ const SHOW_COUNT = 10 export default function QuoteList({ event, className }: { event: Event; className?: string }) { const { t } = useTranslation() - const { startLogin } = useNostr() + const { startLogin, relayList: userRelayList } = useNostr() const { hideUntrustedInteractions, isUserTrusted } = useUserTrust() const [timelineKey, setTimelineKey] = useState(undefined) const [events, setEvents] = useState([]) @@ -30,7 +30,9 @@ export default function QuoteList({ event, className }: { event: Event; classNam setHasMore(true) const relayList = await client.fetchRelayList(event.pubkey) - const relayUrls = relayList.read.concat(BIG_RELAY_URLS) + // Include user's mailbox relays for better quote discovery + const userRelays = userRelayList?.read || [] + const relayUrls = relayList.read.concat(userRelays).concat(BIG_RELAY_URLS) const seenOn = client.getSeenEventRelayUrls(event.id) relayUrls.unshift(...seenOn) diff --git a/src/components/ReplyNoteList/index.tsx b/src/components/ReplyNoteList/index.tsx index 20547b5..9197f9e 100644 --- a/src/components/ReplyNoteList/index.tsx +++ b/src/components/ReplyNoteList/index.tsx @@ -14,6 +14,7 @@ import { generateBech32IdFromETag, tagNameEquals } from '@/lib/tag' import { useSecondaryPage } from '@/PageManager' import { useContentPolicy } from '@/providers/ContentPolicyProvider' import { useMuteList } from '@/providers/MuteListProvider' +import { useNostr } from '@/providers/NostrProvider' import { useReply } from '@/providers/ReplyProvider' import { useUserTrust } from '@/providers/UserTrustProvider' import client from '@/services/client.service' @@ -37,6 +38,7 @@ export default function ReplyNoteList({ index, event }: { index?: number; event: const { hideUntrustedInteractions, isUserTrusted } = useUserTrust() const { mutePubkeySet } = useMuteList() const { hideContentMentioningMutedUsers } = useContentPolicy() + const { relayList: userRelayList } = useNostr() const [rootInfo, setRootInfo] = useState(undefined) const { repliesMap, addReplies } = useReply() const replies = useMemo(() => { @@ -141,7 +143,9 @@ export default function ReplyNoteList({ index, event }: { index?: number; event: const relayList = await client.fetchRelayList( (rootInfo as { pubkey?: string }).pubkey ?? event.pubkey ) - const relayUrls = relayList.read.concat(BIG_RELAY_URLS) + // Include user's mailbox relays for better reply discovery + const userRelays = userRelayList?.read || [] + const relayUrls = relayList.read.concat(userRelays).concat(BIG_RELAY_URLS) const seenOn = rootInfo.type === 'E' ? client.getSeenEventRelayUrls(rootInfo.id) diff --git a/src/constants.ts b/src/constants.ts index 4028264..3fe6a18 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -3,16 +3,10 @@ import { kinds } from 'nostr-tools' export const JUMBLE_API_BASE_URL = 'https://api.jumble.social' export const DEFAULT_FAVORITE_RELAYS = [ - 'wss://nostr.wine/', - 'wss://pyramid.fiatjaf.com/', - 'wss://relays.land/spatianostra/', - 'wss://theforest.nostr1.com/', - 'wss://algo.utxo.one/', - 'wss://140.f7z.io/', - 'wss://news.utxo.one/' + 'wss://theforest.nostr1.com/','wss://orly-relay.imwald.eu' ] -export const RECOMMENDED_RELAYS = DEFAULT_FAVORITE_RELAYS.concat(['wss://yabu.me/']) +export const RECOMMENDED_RELAYS = DEFAULT_FAVORITE_RELAYS.concat([]) export const RECOMMENDED_BLOSSOM_SERVERS = [ 'https://blossom.band/', @@ -64,13 +58,19 @@ export const ApplicationDataKey = { } export const BIG_RELAY_URLS = [ - 'wss://relay.damus.io/', - 'wss://nos.lol/', - 'wss://relay.nostr.band/', - 'wss://nostr.mom/' + 'wss://theforest.nostr1.com', + 'wss://orly-relay.imwald.eu', + 'wss://thecitadel.nostr1.com/', + 'wss://nostr.wine', + 'wss://nostr.land/', + 'wss://nostr.sovbit.host/', + 'wss://nostr21.com' ] -export const SEARCHABLE_RELAY_URLS = ['wss://relay.nostr.band/', 'wss://search.nos.today/'] +export const SEARCHABLE_RELAY_URLS = ['wss://relay.nostr.band/', 'wss://freelay.sovbit.host/', 'wss://relay.damus.io/', 'wss://search.nos.today/', 'wss://aggr.nostr.land', 'wss://purplepag.es', 'wss://profiles.nostr1.com'] + +// Combined relay URLs for profile fetching - includes both BIG_RELAY_URLS and SEARCHABLE_RELAY_URLS +export const PROFILE_FETCH_RELAY_URLS = [...BIG_RELAY_URLS, ...SEARCHABLE_RELAY_URLS] export const GROUP_METADATA_EVENT_KIND = 39000 @@ -134,8 +134,7 @@ export const DEFAULT_NIP_96_SERVICE = 'https://nostr.build' export const DEFAULT_NOSTRCONNECT_RELAY = [ 'wss://relay.nsec.app/', - 'wss://nos.lol/', - 'wss://relay.primal.net' + 'wss://thecitadel.nostr1.com' ] export const POLL_TYPE = { diff --git a/src/providers/FavoriteRelaysProvider.tsx b/src/providers/FavoriteRelaysProvider.tsx index 63d3a98..a568ee6 100644 --- a/src/providers/FavoriteRelaysProvider.tsx +++ b/src/providers/FavoriteRelaysProvider.tsx @@ -43,15 +43,21 @@ export function FavoriteRelaysProvider({ children }: { children: React.ReactNode useEffect(() => { if (!favoriteRelaysEvent) { - const favoriteRelays: string[] = DEFAULT_FAVORITE_RELAYS - const storedRelaySets = storage.getRelaySets() - storedRelaySets.forEach(({ relayUrls }) => { - relayUrls.forEach((url) => { - if (!favoriteRelays.includes(url)) { - favoriteRelays.push(url) - } + // For anonymous users (no login), only use relays from BIG_RELAY_URLS + // Don't load potentially untrusted relays from local storage + const favoriteRelays: string[] = pubkey ? DEFAULT_FAVORITE_RELAYS : BIG_RELAY_URLS.slice() + + if (pubkey) { + // Only add stored relay sets if user is logged in + const storedRelaySets = storage.getRelaySets() + storedRelaySets.forEach(({ relayUrls }) => { + relayUrls.forEach((url) => { + if (!favoriteRelays.includes(url)) { + favoriteRelays.push(url) + } + }) }) - }) + } setFavoriteRelays(favoriteRelays) setRelaySetEvents([]) diff --git a/src/services/client.service.ts b/src/services/client.service.ts index e0c572c..94dc5b3 100644 --- a/src/services/client.service.ts +++ b/src/services/client.service.ts @@ -1,4 +1,4 @@ -import { BIG_RELAY_URLS, ExtendedKind } from '@/constants' +import { BIG_RELAY_URLS, ExtendedKind, PROFILE_FETCH_RELAY_URLS } from '@/constants' import { compareEvents, getReplaceableCoordinate, @@ -11,7 +11,7 @@ import { getPubkeysFromPTags, getServersFromServerTags, tagNameEquals } from '@/ import { isLocalNetworkUrl, isWebsocketUrl, normalizeUrl } from '@/lib/url' import { isSafari } from '@/lib/utils' import { ISigner, TProfile, TPublishOptions, TRelayList, TSubRequestFilter } from '@/types' -import { sha256 } from '@noble/hashes/sha2' +import { sha256 } from '@noble/hashes/sha256' import DataLoader from 'dataloader' import dayjs from 'dayjs' import FlexSearch from 'flexsearch' @@ -875,7 +875,7 @@ class ClientService extends EventTarget { } private async fetchEventsFromBigRelays(ids: readonly string[]) { - const events = await this.query(BIG_RELAY_URLS, { + const events = await this.query(PROFILE_FETCH_RELAY_URLS, { ids: Array.from(new Set(ids)), limit: ids.length }) @@ -1143,7 +1143,7 @@ class ClientService extends EventTarget { const eventsMap = new Map() await Promise.allSettled( Array.from(groups.entries()).map(async ([kind, pubkeys]) => { - const events = await this.query(BIG_RELAY_URLS, { + const events = await this.query(PROFILE_FETCH_RELAY_URLS, { authors: pubkeys, kinds: [kind] }) @@ -1246,7 +1246,7 @@ class ClientService extends EventTarget { } : { authors: [pubkey], kinds: [kind] }) as Filter ) - const events = await this.query(BIG_RELAY_URLS, filters) + const events = await this.query(PROFILE_FETCH_RELAY_URLS, filters) for (const event of events) { const key = getReplaceableCoordinateFromEvent(event) diff --git a/tsconfig.app.json b/tsconfig.app.json index 6b2e117..41ea363 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -24,7 +24,10 @@ "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true + "noUncheckedSideEffectImports": true, + + /* Type resolution */ + "types": [] }, "include": ["src"] }