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)) {