Search improvements — NIP-50 relay detection + smarter zero-results (roadmap #12)

- relayInfo.ts: checkNip50Support fetches NIP-11 relay info (Accept:
  application/nostr+json) and checks supported_nips for 50; results
  cached per session with 4s timeout; getNip50Relays checks all relays
  in parallel

- SearchView: relay NIP-50 support checked on mount in the background
  and shown as context in the idle state ("N of M relays support
  full-text search") and in zero-results states

- Zero results for full-text search now shows:
  - relay NIP-50 count (or "none of your relays support full-text")
  - prominent "Search #<query>" one-click button to retry as hashtag

- Tabs (notes / people) now always rendered after any search, not only
  when both result types are non-empty — makes the UI consistent

- Per-tab zero-results explanations: people tab explains NIP-50
  requirement when no relay supports it

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jure
2026-03-10 20:21:22 +01:00
parent abd38a4edd
commit d72dfe56d8
2 changed files with 143 additions and 47 deletions

View File

@@ -0,0 +1,34 @@
/** Per-session cache of relay NIP-50 support. */
const nip50Cache = new Map<string, boolean>();
/**
* Fetch a relay's NIP-11 info and return whether it supports NIP-50 (full-text search).
* Results are cached for the session. Times out after 4 s.
*/
export async function checkNip50Support(relayWssUrl: string): Promise<boolean> {
if (nip50Cache.has(relayWssUrl)) return nip50Cache.get(relayWssUrl)!;
const httpUrl = relayWssUrl.replace(/^wss?:\/\//, "https://");
try {
const resp = await fetch(httpUrl, {
headers: { Accept: "application/nostr+json" },
signal: AbortSignal.timeout(4000),
});
const info = await resp.json();
const supported =
Array.isArray(info.supported_nips) && (info.supported_nips as number[]).includes(50);
nip50Cache.set(relayWssUrl, supported);
return supported;
} catch {
nip50Cache.set(relayWssUrl, false);
return false;
}
}
/** Check all provided relay URLs in parallel; return those that support NIP-50. */
export async function getNip50Relays(relayUrls: string[]): Promise<string[]> {
const results = await Promise.all(
relayUrls.map(async (url) => ({ url, ok: await checkNip50Support(url) }))
);
return results.filter((r) => r.ok).map((r) => r.url);
}