From 5b92c9384074e0d94c784193be00f03a08bb9599 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 26 Aug 2026 07:55:28 -0700 Subject: The old address book habit carries over: v3.coinos.io/ opens that user's profile — the server already hands every stray path to the app, which now reads a lone name (or npub, or bare key) off the doormat, asks the registrar who lives there, and shows you in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi --- src/features/messages.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'src/features') diff --git a/src/features/messages.js b/src/features/messages.js index 9336f7c..f563435 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -25,6 +25,7 @@ import { import { makeDMRumor, unwrapDM, wrapDM } from '../dm.js'; import { saveInbox } from '../dm-inbox.js'; import { makeSearcher, resultRows, fallbackAvatar } from '../recipient-search.js'; +import { getNetwork } from '../api.js'; import { hexToBytes, bytesToHex } from '@noble/hashes/utils'; import { t } from '../i18n.js'; @@ -607,6 +608,18 @@ export function messagesFeature(ctx) { const urlInvite = typeof location !== 'undefined' ? parseInviteLink(location.href) : null; if (urlInvite) { try { history.replaceState(null, '', '/'); } catch {} } + // coinos.io/ parity: a claimed name (or a raw npub / hex key) as + // the whole URL path deep-links to that profile. Real files never reach the + // app — the server tries them first — and gift/invite links carry their own + // multi-segment paths, which this single-segment shape can't match. The + // path is consumed immediately so a reload lands on the wallet as usual. + const urlProfile = (() => { + if (typeof location === 'undefined' || urlInvite) return null; + const m = location.pathname.match(/^\/([A-Za-z0-9._-]{1,64})\/?$/); + return m ? m[1] : null; + })(); + if (urlProfile) { try { history.replaceState(null, '', '/'); } catch {} } + // ---- push notifications ------------------------------------------------- // The nwcpush notifier watches relays for what it can see without keys: // kind-1059 wraps p-tagged at us (DMs, direct invites), zap receipts @@ -2380,6 +2393,22 @@ export function messagesFeature(ctx) { loadLinkInvite(urlInvite); setTimeout(() => { ui.chatOpen = true; ui.msgView = 'home'; render(); }, 0); } + if (urlProfile) { + (async () => { + let pk = parseNostrPubkey(urlProfile); + if (!pk && /^[a-z0-9._-]{1,30}$/i.test(urlProfile)) { + // same registrar + domain rule the names feature uses + const domain = getNetwork() === 'mutinynet' ? 'staging.coinos.io' : 'coinos.io'; + const name = urlProfile.toLowerCase(); + try { + const j = await fetch(`https://names.coinos.io/.well-known/nostr.json?name=${encodeURIComponent(name)}&domain=${domain}`) + .then((r) => r.json()); + pk = (j.names || {})[name] || null; + } catch {} + } + if (pk && /^[0-9a-f]{64}$/.test(pk)) openProfile(pk); + })(); + } window.addEventListener('resize', onViewportResize); window.visualViewport?.addEventListener('resize', onViewportResize); allUnsubs.push(() => { -- cgit v1.2.3