Search perf, NIP fixes, replying-to usernames, highlights & mentions filter#135
Conversation
Replace sequential for...of loop in searchByAnyTerms with Promise.allSettled so that each OR term is searched concurrently. Pre-resolve fallback relay set once before parallel execution to eliminate the memoization race in ensureFallbackRelaySet. Individual term failures are isolated and don't kill the batch. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace 3 serial for...of author resolution loops with Promise.all so that multiple by: tokens are resolved concurrently. Each token is individually wrapped in try/catch — decode failures return null and are filtered out, matching the previous skip-and-warn behavior. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract measureRelayPing and measureAllRelayPings into a new src/lib/relayPing.ts module with injectable dependencies for testability. The key fix: each ping subscription now receives a relaySet scoped to the single target relay (NDKRelaySet.fromRelayUrls([relayUrl])), so the REQ is sent only to the relay being measured. Previously the subscription went to all connected relays, making ping measurements inaccurate. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show first 50 results initially with a "Show more" button that loads 50 more at a time. Pagination resets only when the search query changes, not when results mutate (e.g. NIP-05 verified reordering), avoiding the infinite-reset loop. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The result deduplication in searchEvents used arr.findIndex(x => x.id === e.id) which is O(n) per element, yielding O(n^2) total. Replace with a Set<string> lookup for O(n). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
NIP-51 specifies 'relay' tags for blocked relay lists (kind 10006) and search relay lists (kind 10007). The code was only checking for 'r' tags, which is the NIP-65 convention for kind 10002. Now checks for both 'relay' (per spec) and 'r' (for compatibility with mis-tagged events in the wild). Without this fix, user-configured blocked relays and search relays were silently ignored. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
filterNip50Relays was injecting fallback relays (primal, snort, ditto) without verifying they actually support NIP-50. This caused non-NIP-50 relays to receive search: filters and return extraneous results. Now runs checkNip50Support on each fallback candidate before adding it to the supported list, matching the verification applied to the primary relay set. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Queries like 'language:en' were silently dropped because: 1. buildSearchQueryWithExtensions returned early on empty baseQuery 2. search.ts used 'cleanedQuery || undefined' which made '' falsy Now buildSearchQueryWithExtensions produces extension-only strings when extensions are present, and the caller always invokes it so that extension-only queries reach the relay as valid search filters. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds mentions:<user> syntax to find events that mention a specific user via NIP-27 p-tags. Supports multiple mentions: tokens and combines with by: and free-text search terms. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Highlights matching search terms in note content with a blue background. Extracts terms from the query (excluding filter tokens like by:, kind:, mentions:) and wraps matches in <mark> elements. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace raw nevent identifiers with resolved display names for reply parent authors. Uses e-tag[4] pubkey when available (NIP-10), falls back to fetching the parent event with relay hint from e-tag[2]. Includes module-level profile cache with TTL, in-flight deduplication, and IntersectionObserver for lazy resolution of off-screen notes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract resolveProfileName to shared profileUtils so NoteHeader, InlineNostrToken, and EventCard all use the same cached resolver. When default relays return no profile, retry against profile-specific relays (purplepag.es, search.nos.today, relay.nostr.band). Also fixes double npub:npub1... prefix in fallback display. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add 6s timeout to parent event fetch to prevent hanging - Try relay hint first, then fall back to default relays - Use relaySets.profileSearch() instead of hardcoded RELAYS.PROFILE_SEARCH to respect user's blocked relay preferences (NIP-51 kind 10006) - EventCard InlineAuthor now uses shared resolveProfileName for consistent caching and profile relay fallback Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@alltheseas is attempting to deploy a commit to the dergigi's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Just saw this now 😅 I'll try to have a look soon |
|
all good, I think ants are the best hope for non-native search at this point. no pressure. will submit nip-66 upgrades based on my nostrability/outbox nip-66 learnings shortly as well. during my outbox benchmarks I found that less than 1/2 relays return real info (many dead/offline/non-responsive). by adding nip-66 to outbox algos as a pre-filter for relay liveness, this reduces load times in the range of -40% to -50%. i suspect there will be benefit with search as well. |
Configuration for NIP-66 relay liveness integration: - 30-min cache/refresh interval (monitors publish hourly) - 15s fetch timeout - 80% safety threshold to prevent catastrophic filtering - 24h max age for dead relay entries before degrading to unknown Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New module that fetches kind 30166 events from relay monitors to determine relay liveness, RTT, and NIP support. Key design decisions: - Asymmetric staleness: alive entries trusted indefinitely (false positive = just a timeout), dead entries expire after 24h and degrade to 'unknown' (false negative = missed results) - Safety valve: if filtering would remove >80% of relays, skip entirely to prevent catastrophic failure from bad monitor data - Multiple sources: queries known monitor relays + user's connected NDK pool relays for broader coverage - Persistent cache via localStorage with 30-min background refresh - Concurrent call coalescing to prevent duplicate fetches Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire NIP-66 data into the relay selection pipeline: - filterNip50Relays: pre-filter dead relays before probing, use NIP-66 N tags as fast path to skip HTTP NIP-11 probes - getNip50SearchRelaySet: enrich candidates with NIP-66-discovered NIP-50 relays, remove dead debug loop - getBroadRelaySet: filter dead relays from broad set - getOutboxSearchCapableRelays: pre-filter author's write relays before expensive NIP-11 probing - connect(): fire-and-forget ensureNip66Data() so cache is populated before first search - Relay monitoring lifecycle: start/stop NIP-66 background refresh All integration points use only cached data (synchronous lookups). NIP-66 never blocks search — if cache is empty, all functions fall through to existing behavior unchanged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Display monitor data next to each relay in the UI: - Green [45ms] when monitor reports alive with RTT - Red [dead] when monitor reports dead - Nothing when no monitor data available Visual indicator only — no behavioral change. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Self-contained benchmark script measuring NIP-66 relay liveness filtering impact across four phases: - Phase A: HTTP-only NIP-11 probing (3-endpoint, no NIP-66) - Phase B: NIP-66 pre-filtering + NIP-50 fast path - Phase C: actual NIP-50 search comparison (opt-in via --search) - Phase D: WebSocket connection timing with/without filtering Key findings from benchmark runs: - 51 NIP-50 relays discovered via NIP-66 beyond 7 hardcoded - 48% fewer HTTP probes (dead relay filtering + fast path) - +8% search event recall from extra NIP-50 relay discovery - 1 NIP-50 relay rescued per run (HTTP timeout, NIP-66 knows) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
here is the follow-on nip-66 PR: #136 |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
dergigi
left a comment
There was a problem hiding this comment.
Solid PR — NIP-51 tag parsing fix, parallel search, scoped relay pings, profile resolution cleanup, search highlighting, pagination, and mentions filter all look good.
Two nits:
-
Dead ternary in EventCard.tsx —
result.isNpubFallback ? result.display : result.display— both branches are identical, can simplify to justresult.display. -
bench/nip66.ts seems to have leaked from the NIP-66 branch (#136) into this PR.
Otherwise, nice work. The NIP-51 relay tag fix alone is worth merging. Perf improvements are real — Set-based dedup and parallel OR search are solid wins.
Recommend: merge this first, then #136 stacks cleanly on top.






Summary
Bug fixes
relaytags (per spec) in addition tortagslanguage:enno longer drops the search field when base query is emptyPerformance
Promise.allSettledPromise.allO(n)Set-based deduplication replacingO(n^2)findIndexFeatures
mentions:search filter for #p tag queriesTest plan
language:enextension-only query returns resultsmentions:npub...filter returns tagged events🤖 Generated with Claude Code