diff options
| author | Adam Soltys <[email protected]> | 2026-08-02 17:51:37 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-08-02 17:51:37 -0700 |
| commit | d33643e0683dfac4037c0b61d4aa823782f582e7 (patch) | |
| tree | ff185690f42cbb07d3fa925b2b7e5f8db5e1e53c /names/server.js | |
| parent | 64f96e031e6ea219cc03eb8aa2cc4d0cf7e1f4e4 (diff) | |
| download | coinosv3-d33643e0683dfac4037c0b61d4aa823782f582e7.tar.gz coinosv3-d33643e0683dfac4037c0b61d4aa823782f582e7.zip | |
Recipient search: usernames and npubs, in chat and the Send form
A shared engine (src/recipient-search.js) merges three ranked sources:
an exact npub/hex paste, coinos usernames from the registrar's new
/search prefix endpoint, and NIP-50 kind-0 full-text search on
relay.nostr.band — the approach the major web clients take, since
ordinary relays don't index profiles. Results dedupe by pubkey, fill
avatars in one batched kind-0 fetch, and cache per query so narrowing
never re-hits the network. Input is debounced 300ms and gated by a
searchable() heuristic so addresses, invoices, and keys never trigger
a search.
Chat's New message panel narrows as you type and opens the thread on
pick; the Send form shows the same candidates under the destination
input and picking one runs the normal paste path (payment address →
BIP-353, npub → zap).
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
Diffstat (limited to 'names/server.js')
| -rw-r--r-- | names/server.js | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/names/server.js b/names/server.js index 8a0cab3..d9aa299 100644 --- a/names/server.js +++ b/names/server.js @@ -419,6 +419,20 @@ Bun.serve({ }); } + // Prefix search over registered names — powers recipient search in the + // wallet's DMs. Public data (every name is a public DNS record). + if (url.pathname === '/search' && req.method === 'GET') { + if (!rateOk(ip, 60)) return json({ error: 'rate limited' }, 429); + const q = (url.searchParams.get('q') || '').toLowerCase().trim(); + if (q.length < 2 || q.length > 30) return json({ results: [] }); + const results = Object.entries(state.names) + .filter(([key]) => key.split('@')[0].startsWith(q)) + .sort(([a], [b]) => a.length - b.length || (a < b ? -1 : 1)) + .slice(0, 10) + .map(([key, r]) => ({ address: key, name: key.split('@')[0], pubkey: r.pubkey })); + return json({ results }); + } + // Availability / lookup. Public data (it's DNS). const m = url.pathname.match(/^\/name\/([a-z0-9._-]{1,30})$/); if (m && req.method === 'GET') { |
