diff --git a/src/components/Note/index.tsx b/src/components/Note/index.tsx index 96e4eb6d..eaaec1d7 100644 --- a/src/components/Note/index.tsx +++ b/src/components/Note/index.tsx @@ -392,7 +392,6 @@ export default function Note({ let content: React.ReactNode if (!isRenderableNoteKind(event.kind)) { - logger.debug('Note component - rendering UnknownNote for unsupported kind:', event.kind) content = } else if (muteSetHas(mutePubkeySet, event.pubkey) && !showMuted) { content = setShowMuted(true)} /> diff --git a/src/components/SearchResult/FullTextSearchByRelay.tsx b/src/components/SearchResult/FullTextSearchByRelay.tsx index eefb1bff..b1aaa497 100644 --- a/src/components/SearchResult/FullTextSearchByRelay.tsx +++ b/src/components/SearchResult/FullTextSearchByRelay.tsx @@ -2,7 +2,6 @@ import NoteCard from '@/components/NoteCard' import RelayIcon from '@/components/RelayIcon' import { Skeleton } from '@/components/ui/skeleton' import { compareEventsForDTagQuery } from '@/lib/dtag-search' -import logger from '@/lib/logger' import { formatPubkey, pubkeyToNpub } from '@/lib/pubkey' import { normalizeUrl } from '@/lib/url' import { NoteFeedProfileContext, type NoteFeedProfileContextValue } from '@/providers/NoteFeedProfileContext' @@ -213,24 +212,6 @@ function sortRelaysByHost(urls: readonly string[]): string[] { ) } -/** Console hint: what this one-shot outcome suggests about NIP-50 (never proof without NIP-11). */ -function nip50OutcomeHint(args: { - phase: 'done' | 'error' - rawCount: number - connectionError?: string -}): string { - if (args.phase === 'error') { - return 'no_transport_or_relay_closed_request — cannot tell NIP-50 from this run' - } - if (args.rawCount > 0) { - return 'returned_events_for_REQ_with_search_field — relay likely honors NIP-50 for this query (verify with NIP-11 supported_nips)' - } - if (args.connectionError) { - return 'zero_events_but_connection_error_message — partial failure or restrictive CLOSE; NIP-50 unclear' - } - return 'zero_events_clean_close — no_hits_or_search_ignored_or_empty_index — cannot distinguish without NIP-11 or a known match' -} - export default function FullTextSearchByRelay({ searchQuery, relayUrls, @@ -325,15 +306,6 @@ export default function FullTextSearchByRelay({ } const runOneRelay = async (relayUrl: string) => { - const host = relayHostForSubscribeLog(relayUrl) - logger.debug('[NIP-50 full-text] card_begin', { - runId: myRun, - relayUrl, - host, - timeoutMs: FULL_TEXT_SEARCH_PER_RELAY_TIMEOUT_MS, - filter: { search: filter.search, kinds: filter.kinds, limit: filter.limit } - }) - const t0 = performance.now() try { const { events: raw, connectionError } = await client.fetchEventsFromSingleRelay( @@ -350,18 +322,6 @@ export default function FullTextSearchByRelay({ if (myRun !== runGeneration.current) return const ms = Math.round(performance.now() - t0) if (sorted.length === 0 && connectionError) { - logger.debug('[NIP-50 full-text] card_end', { - runId: myRun, - relayUrl, - host, - phase: 'error' as const, - ms, - eventCountRaw: raw.length, - eventCountShown: 0, - connectionError, - cardErrorMessage: connectionError, - nip50Hint: nip50OutcomeHint({ phase: 'error', rawCount: 0, connectionError }) - }) setRelayRows((prev) => prev.map((r) => r.relayUrl === relayUrl @@ -374,28 +334,6 @@ export default function FullTextSearchByRelay({ mergeIntoHits(relayUrl, sorted) - logger.debug('[NIP-50 full-text] card_end', { - runId: myRun, - relayUrl, - host, - phase: 'done' as const, - ms, - eventCountRaw: raw.length, - eventCountShown: sorted.length, - connectionError: sorted.length > 0 ? undefined : connectionError, - cardNote: - sorted.length === 0 && connectionError - ? 'UI shows soft warning (empty with message)' - : sorted.length === 0 - ? 'UI empty state' - : 'UI lists notes', - nip50Hint: nip50OutcomeHint({ - phase: 'done', - rawCount: raw.length, - connectionError: sorted.length > 0 ? undefined : connectionError - }) - }) - setRelayRows((prev) => prev.map((r) => r.relayUrl === relayUrl @@ -413,18 +351,6 @@ export default function FullTextSearchByRelay({ if (myRun !== runGeneration.current) return const msg = err instanceof Error ? err.message : String(err) const ms = Math.round(performance.now() - t0) - logger.debug('[NIP-50 full-text] card_end', { - runId: myRun, - relayUrl, - host, - phase: 'error' as const, - ms, - eventCountRaw: 0, - eventCountShown: 0, - connectionError: undefined, - cardErrorMessage: msg, - nip50Hint: nip50OutcomeHint({ phase: 'error', rawCount: 0 }) - }) setRelayRows((prev) => prev.map((r) => r.relayUrl === relayUrl ? { ...r, phase: 'error', eventCount: 0, ms, errorMessage: msg } : r @@ -442,25 +368,11 @@ export default function FullTextSearchByRelay({ } void (async () => { - logger.debug('[NIP-50 full-text] wave_begin', { - runId: myRun, - query: q, - relayCount: normalizedRelays.length, - concurrency: poolSize, - filter: { search: filter.search, kinds: filter.kinds, limit: filter.limit }, - relays: normalizedRelays.map((u) => ({ url: u, host: relayHostForSubscribeLog(u) })) - }) try { await Promise.all(Array.from({ length: poolSize }, () => worker())) } catch { /* runOneRelay already updates relay rows */ } - if (myRun !== runGeneration.current) return - logger.debug('[NIP-50 full-text] wave_end', { - runId: myRun, - relayCount: normalizedRelays.length, - note: 'matches UI "all relays finished" when every relay row is done or error' - }) })() return cleanupInvalidatePreviousRun diff --git a/src/lib/relay-list-builder.ts b/src/lib/relay-list-builder.ts index d7e8fa66..1dda86d2 100644 --- a/src/lib/relay-list-builder.ts +++ b/src/lib/relay-list-builder.ts @@ -150,13 +150,8 @@ export async function buildComprehensiveRelayList(options: RelayListBuilderOptio authorOutboxes.forEach(addRelay) const authorInboxes = userReadRelaysWithHttp(authorRelayList).slice(0, 10) authorInboxes.forEach(addRelay) - logger.debug('[RelayListBuilder] Added author relays', { - author: authorPubkey.substring(0, 8), - outboxes: authorOutboxes.length, - inboxes: authorInboxes.length - }) } catch (error) { - logger.debug('[RelayListBuilder] Failed to read author relay list from storage', { error }) + logger.warn('[RelayListBuilder] Failed to read author relay list from storage', { error }) } } @@ -176,28 +171,16 @@ export async function buildComprehensiveRelayList(options: RelayListBuilderOptio } // Include favorite relays (kind 10012) if requested - let favoriteRelaysCount = 0 if (includeFavoriteRelays) { try { const favoriteRelays = await client.fetchFavoriteRelays(userPubkey) favoriteRelays.forEach(addRelay) - favoriteRelaysCount = favoriteRelays.length - logger.debug('[RelayListBuilder] Added user favorite relays', { - count: favoriteRelaysCount - }) } catch (error) { - logger.debug('[RelayListBuilder] Failed to fetch user favorite relays', { error }) + logger.warn('[RelayListBuilder] Failed to fetch user favorite relays', { error }) } } - - logger.debug('[RelayListBuilder] Added user own relays', { - read: (userRelayList.read || []).length, - write: (userRelayList.write || []).length, - local: includeLocalRelays ? (await getCacheRelayUrls(userPubkey)).length : 0, - favorite: favoriteRelaysCount - }) } catch (error) { - logger.debug('[RelayListBuilder] Failed to fetch user relay list', { error }) + logger.warn('[RelayListBuilder] Failed to fetch user relay list', { error }) } } else if (userPubkey) { // Even if not including user's own relays, still include user's inboxes for reading @@ -217,15 +200,12 @@ export async function buildComprehensiveRelayList(options: RelayListBuilderOptio try { const favoriteRelays = await client.fetchFavoriteRelays(userPubkey) favoriteRelays.forEach(addRelay) - logger.debug('[RelayListBuilder] Added user favorite relays (with inboxes path)', { - count: favoriteRelays.length - }) } catch (error) { - logger.debug('[RelayListBuilder] Failed to fetch user favorite relays', { error }) + logger.warn('[RelayListBuilder] Failed to fetch user favorite relays', { error }) } } } catch (error) { - logger.debug('[RelayListBuilder] Failed to fetch user inboxes', { error }) + logger.warn('[RelayListBuilder] Failed to fetch user inboxes', { error }) } } @@ -362,7 +342,7 @@ export async function buildPollResultsReadRelayUrls(options: { viewerReadSlice = userReadRelaysWithHttp(viewerRl).slice(0, POLL_RESULTS_NIP65_READ_SLICE) } } catch { - logger.debug('[RelayListBuilder] poll results: NIP-65 relay list race failed') + /* ignore — poll results still use other layers */ } pushLayer(viewerReadSlice) @@ -373,7 +353,7 @@ export async function buildPollResultsReadRelayUrls(options: { const localRelays = await getCacheRelayUrls(viewerPubkey) pushLayer(localRelays) } catch { - logger.debug('[RelayListBuilder] poll results: cache relays failed') + /* ignore */ } } diff --git a/src/services/client-events.service.ts b/src/services/client-events.service.ts index 20effecb..7a250b3f 100644 --- a/src/services/client-events.service.ts +++ b/src/services/client-events.service.ts @@ -503,34 +503,12 @@ export class EventService { filter.ids?.length === 1 && /^[0-9a-f]{64}$/i.test(String(filter.ids[0])) ? { explicitNoteLookupHexId: String(filter.ids[0]).toLowerCase() } : undefined - const logKey = - 'ids' in filter && filter.ids?.[0] - ? filter.ids[0].slice(0, 8) - : Array.isArray(filter['#a']) && filter['#a'][0] - ? String(filter['#a'][0]).slice(0, 40) - : `${filter.kinds?.[0]}:${(filter.authors?.[0] ?? '').slice(0, 8)}` - - logger.debug('fetchEventWithExternalRelays: Starting search', { - noteIdKey: logKey, - relayCount: externalRelays.length, - relays: externalRelays - }) - - const startTime = Date.now() /** User-driven “try everywhere”: wait for EOSE-ish completion so slower relays (e.g. nos.lol) can answer. */ const events = await this.queryService.query(externalRelays, filter, undefined, { eoseTimeout: 12_000, globalTimeout: 35_000, immediateReturn: false }) - const duration = Date.now() - startTime - - logger.debug('fetchEventWithExternalRelays: Search completed', { - noteIdKey: logKey, - relayCount: externalRelays.length, - eventsFound: events.length, - durationMs: duration - }) const usable = events .filter((e) => !shouldDropEventOnIngest(e, ingestOpts)) @@ -1249,13 +1227,6 @@ export class EventService { return undefined } - logger.debug('[EventService] Using comprehensive relay list', { - author: authorPubkey?.substring(0, 8), - relayCount: relayUrls.length, - hasHints: relayHints.length > 0, - hasSeen: seenRelays.length > 0 - }) - const isSingleEventById = Boolean(filter.ids && filter.ids.length === 1 && filter.limit === 1) /** Replaceable coordinate: `#a` (preferred) or legacy `authors` + `#d`. */ const isReplaceableCoordinateFetch = @@ -1275,13 +1246,6 @@ export class EventService { .filter((e) => !shouldDropEventOnIngest(e, ingestOpts)) .sort((a, b) => b.created_at - a.created_at)[0] - if (event && isSingleEventById && !isReplaceableEvent(event.kind)) { - logger.debug('[EventService] Non-replaceable event returned immediately', { - eventId: event.id.substring(0, 8), - kind: event.kind - }) - } - return event } diff --git a/src/services/client-query.service.ts b/src/services/client-query.service.ts index da086afb..e75313b9 100644 --- a/src/services/client-query.service.ts +++ b/src/services/client-query.service.ts @@ -29,13 +29,7 @@ import { applyRelayNip42AckTimeout } from '@/lib/relay-nip42-tuning' import { isIndexRelayTransportFailure, queryIndexRelay } from '@/lib/index-relay-http' import logger from '@/lib/logger' import { isHttpRelayUrl, normalizeHttpRelayUrl, normalizeUrl } from '@/lib/url' -import { - RelaySubscribeOpBatch, - compactFilterForRelayLog, - humanizeSubscribeTerminalDetail, - relayHostForSubscribeLog, - type RelayOpTerminalRow -} from '@/services/relay-operation-log.service' +import { RelaySubscribeOpBatch, type RelayOpTerminalRow } from '@/services/relay-operation-log.service' import { patchRelayNoticeForFetchFailures } from '@/services/relay-notice-fetch-failure' import type { Filter, Event as NEvent } from 'nostr-tools' import { SimplePool, EventTemplate, VerifiedEvent, nip19 } from 'nostr-tools' @@ -82,54 +76,44 @@ function logQueryReqConsolidatedEnd( kindHistogram[k] = (kindHistogram[k] ?? 0) + 1 } - const norm = (u: string) => normalizeUrl(u) || u - type Row = { - url: string - host: string - terminal?: RelayOpTerminalRow['outcome'] - detail?: string - eventsReturned: number - } - const byKey = new Map() - - const rowFor = (url: string): Row => { - const key = norm(url) - let r = byKey.get(key) - if (!r) { - r = { url: key, host: relayHostForSubscribeLog(key), eventsReturned: 0 } - byKey.set(key, r) - } - return r - } - + const outcomeCounts: Record = {} for (const t of terminals) { - const r = rowFor(t.relayUrl) - r.terminal = t.outcome - r.detail = humanizeSubscribeTerminalDetail(t.outcome, t.detail) + const k = t.outcome + outcomeCounts[k] = (outcomeCounts[k] ?? 0) + 1 } - - for (const e of events) { - const seen = getSeenForEvent(e.id) - for (const u of seen) { - rowFor(u).eventsReturned += 1 - } + const benignEmpty = + events.length === 0 && + (terminals.length === 0 || + terminals.every((t) => t.outcome === 'eose')) + if (benignEmpty) { + return } - for (const u of inputRelays) { - rowFor(u) - } - for (const b of httpBases) { - rowFor(b) + const relayTotal = new Set([ + ...inputRelays.map((u) => normalizeUrl(u) || u), + ...httpBases.map((u) => normalizeUrl(u) || u) + ]).size + + let relaysWithHits = 0 + if (events.length > 0) { + const hitUrls = new Set() + for (const e of events) { + for (const u of getSeenForEvent(e.id)) { + hitUrls.add(normalizeUrl(u) || u) + } + } + relaysWithHits = hitUrls.size } - const perRelay = [...byKey.values()].sort((a, b) => a.host.localeCompare(b.host)) - logger.debug('[QueryService] req_end', { reqId, source, eventCount: events.length, kindHistogram, - perRelay + relayCandidateCount: relayTotal, + terminalCount: terminals.length, + terminalOutcomes: outcomeCounts, + relaysWithEventHits: relaysWithHits }) } @@ -436,17 +420,6 @@ export class QueryService { const inputRelaysOrdered = Array.from(new Set(urls.map((u) => normalizeUrl(u) || u).filter(Boolean))) const wsRelayCandidates = Array.from(new Set(wsQueryUrls.map((u) => normalizeUrl(u) || u).filter(Boolean))) - logger.debug('[QueryService] req_begin', { - reqId, - source, - relays: inputRelaysOrdered, - httpRelayBases, - wsRelayCandidates, - filters: sanitizedFilters.map(compactFilterForRelayLog), - eoseTimeout, - globalTimeout - }) - return await new Promise((resolve) => { const events: NEvent[] = [] const abortHttp = new AbortController() diff --git a/src/services/client-replaceable-events.service.ts b/src/services/client-replaceable-events.service.ts index 18be9a16..1cb9f9bd 100644 --- a/src/services/client-replaceable-events.service.ts +++ b/src/services/client-replaceable-events.service.ts @@ -186,14 +186,7 @@ export class ReplaceableEventService { containingEventRelays: string[] = [] ): Promise { const cacheKey = d ? `${kind}:${pubkey}:${d}` : `${kind}:${pubkey}` - logger.debug('[ReplaceableEventService] fetchReplaceableEvent start', { - pubkey, - kind, - d, - cacheKey, - containingEventRelays: containingEventRelays.length - }) - + try { if (kind === kinds.Metadata && !d) { const sessionEv = client.eventService.getSessionMetadataForPubkey(pubkey) @@ -212,9 +205,6 @@ export class ReplaceableEventService { containingEventRelays.length === 0 && ReplaceableEventService.isProfileFetchMissCached(pubkey) ) { - logger.debug('[ReplaceableEventService] Skipping metadata fetch (recent profile miss cache)', { - pubkey - }) return undefined } @@ -247,18 +237,9 @@ export class ReplaceableEventService { let event: NEvent | undefined if (containingEventRelays.length > 0 && kind === kinds.Metadata && !d) { // For profiles with containing event relays (author's relay list), check IndexedDB first, then query directly - logger.debug('[ReplaceableEventService] Checking IndexedDB for profile with containing relays', { - pubkey, - kind - }) try { const indexedDbCached = await indexedDb.getReplaceableEvent(pubkey, kind, d) if (indexedDbCached) { - logger.debug('[ReplaceableEventService] Found in IndexedDB', { - pubkey, - kind, - eventId: indexedDbCached.id - }) // Refresh in background this.refreshInBackground(pubkey, kind, d).catch(() => {}) return indexedDbCached @@ -270,19 +251,9 @@ export class ReplaceableEventService { error: error instanceof Error ? error.message : String(error) }) } - + // Not in IndexedDB, fetch from network with custom relay list - logger.debug('[ReplaceableEventService] Building relay list with containing event relays', { - pubkey, - containingRelayCount: containingEventRelays.length - }) const relayUrls = await this.buildComprehensiveRelayListForAuthor(pubkey, kind, containingEventRelays, []) - logger.debug('[ReplaceableEventService] Querying relays', { - pubkey, - relayCount: relayUrls.length, - relays: relayUrls.slice(0, 5) - }) - const startTime = Date.now() const events = await this.queryService.query( relayUrls, { @@ -296,51 +267,19 @@ export class ReplaceableEventService { globalTimeout: METADATA_BATCH_QUERY_GLOBAL_TIMEOUT_MS } ) - const queryTime = Date.now() - startTime - logger.debug('[ReplaceableEventService] Query completed', { - pubkey, - eventCount: events.length, - queryTime: `${queryTime}ms` - }) const sortedEvents = events.sort((a, b) => b.created_at - a.created_at) event = sortedEvents.length > 0 ? sortedEvents[0] : undefined } else { // Use DataLoader for batching (IndexedDB checks and network fetches are batched) - logger.debug('[ReplaceableEventService] Using DataLoader (batches IndexedDB + network)', { - pubkey, - kind, - d - }) - const startTime = Date.now() const loadedEvent = d ? await this.replaceableEventDataLoader.load({ pubkey, kind, d }) : await this.replaceableEventFromBigRelaysDataloader.load({ pubkey, kind }) - const loadTime = Date.now() - startTime - logger.debug('[ReplaceableEventService] DataLoader completed', { - pubkey, - found: !!loadedEvent, - loadTime: `${loadTime}ms` - }) event = loadedEvent || undefined } if (event) { - logger.debug('[ReplaceableEventService] Event found', { - pubkey, - kind, - eventId: event.id, - created_at: event.created_at - }) return event } - - // Log when no event is found (helps debug relay failures) - if (kind === kinds.Metadata) { - logger.debug('[ReplaceableEventService] No profile found for pubkey', { - pubkey, - cacheKey - }) - } } catch (error) { // Log errors but don't throw - return undefined so UI can show fallback if (kind === kinds.Metadata) { @@ -357,11 +296,7 @@ export class ReplaceableEventService { }) } } - - logger.debug('[ReplaceableEventService] fetchReplaceableEvent returning undefined', { - pubkey, - kind - }) + return undefined } @@ -486,19 +421,6 @@ export class ReplaceableEventService { private async replaceableEventFromBigRelaysBatchLoadFn( params: readonly { pubkey: string; kind: number }[] ): Promise<(NEvent | null)[]> { - // CRITICAL: Reduce logging during rapid scrolling - only log large batches - if (params.length > 50) { - logger.debug('[ReplaceableEventService] Large batch load function called', { - paramCount: params.length, - kind: params[0]?.kind - }) - } else { - logger.debug('[ReplaceableEventService] Batch load function called', { - paramCount: params.length, - kind: params[0]?.kind - }) - } - const results: (NEvent | null)[] = new Array(params.length).fill(null) const eventsMap = new Map() @@ -532,11 +454,6 @@ export class ReplaceableEventService { const pubkeys = items.map((x) => x.pubkey) try { const indexedDbEvents = await indexedDb.getManyReplaceableEvents(pubkeys, kind) - logger.debug('[ReplaceableEventService] IndexedDB batch query completed', { - kind, - pubkeyCount: pubkeys.length, - foundCount: indexedDbEvents.filter((e) => e !== null && e !== undefined).length - }) items.forEach(({ pubkey, index }, idx) => { const event = indexedDbEvents[idx] @@ -581,9 +498,6 @@ export class ReplaceableEventService { // Step 2: Only fetch missing events from network if (missingParams.length === 0) { - logger.debug('[ReplaceableEventService] All events resolved (session + IndexedDB), skipping network fetch', { - totalCount: params.length - }) return results } @@ -604,19 +518,6 @@ export class ReplaceableEventService { } if (networkMissing.length > 0) { - // Only log at info level for large batches - if (networkMissing.length > 50) { - logger.debug('[ReplaceableEventService] Fetching missing events from network', { - missingCount: networkMissing.length, - totalCount: params.length - }) - } else { - logger.debug('[ReplaceableEventService] Fetching missing events from network', { - missingCount: networkMissing.length, - totalCount: params.length - }) - } - // Group missing params by kind for network fetch const missingGroups = new Map() networkMissing.forEach(({ pubkey, kind, index }) => { @@ -714,21 +615,6 @@ export class ReplaceableEventService { } else { relayUrls = [...FAST_READ_RELAY_URLS] } - - // Only log at info level for large batches - if (pubkeys.length > 50) { - logger.debug('[ReplaceableEventService] Starting query for large batch', { - kind, - pubkeyCount: pubkeys.length, - relayCount: relayUrls.length - }) - } else { - logger.debug('[ReplaceableEventService] Starting query for batch', { - kind, - pubkeyCount: pubkeys.length, - relayCount: relayUrls.length - }) - } // Contacts + NIP-65 need the same patience as pins/payment: 100ms EOSE loses the race on slow relays // and multi-author batches must not use replaceableRace (first EVENT may not be the latest per author). const isSlowReplaceableBatch = @@ -778,21 +664,7 @@ export class ReplaceableEventService { queryOpts ) } - // Only log at info level for large batches or if many events found - if (pubkeys.length > 50 || events.length > 100) { - logger.debug('[ReplaceableEventService] Query completed for batch', { - kind, - pubkeyCount: pubkeys.length, - eventCount: events.length - }) - } else { - logger.debug('[ReplaceableEventService] Query completed for batch', { - kind, - pubkeyCount: pubkeys.length, - eventCount: events.length - }) - } - + // CRITICAL: Limit the number of events processed to prevent memory issues during rapid scrolling // If we have too many events, only process the most recent ones per pubkey if (events.length > 1000) { @@ -812,10 +684,6 @@ export class ReplaceableEventService { } // Convert back to array, but limit to reasonable size const limitedEvents = Array.from(eventsByPubkey.values()).slice(0, 500) - logger.debug('[ReplaceableEventService] Limited batch size', { - originalCount: events.length, - limitedCount: limitedEvents.length - }) // Use limited events for processing for (const event of limitedEvents) { const key = `${event.pubkey}:${event.kind}` @@ -863,22 +731,9 @@ export class ReplaceableEventService { /* ignore */ } } - - // Log when no events are found (helps debug relay failures) - if (kind === kinds.Metadata && events.length === 0 && pubkeys.length > 0) { - logger.debug('[ReplaceableEventService] No profile events found from relays', { - pubkeyCount: pubkeys.length, - relayCount: relayUrls.length, - relays: relayUrls.slice(0, 3) // Show first 3 for brevity - }) - } }) ) - } else { - logger.debug('[ReplaceableEventService] All missing events resolved from session, skipping network fetch', { - totalCount: params.length - }) } // Step 3: Persist hits only. Do not write negative cache rows (`value: null`) — optional kinds @@ -892,21 +747,7 @@ export class ReplaceableEventService { } }) ) - - // Only log at info level for large batches - if (params.length > 50) { - logger.debug('[ReplaceableEventService] Batch load function completed', { - paramCount: params.length, - foundCount: results.filter(r => r !== null).length, - indexedDbCount: params.length - missingParams.length, - networkCount: missingParams.length - }) - } else { - logger.debug('[ReplaceableEventService] Batch load function completed', { - paramCount: params.length, - foundCount: results.filter(r => r !== null).length - }) - } + return results } @@ -1000,17 +841,13 @@ export class ReplaceableEventService { * Fetch profile event by id (hex, npub, nprofile) */ async fetchProfileEvent(id: string, _skipCache: boolean = false): Promise { - logger.debug('[ReplaceableEventService] fetchProfileEvent start', { id }) - let pubkey: string | undefined let relays: string[] = [] if (/^[0-9a-f]{64}$/.test(id)) { pubkey = id - logger.debug('[ReplaceableEventService] ID is hex pubkey', { pubkey }) } else { try { const { data, type } = nip19.decode(id) - logger.debug('[ReplaceableEventService] Decoded bech32 ID', { type }) switch (type) { case 'npub': pubkey = data @@ -1018,7 +855,6 @@ export class ReplaceableEventService { case 'nprofile': pubkey = data.pubkey if (data.relays) relays = data.relays - logger.debug('[ReplaceableEventService] nprofile has relay hints', { relayCount: relays.length }) break } } catch (error) { @@ -1062,21 +898,11 @@ export class ReplaceableEventService { // CRITICAL: Do NOT pass relay hints here - passing any relays bypasses DataLoader and creates individual subscriptions // DataLoader already uses default relays internally and batches all profile fetches // We'll use relay hints in Step 2/3 only if Step 1 fails - logger.debug('[ReplaceableEventService] Step 1: Trying with DataLoader (checks cache first, uses default relays, batched)', { - pubkey, - relayHintCount: relayHints.length, - hasRelayHints: relayHints.length > 0 - }) - // fetchReplaceableEvent uses DataLoader which checks IndexedDB first, then queries default relays // Passing empty array ensures DataLoader is used (batched) - this prevents individual subscriptions const profileEvent = await this.fetchReplaceableEvent(pubkey, kinds.Metadata, undefined, []) if (profileEvent) { - logger.debug('[ReplaceableEventService] Profile found via cache / default relays (DataLoader)', { - pubkey, - eventId: profileEvent.id - }) await this.indexProfile(profileEvent) return profileEvent } @@ -1084,24 +910,15 @@ export class ReplaceableEventService { await ReplaceableEventService.acquireProfileFallbackNetworkSlot() try { // Step 2: Only after cache + default relays miss — NIP-65 relay list (timeout-capped), then hints + outbox/inbox + defaults. - logger.debug('[ReplaceableEventService] Step 2: Fetching author relay list as fallback', { - pubkey, - relayHintCount: relayHints.length - }) - let authorRelayList: { read?: string[]; write?: string[] } | null = null try { const hasLocal10002 = await ReplaceableEventService.hasRelayListInLocalCache(pubkey) if (hasLocal10002) { authorRelayList = await client.peekRelayListFromStorage(pubkey) - logger.debug('[ReplaceableEventService] Step 2: using cached kind 10002 (skip fetchRelayList network)', { - pubkey - }) } else { const relayListPromise = client.fetchRelayList(pubkey) const timeoutPromise = new Promise((resolve) => { setTimeout(() => { - logger.debug('[ReplaceableEventService] fetchRelayList timeout, giving up', { pubkey }) resolve(null) }, 2800) }) @@ -1140,16 +957,11 @@ export class ReplaceableEventService { expandedRelays ) if (profileFromExpanded) { - logger.debug('[ReplaceableEventService] Profile found after relay-list fallback', { - pubkey, - eventId: profileFromExpanded.id - }) await this.indexProfile(profileFromExpanded) return profileFromExpanded } // Step 3: Last resort — broad relay query (timeout-bounded in query layer) - logger.debug('[ReplaceableEventService] Step 3: Comprehensive relay query (last resort)', { pubkey }) try { const userPubkey = client.pubkey const comprehensiveRelays = await buildComprehensiveRelayList({ @@ -1165,14 +977,7 @@ export class ReplaceableEventService { includeLocalRelays: true }) - logger.debug('[ReplaceableEventService] Comprehensive relay list built', { - pubkey, - relayCount: comprehensiveRelays.length, - relays: comprehensiveRelays.slice(0, 10) - }) - if (comprehensiveRelays.length > 0) { - const startTime = Date.now() const events = await this.queryService.query( comprehensiveRelays, { @@ -1186,22 +991,10 @@ export class ReplaceableEventService { globalTimeout: 3500 } ) - const queryTime = Date.now() - startTime - - logger.debug('[ReplaceableEventService] Comprehensive search completed', { - pubkey, - eventCount: events.length, - queryTime: `${queryTime}ms`, - relayCount: comprehensiveRelays.length - }) if (events.length > 0) { const sortedEvents = events.sort((a, b) => b.created_at - a.created_at) const found = sortedEvents[0]! - logger.debug('[ReplaceableEventService] Profile found via comprehensive search', { - pubkey, - eventId: found.id - }) await this.indexProfile(found) return found } @@ -1216,10 +1009,6 @@ export class ReplaceableEventService { ReplaceableEventService.releaseProfileFallbackNetworkSlot() } - logger.debug('[ReplaceableEventService] Profile not found after cache, relay-list fallback, and comprehensive search', { - pubkey, - triedRelayHints: relayHints.length > 0 - }) if (!_skipCache && relayHints.length === 0) { ReplaceableEventService.rememberProfileFetchMiss(pubkey) } @@ -1676,15 +1465,6 @@ export class ReplaceableEventService { result.push([relayUrl, Array.from(pubkeys)]) } - logger.debug('[ReplaceableEventService] fetchFollowingFavoriteRelays completed', { - followingsCount: followings.length, - processedCount: followingsToProcess.length, - favoriteRelaysEventsFound: favoriteRelaysEvents.filter((e) => e !== undefined).length, - relayListEventsFound: relayListEvents.filter((e) => e !== undefined).length, - uniqueRelays: result.length, - totalUsers: result.reduce((sum, [, users]) => sum + users.length, 0) - }) - return result } } diff --git a/src/services/client.service.ts b/src/services/client.service.ts index 8cfd0cec..60b0048d 100644 --- a/src/services/client.service.ts +++ b/src/services/client.service.ts @@ -3941,23 +3941,12 @@ class ClientService extends EventTarget { const cacheKey = this.relayListRequestCacheKey(pubkey) const existingRequest = this.relayListRequestCache.get(cacheKey) if (existingRequest) { - // Leader already logged `[FetchRelayList] Starting fetch`; joiners stay silent per burst. return existingRequest } - - logger.debug('[FetchRelayList] Starting fetch', { pubkey }) + const requestPromise = (async () => { try { - const startTime = Date.now() const [relayList] = await this.fetchRelayLists([pubkey]) - const duration = Date.now() - startTime - logger.debug('[FetchRelayList] Fetch completed', { - pubkey, - duration: `${duration}ms`, - hasRelayList: !!relayList, - writeCount: relayList?.write?.length ?? 0, - readCount: relayList?.read?.length ?? 0 - }) return relayList } catch (error) { logger.warn('[FetchRelayList] Fetch failed; using IndexedDB / defaults', { @@ -4213,14 +4202,6 @@ class ClientService extends EventTarget { const missing10002Pubkeys = pubkeys.filter((_pk, i) => storedRelayEvents[i] == null) if (missing10002Pubkeys.length > 0) { - logger.debug( - '[FetchRelayLists] Kind 10002 missing in IndexedDB for some pubkeys; fetching only those over the network', - { - batchSize: pubkeys.length, - missingCount: missing10002Pubkeys.length, - missingPubkeyPrefixes: missing10002Pubkeys.map((p) => p.slice(0, 12)) - } - ) const [relFetched, httpFetched] = await Promise.all([ this.replaceableEventService.fetchReplaceableEventsFromProfileFetchRelays( missing10002Pubkeys, @@ -4269,10 +4250,6 @@ class ClientService extends EventTarget { if (allHaveKind10002) { this.refreshRelayListsFromNetwork(pubkeys, storedRelayEvents) - logger.debug( - '[FetchRelayLists] Kind 10002 present in IndexedDB for all pubkeys; merging locally, network refresh in background', - { count: pubkeys.length } - ) const cacheRelayEvents = await Promise.race([ this.fetchCacheRelayEventsFromMultipleSources(pubkeys, storedRelayEvents, storedRelayEvents), new Promise<(NEvent | null | undefined)[]>((resolve) => diff --git a/src/services/indexed-db.service.ts b/src/services/indexed-db.service.ts index fd4efeac..882f1cfa 100644 --- a/src/services/indexed-db.service.ts +++ b/src/services/indexed-db.service.ts @@ -270,29 +270,6 @@ class IndexedDbService { private static readonly TOMBSTONE_NOT_CACHE_TTL_MS = 45_000 private static readonly TOMBSTONE_NOT_CACHE_MAX = 4096 - /** - * During bulk hydrates, `getReplaceableEvent` can run hundreds of times in a short window. - * One sample slot per completed lookup; first few per window log in full, then sample. - */ - private replaceableGetDebugWindow = { t0: 0, n: 0 } - private static readonly REPLACEABLE_GET_DEBUG_WINDOW_MS = 150 - private static readonly REPLACEABLE_GET_DEBUG_BURST_AFTER = 10 - private static readonly REPLACEABLE_GET_DEBUG_SAMPLE_EVERY = 24 - - private takeReplaceableGetDebugLogSlot(): boolean { - const now = Date.now() - const winMs = IndexedDbService.REPLACEABLE_GET_DEBUG_WINDOW_MS - if (now - this.replaceableGetDebugWindow.t0 > winMs) { - this.replaceableGetDebugWindow = { t0: now, n: 0 } - } - this.replaceableGetDebugWindow.n += 1 - const n = this.replaceableGetDebugWindow.n - const burstAfter = IndexedDbService.REPLACEABLE_GET_DEBUG_BURST_AFTER - const sampleEvery = IndexedDbService.REPLACEABLE_GET_DEBUG_SAMPLE_EVERY - return n <= burstAfter || n % sampleEvery === 0 - } - - /** First TTL sweep after DB open (profile / relay list rows). */ private static readonly CLEANUP_INITIAL_DELAY_MS = 60 * 1000 /** Repeat TTL sweeps on this interval so pruning is not a one-shot. */ private static readonly CLEANUP_INTERVAL_MS = 60 * 60 * 1000 @@ -624,16 +601,8 @@ class IndexedDbService { const request = store.get(key) request.onsuccess = () => { - const allowDetailLog = this.takeReplaceableGetDebugLogSlot() const row = request.result as TValue | undefined if (!row) { - if (allowDetailLog) { - logger.debug('[IndexedDB] getReplaceableEvent - no row found', { - pubkey, - kind, - d - }) - } transaction.commit() return resolve(undefined) } @@ -644,22 +613,6 @@ class IndexedDbService { if (isProfileOrPayment && row.addedAt && Date.now() - row.addedAt > PROFILE_AND_PAYMENT_CACHE_MAX_AGE_MS) { // Profile is stale, but return it anyway - refresh will happen in background // This prevents the "no profile" state when cache exists but is just old - if (allowDetailLog) { - logger.debug('[IndexedDB] Profile cache is stale but returning anyway', { - pubkey, - age: Date.now() - row.addedAt, - maxAge: PROFILE_AND_PAYMENT_CACHE_MAX_AGE_MS, - eventId: row.value?.id - }) - } - } - if (allowDetailLog) { - logger.debug('[IndexedDB] getReplaceableEvent - found', { - pubkey, - kind, - eventId: row.value?.id, - addedAt: row.addedAt - }) } transaction.commit() resolve(row.value) diff --git a/src/services/note-stats.service.ts b/src/services/note-stats.service.ts index d3e4d778..562d6dd9 100644 --- a/src/services/note-stats.service.ts +++ b/src/services/note-stats.service.ts @@ -137,10 +137,6 @@ class NoteStatsService { }, this.BATCH_DELAY) } - private statsPendingSize() { - return this.pendingForeground.size + this.pendingEvents.size - } - /** Up to {@link MAX_BATCH_SIZE} ids, foreground queue first (same insertion order within each set). */ private takeNextStatsSlice(): string[] { const out: string[] = [] @@ -186,7 +182,6 @@ class NoteStatsService { opts?: { foreground?: boolean } ) { const eventId = this.statsKey(event.id) - const idShort = `${eventId.slice(0, 12)}…` const foreground = opts?.foreground === true const rememberRoot = () => { @@ -204,12 +199,6 @@ class NoteStatsService { this.pendingEvents.delete(eventId) this.pendingForeground.add(eventId) } - logger.debug('[NoteStats] fetchNoteStats: merged into existing pending batch', { - eventId: idShort, - kind: event.kind, - pendingForeground: this.pendingForeground.size, - pendingBackground: this.pendingEvents.size - }) this.maybeFlushStatsBatch(foreground) return } @@ -220,10 +209,6 @@ class NoteStatsService { if (foreground) { this.deferredRequeueForeground.add(eventId) } - logger.debug('[NoteStats] fetchNoteStats: deferred (already processing same id)', { - eventId: idShort, - kind: event.kind - }) return } @@ -235,15 +220,6 @@ class NoteStatsService { } rememberRoot() - logger.debug('[NoteStats] fetchNoteStats: queued new id', { - eventId: idShort, - kind: event.kind, - foreground, - pendingForeground: this.pendingForeground.size, - pendingBackground: this.pendingEvents.size, - immediateBatch: this.statsPendingSize() >= this.MAX_BATCH_SIZE - }) - this.maybeFlushStatsBatch(foreground) } @@ -276,20 +252,12 @@ class NoteStatsService { return } if (this.processBatchRunning) { - logger.debug('[NoteStats] processBatch: skipped (already running)', { - pendingForeground: this.pendingForeground.size, - pendingBackground: this.pendingEvents.size - }) return } if (this.pendingForeground.size === 0 && this.pendingEvents.size === 0) { return } - logger.debug('[NoteStats] processBatch: running', { - pendingForeground: this.pendingForeground.size, - pendingBackground: this.pendingEvents.size - }) this.processBatchRunning = true if (this.batchTimeout) { clearTimeout(this.batchTimeout) @@ -298,13 +266,6 @@ class NoteStatsService { try { const eventsToProcess = this.takeNextStatsSlice() - logger.debug('[NoteStats] processBatch slice', { - count: eventsToProcess.length, - ids: eventsToProcess.map((id) => `${id.slice(0, 12)}…`), - remainingForeground: this.pendingForeground.size, - remainingBackground: this.pendingEvents.size, - concurrency: this.STATS_SLICE_CONCURRENCY - }) for (let i = 0; i < eventsToProcess.length; i += this.STATS_SLICE_CONCURRENCY) { const chunk = eventsToProcess.slice(i, i + this.STATS_SLICE_CONCURRENCY) await Promise.all(chunk.map((eventId) => this.processSingleEvent(eventId))) @@ -319,9 +280,6 @@ class NoteStatsService { private async processSingleEvent(eventId: string) { if (this.processingCache.has(eventId)) { - logger.debug('[NoteStats] processSingleEvent: skip (concurrent in-flight)', { - eventId: `${eventId.slice(0, 12)}…` - }) return } @@ -331,7 +289,7 @@ class NoteStatsService { this.pendingFetchFavoriteRelays.delete(eventId) let publishedStatsSnapshot = false - const markStatsLoaded = (rawStatsKey: string, reason: string) => { + const markStatsLoaded = (rawStatsKey: string) => { if (publishedStatsSnapshot) return publishedStatsSnapshot = true const statsKey = this.statsKey(rawStatsKey) @@ -339,35 +297,19 @@ class NoteStatsService { ...(this.noteStatsMap.get(statsKey) ?? {}), updatedAt: dayjs().unix() }) - const subscriberCount = this.noteStatsSubscribers.get(statsKey)?.size ?? 0 - logger.debug('[NoteStats] processSingleEvent: snapshot published', { - statsKey: `${statsKey.slice(0, 12)}…`, - reason, - subscriberCount - }) this.notifyNoteStats(statsKey) } let resolvedEvent: Event | undefined try { - logger.debug('[NoteStats] processSingleEvent: start', { eventId: `${eventId.slice(0, 12)}…` }) // Synthetic RSS/Web thread parents are not published; use the instance from fetchNoteStats. const synthetic = this.pendingSyntheticRootById.get(eventId) this.pendingSyntheticRootById.delete(eventId) const callerRoot = this.pendingStatsRootEventById.get(eventId) this.pendingStatsRootEventById.delete(eventId) resolvedEvent = synthetic ?? callerRoot ?? (await eventService.fetchEvent(eventId)) - const rootSource = synthetic ? 'synthetic-rss' : callerRoot ? 'caller-card' : resolvedEvent ? 'fetchEvent' : 'none' - logger.debug('[NoteStats] processSingleEvent: root resolution', { - eventId: `${eventId.slice(0, 12)}…`, - rootSource, - resolvedKind: resolvedEvent?.kind - }) if (!resolvedEvent) { - logger.debug('[NoteStats] processSingleEvent: no root event — publishing empty snapshot', { - eventId: `${eventId.slice(0, 12)}…` - }) - markStatsLoaded(eventId, 'no-root-event') + markStatsLoaded(eventId) return } @@ -379,10 +321,6 @@ class NoteStatsService { this.updateNoteStatsByEvents(preFromSession, resolvedEvent.pubkey, { statsRootEvent: resolvedEvent }) - logger.debug('[NoteStats] processSingleEvent: pre-merged session interactions', { - eventId: `${resolvedEvent.id.slice(0, 12)}…`, - count: preFromSession.length - }) } } @@ -399,21 +337,11 @@ class NoteStatsService { firstRelayResultGraceMs: false as const } - const events: Event[] = [] - logger.debug( - '[NoteStats] Fetching stats for event', - resolvedEvent.id.substring(0, 8), - 'from', - finalRelayUrls.length, - 'relays' - ) - const { queryService } = await import('@/services/client.service') const onStatsEvent = (evt: Event) => { this.updateNoteStatsByEvents([evt], resolvedEvent!.pubkey, { statsRootEvent: resolvedEvent! }) - events.push(evt) } await Promise.all([ nonSocial.length > 0 @@ -430,21 +358,16 @@ class NoteStatsService { : Promise.resolve([] as Event[]) ]) - logger.debug('[NoteStats] processSingleEvent: relay fetch finished', { - eventId: `${resolvedEvent.id.slice(0, 12)}…`, - interactionEventsReceived: events.length - }) - - markStatsLoaded(resolvedEvent.id, 'fetch-ok') + markStatsLoaded(resolvedEvent.id) } catch (err) { logger.warn('[NoteStats] processSingleEvent failed', { eventId: eventId.substring(0, 8), error: err instanceof Error ? err.message : String(err) }) - markStatsLoaded(resolvedEvent?.id ?? eventId, 'catch-after-error') + markStatsLoaded(resolvedEvent?.id ?? eventId) } finally { if (!publishedStatsSnapshot) { - markStatsLoaded(resolvedEvent?.id ?? eventId, 'finally-fallback') + markStatsLoaded(resolvedEvent?.id ?? eventId) } this.processingCache.delete(eventId) if (this.inFlightDeferredFavoriteRelays.has(eventId)) {