aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-26 07:55:28 -0700
committerAdam Soltys <[email protected]>2026-08-26 07:55:28 -0700
commit5b92c9384074e0d94c784193be00f03a08bb9599 (patch)
tree6ec1c12af97cde6cd4b8b92f67c67c7832257eae /src
parent14817c69079cd4cf92b0e7a0e630e68d4c8211c0 (diff)
downloadcoinosv3-5b92c9384074e0d94c784193be00f03a08bb9599.tar.gz
coinosv3-5b92c9384074e0d94c784193be00f03a08bb9599.zip
The old address book habit carries over: v3.coinos.io/<username> 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
Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_019eA8JRq9Wr7z2fRQk99HLi
Diffstat (limited to 'src')
-rw-r--r--src/features/messages.js29
1 files changed, 29 insertions, 0 deletions
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/<username> 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(() => {