From 6e06656d86a72a0ae21bb2bb02e023cebecf2224 Mon Sep 17 00:00:00 2001 From: Silberengel Date: Mon, 11 May 2026 20:28:57 +0200 Subject: [PATCH] bug-fixes --- src/components/NormalFeed/index.tsx | 15 +- src/constants.ts | 65 ++----- src/lib/event-metadata.ts | 10 +- src/pages/primary/NoteListPage/RelaysFeed.tsx | 15 +- src/providers/FeedProvider.tsx | 171 ++++++++++++++---- src/providers/feed-context.tsx | 3 + src/services/client.service.ts | 2 +- src/services/lightning.service.ts | 4 +- 8 files changed, 190 insertions(+), 95 deletions(-) diff --git a/src/components/NormalFeed/index.tsx b/src/components/NormalFeed/index.tsx index 8e373562..1357cb07 100644 --- a/src/components/NormalFeed/index.tsx +++ b/src/components/NormalFeed/index.tsx @@ -59,6 +59,10 @@ const NormalFeed = forwardRef { + if (listMode === 'postsAndReplies' && repliesSubRequests) { + return repliesSubRequests + } if (listMode !== 'media') return subRequests return subRequests.map((req) => ({ ...req, - urls: isMainFeed ? galleryRelayUrlsMergedWithReadLayer(req.urls) : req.urls, + urls: isMainFeed && widenMainGalleryRelays ? galleryRelayUrlsMergedWithReadLayer(req.urls) : req.urls, filter: { ...req.filter, kinds: MEDIA_KINDS } })) - }, [listMode, subRequests, MEDIA_KINDS, isMainFeed]) + }, [listMode, subRequests, repliesSubRequests, MEDIA_KINDS, isMainFeed, widenMainGalleryRelays]) const handleListModeChange = useCallback( (mode: TNoteListMode | string) => { diff --git a/src/constants.ts b/src/constants.ts index 4275bdf4..58a04b2d 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,13 +1,5 @@ import { kinds, type Filter } from 'nostr-tools' -/** - * API base URL. Prefer `VITE_IMWALD_API_BASE_URL`; `VITE_JUMBLE_API_BASE_URL` is still read for existing deploys. - */ -export const IMWALD_API_BASE_URL = - (import.meta.env.VITE_IMWALD_API_BASE_URL as string | undefined)?.trim() || - (import.meta.env.VITE_JUMBLE_API_BASE_URL as string | undefined)?.trim() || - 'https://api.jumble.imwald.eu' - /** Git Republic web UI for repository links; override with VITE_GITREPUBLIC_WEB_BASE_URL for self-hosted. */ export const GITREPUBLIC_WEB_BASE_URL = ( (import.meta.env.VITE_GITREPUBLIC_WEB_BASE_URL as string | undefined) ?? 'https://gitrepublic.imwald.eu' @@ -128,12 +120,6 @@ export const OUTBOX_PUBLISH_RETRY_DELAY_MS = 5000 */ export const EARLY_PUBLISH_SUCCESS_GRACE_MS = 1200 -/** - * Cap how long we wait on NIP-65 / inbox relay-list resolution (including `fetchRelayLists` network phase - * and kind-10432 fetch) before publishing or falling back to IndexedDB-only merge. - * Without this, a stuck `fetchReplaceableEventsFromProfileFetchRelays` can block the UI even when kind - * 10002 is already in IndexedDB (the 30s publish timeout only runs after targets are resolved). - */ /** * Budget for `fetchRelayLists` / NIP-65 resolution on the publish path. Longer waits block the reply button * while relays stall; shorter values fall back to IndexedDB + deduped picker order sooner (still correct). @@ -254,8 +240,6 @@ export const METADATA_BATCH_AUTHORS_CHUNK = 22 */ export const PROFILE_FETCH_PROMISE_TIMEOUT_MS = 20000 -export const RECOMMENDED_RELAYS = DEFAULT_FAVORITE_RELAYS.concat([]) - export const RECOMMENDED_BLOSSOM_SERVERS = [ 'https://blossom.band', 'https://blossom.primal.net', @@ -366,12 +350,6 @@ export const DOCUMENT_RELAY_URLS = [ 'wss://relay.wikifreedia.xyz' ] as const -/** - * Block-list order (applied in sequence when building relay lists): - * 1. READ_ONLY — never publish (search mirrors, index relays, NIP-42 read-only aggregators) - * 2. SOCIAL_KIND_BLOCKED — skip for REQ/publish that touch {@link SOCIAL_KIND_BLOCKED_KINDS} (see list below) - * 3. E_TAG_FILTER_BLOCKED — skip for reply/quote/stats fetches (#e, #a, #q filters) - */ /** * Relays that must never receive publishes: search engines, index mirrors, and similar endpoints that only ingest * or aggregate for read. Distinct from {@link SOCIAL_KIND_BLOCKED_RELAY_URLS} (kind-coverage limits, not write policy). @@ -454,7 +432,7 @@ export const GIF_RELAY_URLS = [ export const SEARCHABLE_RELAY_URLS = [ 'wss://search.nos.today', - 'wss://nostr.wine', + 'wss://nostr.wine', 'wss://orly-relay.imwald.eu', 'wss://aggr.nostr.land', 'wss://thecitadel.nostr1.com', @@ -468,24 +446,22 @@ export const SEARCHABLE_RELAY_URLS = [ 'wss://nostr-pub.wellorder.net', 'wss://pyramid.fiatjaf.com/', 'wss://nostrelites.org' - ] +] export const PROFILE_RELAY_URLS = [ - 'wss://nos.lol', - 'wss://relay.damus.io', - 'wss://profiles.nostr1.com', - 'wss://purplepag.es', - 'wss://thecitadel.nostr1.com' - ] - - export const FOLLOWS_HISTORY_RELAY_URLS = [ - 'wss://hist.nostr.land' - ] - -// Combined relay URLs for profile fetching - includes both FAST_READ_RELAY_URLS and SEARCHABLE_RELAY_URLS -export const PROFILE_FETCH_RELAY_URLS = [...SEARCHABLE_RELAY_URLS, ...FAST_READ_RELAY_URLS, ...PROFILE_RELAY_URLS] + 'wss://nos.lol', + 'wss://relay.damus.io', + 'wss://profiles.nostr1.com', + 'wss://purplepag.es', + 'wss://thecitadel.nostr1.com' +] -export const GROUP_METADATA_EVENT_KIND = 39000 +export const FOLLOWS_HISTORY_RELAY_URLS = [ + 'wss://hist.nostr.land' +] + +// Combined relay URLs for profile fetching: search/index relays, fallback inboxes, and profile-specific relays. +export const PROFILE_FETCH_RELAY_URLS = [...SEARCHABLE_RELAY_URLS, ...FAST_READ_RELAY_URLS, ...PROFILE_RELAY_URLS] export const ExtendedKind = { PICTURE: 20, @@ -577,11 +553,6 @@ export const ExtendedKind = { export const UNSIGNED_EXPERIMENTAL_KIND_MIN = 69999 export const UNSIGNED_EXPERIMENTAL_KIND_MAX = 130000 -export const UNSIGNED_EXPERIMENTAL_RELAY_URLS = [ - 'wss://nostr.land', - 'wss://theforest.gitcitadel.eu', -] - export function isUnsignedExperimentalKind(kind: number): boolean { return kind >= UNSIGNED_EXPERIMENTAL_KIND_MIN && kind <= UNSIGNED_EXPERIMENTAL_KIND_MAX } @@ -670,7 +641,7 @@ export const NOTE_STATS_OP_REFERENCE_KINDS_WITHOUT_HIGHLIGHT: readonly number[] * stack — those relays do not carry this note/comment surface (kinds **1** / **1111** / **11** per relay policy). * @see {@link relayFilterIncludesSocialKindBlockedKind} */ -export const SOCIAL_KIND_BLOCKED_KINDS: readonly number[] = [ +const SOCIAL_KIND_BLOCKED_KINDS: readonly number[] = [ kinds.ShortTextNote, ExtendedKind.DISCUSSION, ExtendedKind.COMMENT @@ -738,7 +709,7 @@ export function relayFilterIncludesSocialKindBlockedKind(filter: Filter): boolea /** * Document/event kinds that should always include {@link DOCUMENT_RELAY_URLS} in read/publish relay candidates. */ -export const DOCUMENT_RELAY_KINDS: readonly number[] = [ +const DOCUMENT_RELAY_KINDS: readonly number[] = [ kinds.LongFormArticle, // 30023 ExtendedKind.WIKI_ARTICLE, // 30818 ExtendedKind.WIKI_ARTICLE_MARKDOWN, // 30817 @@ -936,18 +907,14 @@ export const URL_REGEX = /https?:\/\/[\w\p{L}\p{N}\p{M}&.\-/?=#@%+_:!~*]+(?:,[^\s.][\w\p{L}\p{N}\p{M}&.\-/?=#@%+_:!~*,]*)*[^\s.,;:'")\]}!?,。;:"'!?】)](?=\.(?:\s|$)|,\s|,(?=\/|\s|$)|$|[^\w\p{L}\p{N}\p{M}&.\-/?=#@%+_:!~*,])/giu export const WS_URL_REGEX = /wss?:\/\/[\w\p{L}\p{N}\p{M}&.\-/?=#@%+_:!~*]+[^\s.,;:'")\]}!?,。;:"'!?】)](?=\.(?:\s|$)|,\s|,(?=\/|\s|$)|$|[^\w\p{L}\p{N}\p{M}&.\-/?=#@%+_:!~*,])/giu -export const EMAIL_REGEX = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ /** @see {@link '@/lib/content-patterns'} — single source for emoji + nostr regexes */ export { - EMOJI_SHORT_CODE_MAX_INNER_LENGTH, EMOJI_SHORT_CODE_REGEX, EMBEDDED_EVENT_REGEX, EMBEDDED_MENTION_REGEX } from '@/lib/content-patterns' export const HASHTAG_REGEX = /#[a-zA-Z0-9_\-\u00C0-\u017F\u0100-\u017F\u0180-\u024F\u1E00-\u1EFF]+/g export const LN_INVOICE_REGEX = /(ln(?:bc|tb|bcrt))([0-9]+[munp]?)?1([02-9ac-hj-np-z]+)/g -export const EMOJI_REGEX = - /[\u{1F600}-\u{1F64F}]|[\u{1F300}-\u{1F5FF}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{1F900}-\u{1F9FF}]|[\u{1FA70}-\u{1FAFF}]|[\u{1F004}]|[\u{1F0CF}]|[\u{1F18E}]|[\u{3030}]|[\u{2B50}]|[\u{2B55}]|[\u{2934}-\u{2935}]|[\u{2B05}-\u{2B07}]|[\u{2B1B}-\u{2B1C}]|[\u{3297}]|[\u{3299}]|[\u{303D}]|[\u{00A9}]|[\u{00AE}]|[\u{2122}]|[\u{23E9}-\u{23EF}]|[\u{23F0}]|[\u{23F3}]|[\u{FE00}-\u{FE0F}]|[\u{200D}]/gu export const YOUTUBE_URL_REGEX = /https?:\/\/(?:(?:(?:www|m|music)\.)?youtube\.com\/(?:watch\?[^#\s]*|embed\/[\w-]+|shorts\/[\w-]+|live\/[\w-]+)|(?:www\.)?youtube-nocookie\.com\/(?:watch\?[^#\s]*|embed\/[\w-]+|shorts\/[\w-]+|live\/[\w-]+)|youtu\.be\/[\w-]+)(?:\?[^#\s]*)?(?:#[^\s]*)?/gi diff --git a/src/lib/event-metadata.ts b/src/lib/event-metadata.ts index 366bcb92..2ea77eef 100644 --- a/src/lib/event-metadata.ts +++ b/src/lib/event-metadata.ts @@ -1,4 +1,4 @@ -import { ExtendedKind, FAST_READ_RELAY_URLS, POLL_TYPE } from '@/constants' +import { ExtendedKind, FAST_READ_RELAY_URLS, FAST_WRITE_RELAY_URLS, POLL_TYPE } from '@/constants' import { TEmoji, TMailboxRelay, TPollType, TRelayList, TRelaySet, TPaymentInfo, TProfile } from '@/types' import { Event, kinds } from 'nostr-tools' import { buildATag } from './draft-event' @@ -19,7 +19,7 @@ const emptyHttpRelayListFields = { export function getRelayListFromEvent(event?: Event | null, blockedRelays?: string[]) { if (!event) { return { - write: FAST_READ_RELAY_URLS, + write: FAST_WRITE_RELAY_URLS, read: FAST_READ_RELAY_URLS, originalRelays: [], ...emptyHttpRelayListFields @@ -59,11 +59,11 @@ export function getRelayListFromEvent(event?: Event | null, blockedRelays?: stri } }) - // If there are too many relays, use the default FAST_READ_RELAY_URLS + // If there are too many relays, use the default inbox/outbox relays. // Because they don't know anything about relays, their settings cannot be trusted return { - write: relayList.write.length && relayList.write.length <= 8 ? relayList.write : FAST_READ_RELAY_URLS, - read: relayList.read.length && relayList.write.length <= 8 ? relayList.read : FAST_READ_RELAY_URLS, + write: relayList.write.length && relayList.write.length <= 8 ? relayList.write : FAST_WRITE_RELAY_URLS, + read: relayList.read.length && relayList.read.length <= 8 ? relayList.read : FAST_READ_RELAY_URLS, originalRelays: relayList.originalRelays, ...emptyHttpRelayListFields } diff --git a/src/pages/primary/NoteListPage/RelaysFeed.tsx b/src/pages/primary/NoteListPage/RelaysFeed.tsx index 1890b8ce..87682292 100644 --- a/src/pages/primary/NoteListPage/RelaysFeed.tsx +++ b/src/pages/primary/NoteListPage/RelaysFeed.tsx @@ -17,7 +17,7 @@ const RelaysFeed = forwardRef< kindsOverride?: number[] } >(function RelaysFeed({ setSubHeader, onSubHeaderRefresh, kindsOverride }, ref) { - const { relayUrls } = useFeed() + const { relayUrls, replyRelayUrls } = useFeed() const { showKinds } = useKindFilterOrDefaults() const [areAlgoRelays, setAreAlgoRelays] = useState(false) @@ -86,6 +86,17 @@ const RelaysFeed = forwardRef< } ] }, [canRenderFeed, relayUrls, defaultKinds]) + const repliesSubRequests = useMemo(() => { + if (!canRenderFeed) return [] + return [ + { + urls: replyRelayUrls.length > 0 ? replyRelayUrls : relayUrls, + filter: { + kinds: defaultKinds + } + } + ] + }, [canRenderFeed, replyRelayUrls, relayUrls, defaultKinds]) if (!canRenderFeed) { return null @@ -101,6 +112,8 @@ const RelaysFeed = forwardRef< setSubHeader={setSubHeader} onSubHeaderRefresh={onSubHeaderRefresh} preserveTimelineOnSubRequestsChange + repliesSubRequests={repliesSubRequests} + widenMainGalleryRelays={false} feedTimelineScopeKey="all-favorites" showFeedClientFilter hostPrimaryPageName="feed" diff --git a/src/providers/FeedProvider.tsx b/src/providers/FeedProvider.tsx index 3482a81b..ffe28120 100644 --- a/src/providers/FeedProvider.tsx +++ b/src/providers/FeedProvider.tsx @@ -1,10 +1,13 @@ +import { FAST_READ_RELAY_URLS, FAST_WRITE_RELAY_URLS } from '@/constants' import { feedRelayPolicyUrls } from '@/features/feed/relay-policy' import { getFavoritesFeedRelayUrls } from '@/lib/favorites-feed-relays' import { getRelayListFromEvent, getHttpRelayListFromEvent } from '@/lib/event-metadata' import logger from '@/lib/logger' +import { AGGR_NOSTR_LAND_WSS } from '@/lib/nostr-land-aggr' import { normalizeAnyRelayUrl } from '@/lib/url' import { buildWispTrendingNotesRelayUrl } from '@/lib/wisp-trending-relay' import { useEffect, useMemo, useState, useCallback } from 'react' +import type { Dispatch, ReactNode, SetStateAction } from 'react' import { FeedContext } from './feed-context' import { useFavoriteRelays } from './FavoriteRelaysProvider' import { useNostr } from './NostrProvider' @@ -37,54 +40,133 @@ function buildAllFavoritesFeedRelayUrls( }) } -export function FeedProvider({ children }: { children: React.ReactNode }) { - const { isInitialized, cacheRelayListEvent, httpRelayListEvent } = useNostr() - const { favoriteRelays, blockedRelays } = useFavoriteRelays() - - /** - * Extra relay URLs always merged into the all-favorites feed: - * - Cache relays (kind 10432) if the user has configured any - * - HTTP index relays (kind 10243) if the user has configured any - * - The Wisp trending relay (always included) - */ - const extraFeedRelayUrls = useMemo(() => { - const extra: string[] = [buildWispTrendingNotesRelayUrl()] +function relayListMentionsNostrLand(urls: readonly string[]): boolean { + return urls.some((url) => { + const normalized = normalizeAnyRelayUrl(url) || url.trim() + if (!normalized) return false + try { + const parsed = new URL(normalized.replace(/^ws:\/\//i, 'http://').replace(/^wss:\/\//i, 'https://')) + return parsed.hostname.toLowerCase() === 'nostr.land' + } catch { + return false + } + }) +} + +function buildHomeReplyFeedRelayUrls( + primaryRelayUrls: string[], + inboxRelayUrls: string[], + cacheRelayUrls: string[], + httpRelayUrls: string[], + includeNostrLandAggr: boolean, + blockedRelays: string[] +): string[] { + return feedRelayPolicyUrls([ + { source: 'favorites', urls: primaryRelayUrls }, + { source: 'viewer-read', urls: inboxRelayUrls }, + { source: 'cache', urls: cacheRelayUrls }, + { source: 'http-index', urls: httpRelayUrls }, + ...(includeNostrLandAggr ? [{ source: 'read-only', urls: [AGGR_NOSTR_LAND_WSS] }] : []) + ], { + operation: 'read', + blockedRelays, + nostrLandAggr: 'never', + applySocialKindBlockedFilter: false, + allowThirdPartyLocalRelays: true + }) +} + +export function FeedProvider({ children }: { children: ReactNode }) { + const { isInitialized, relayList, cacheRelayListEvent, httpRelayListEvent } = useNostr() + const { favoriteRelays, blockedRelays, relaySets } = useFavoriteRelays() + + const favoriteFeedRelayUrls = useMemo( + () => [...favoriteRelays, ...relaySets.flatMap((relaySet) => relaySet.relayUrls)], + [favoriteRelays, relaySets] + ) + + /** Home Notes/Gallery stay focused: favorites/defaults plus the mixed trending relay. */ + const primaryExtraRelayUrls = useMemo(() => [buildWispTrendingNotesRelayUrl()], []) + + /** Home Replies widen to relays that can surface inbox/reply context. */ + const replyExtraRelayLayers = useMemo(() => { + const cacheRelayUrls: string[] = [] if (cacheRelayListEvent) { - const list = getRelayListFromEvent(cacheRelayListEvent) - extra.push(...list.read, ...list.write) + const list = getRelayListFromEvent(cacheRelayListEvent, blockedRelays) + cacheRelayUrls.push(...list.read, ...list.write) } + + const httpRelayUrls: string[] = [...(relayList?.httpRead ?? []), ...(relayList?.httpWrite ?? [])] if (httpRelayListEvent) { - const list = getHttpRelayListFromEvent(httpRelayListEvent) - extra.push(...list.httpRead, ...list.httpWrite) + const list = getHttpRelayListFromEvent(httpRelayListEvent, blockedRelays) + httpRelayUrls.push(...list.httpRead, ...list.httpWrite) + } + + return { + inboxRelayUrls: relayList?.read?.length ? relayList.read : FAST_READ_RELAY_URLS, + outboxRelayUrls: relayList?.write?.length ? relayList.write : FAST_WRITE_RELAY_URLS, + cacheRelayUrls, + httpRelayUrls } - return extra - }, [cacheRelayListEvent, httpRelayListEvent]) + }, [relayList, cacheRelayListEvent, httpRelayListEvent, blockedRelays]) + /** Default relays immediately so feeds / sidebar REQ never wait on Nostr session restore. */ const [relayUrls, setRelayUrls] = useState(() => buildAllFavoritesFeedRelayUrls([], [], [buildWispTrendingNotesRelayUrl()]) ) + const [replyRelayUrls, setReplyRelayUrls] = useState(() => + buildHomeReplyFeedRelayUrls( + buildAllFavoritesFeedRelayUrls([], [], [buildWispTrendingNotesRelayUrl()]), + [], + [], + [], + false, + [] + ) + ) /** Same logical relay policy result — reuse array ref so NoteList does not re-subscribe. */ - const setRelayUrlsIfChanged = useCallback((next: string[]) => { - setRelayUrls((prev) => { - if (relayUrlListIdentity(prev) === relayUrlListIdentity(next)) return prev - return next - }) - }, []) + const setUrlStateIfChanged = useCallback( + (setter: Dispatch>, next: string[]) => { + setter((prev) => { + if (relayUrlListIdentity(prev) === relayUrlListIdentity(next)) return prev + return next + }) + }, + [] + ) const updateFeedRelayUrls = useCallback(() => { - const finalRelays = buildAllFavoritesFeedRelayUrls(favoriteRelays, blockedRelays, extraFeedRelayUrls) - logger.debug('Updating all-favorites relay URLs:', finalRelays) - setRelayUrlsIfChanged(finalRelays) - }, [favoriteRelays, blockedRelays, extraFeedRelayUrls, setRelayUrlsIfChanged]) + const primaryRelays = buildAllFavoritesFeedRelayUrls(favoriteFeedRelayUrls, blockedRelays, primaryExtraRelayUrls) + const aggrEligibleRelayUrls = [ + ...favoriteFeedRelayUrls, + ...replyExtraRelayLayers.inboxRelayUrls, + ...replyExtraRelayLayers.outboxRelayUrls, + ...replyExtraRelayLayers.cacheRelayUrls + ] + const replyRelays = buildHomeReplyFeedRelayUrls( + primaryRelays, + replyExtraRelayLayers.inboxRelayUrls, + replyExtraRelayLayers.cacheRelayUrls, + replyExtraRelayLayers.httpRelayUrls, + relayListMentionsNostrLand(aggrEligibleRelayUrls), + blockedRelays + ) + logger.debug('Updating home feed relay URLs:', { + primaryRelays, + replyRelays + }) + setUrlStateIfChanged(setRelayUrls, primaryRelays) + setUrlStateIfChanged(setReplyRelayUrls, replyRelays) + }, [favoriteFeedRelayUrls, blockedRelays, primaryExtraRelayUrls, replyExtraRelayLayers, setUrlStateIfChanged]) const favoriteRelaysIdentity = useMemo( () => - [...favoriteRelays] + [...favoriteFeedRelayUrls] .map((u) => normalizeAnyRelayUrl(u) || u.trim()) .filter(Boolean) .sort() .join('|'), - [favoriteRelays] + [favoriteFeedRelayUrls] ) const blockedRelaysIdentity = useMemo( () => @@ -95,24 +177,45 @@ export function FeedProvider({ children }: { children: React.ReactNode }) { .join('|'), [blockedRelays] ) + const replyExtraRelaysIdentity = useMemo( + () => + [ + ...replyExtraRelayLayers.inboxRelayUrls, + ...replyExtraRelayLayers.outboxRelayUrls, + ...replyExtraRelayLayers.cacheRelayUrls, + ...replyExtraRelayLayers.httpRelayUrls + ] + .map((u) => normalizeAnyRelayUrl(u) || u.trim()) + .filter(Boolean) + .sort() + .join('|'), + [replyExtraRelayLayers] + ) useEffect(() => { logger.debug('FeedProvider relay init:', { isInitialized, favoriteRelays: favoriteRelays.length, + relaySets: relaySets.length, + relaySetRelays: favoriteFeedRelayUrls.length - favoriteRelays.length, + inboxRelays: replyExtraRelayLayers.inboxRelayUrls.length, + outboxRelays: replyExtraRelayLayers.outboxRelayUrls.length, + cacheRelays: replyExtraRelayLayers.cacheRelayUrls.length, + httpRelays: replyExtraRelayLayers.httpRelayUrls.length, blockedRelays: blockedRelays.length }) - if (favoriteRelays.length === 0) { - logger.debug('FeedProvider: favoriteRelays is empty, using defaults') + if (favoriteFeedRelayUrls.length === 0) { + logger.debug('FeedProvider: no favorite or relay-set relays, using defaults') } updateFeedRelayUrls() - }, [isInitialized, favoriteRelaysIdentity, blockedRelaysIdentity, updateFeedRelayUrls]) + }, [isInitialized, favoriteRelaysIdentity, blockedRelaysIdentity, replyExtraRelaysIdentity, updateFeedRelayUrls]) return ( {children} diff --git a/src/providers/feed-context.tsx b/src/providers/feed-context.tsx index d52bf8fc..914051a4 100644 --- a/src/providers/feed-context.tsx +++ b/src/providers/feed-context.tsx @@ -5,7 +5,10 @@ import { createContext, useContext } from 'react' export type TFeedContext = { + /** Home Notes/Gallery: favorites plus mixed trending discovery. */ relayUrls: string[] + /** Home Replies: primary feed relays plus viewer inbox, HTTP, cache, and eligible aggregator relays. */ + replyRelayUrls: string[] } export const FeedContext = createContext(undefined) diff --git a/src/services/client.service.ts b/src/services/client.service.ts index 5b05afec..3dc40b3a 100644 --- a/src/services/client.service.ts +++ b/src/services/client.service.ts @@ -3771,7 +3771,7 @@ class ClientService extends EventTarget { stripped.write.length > 0 ? stripped.write : write.filter(urlIsNonLocalForRemoteViewer) if (read.length === 0 && write.length === 0) { read = [...FAST_READ_RELAY_URLS] - write = [...FAST_READ_RELAY_URLS] + write = [...FAST_WRITE_RELAY_URLS] } } return mergeKind10243({ diff --git a/src/services/lightning.service.ts b/src/services/lightning.service.ts index cf836cf4..af9e9654 100644 --- a/src/services/lightning.service.ts +++ b/src/services/lightning.service.ts @@ -1,4 +1,4 @@ -import { FAST_READ_RELAY_URLS, CODY_PUBKEY, IMWALD_MAINTAINER_PUBKEY } from '@/constants' +import { FAST_READ_RELAY_URLS, FAST_WRITE_RELAY_URLS, CODY_PUBKEY, IMWALD_MAINTAINER_PUBKEY } from '@/constants' import { getZapInfoFromEvent } from '@/lib/event-metadata' import { buildZapPollVoteRequestTemplate, @@ -65,7 +65,7 @@ class LightningService { })(), sender ? client.fetchRelayList(sender) // Keep using client for relay list merging - : Promise.resolve({ read: FAST_READ_RELAY_URLS, write: FAST_READ_RELAY_URLS }) + : Promise.resolve({ read: FAST_READ_RELAY_URLS, write: FAST_WRITE_RELAY_URLS }) ]) if (!profile) { throw new Error('Recipient not found')