Skip to content

Commit c99aa28

Browse files
beacon: canonical profile URL is bare /<hex> (was /p/<hex>)
Cleaner scheme — the pubkey is the path: / home /<hex> human profile page (HTML + OGP) /.well-known/did/nostr/<hex>.json machine DID document RegExp route constrained to 64-hex so it never collides with /api, /healthz, /.well-known or static assets. Legacy #<hex> links still resolve.
1 parent 8a0d4e0 commit c99aa28

2 files changed

Lines changed: 10 additions & 9 deletions

File tree

public/index.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ <h1>A directory of <em style="font-style:italic">did:nostr</em> identities</h1>
132132
function cardHtml(p) {
133133
const c = content(p);
134134
const ct = p._counts || {};
135-
return `<a class="card" href="/p/${p.pubkey}" data-pk="${p.pubkey}">
135+
return `<a class="card" href="/${p.pubkey}" data-pk="${p.pubkey}">
136136
${avatar(c, p.pubkey)}
137137
<div class="name">${esc(c.name || c.display_name || short(p.pubkey))}</div>
138138
${c.nip05 ? `<div class="nip05">${esc(c.nip05)}</div>` : ''}
@@ -197,7 +197,7 @@ <h2>${esc(c.name || short(pk))}</h2>
197197
<div class="sections">
198198
<div class="panel"><h3>DID document</h3><pre>${highlight(didOnly(doc))}</pre></div>
199199
<div class="panel"><h3>Following · ${follows.length}</h3>
200-
${follows.length ? `<div class="follows">${follows.slice(0, 96).map((d) => { const fk = d.replace('did:nostr:', ''); return `<a class="fav" data-pk="${fk}" style="${gradStyle(fk)}" title="${esc(fk)}" href="/p/${fk}"></a>`; }).join('')}</div>`
200+
${follows.length ? `<div class="follows">${follows.slice(0, 96).map((d) => { const fk = d.replace('did:nostr:', ''); return `<a class="fav" data-pk="${fk}" style="${gradStyle(fk)}" title="${esc(fk)}" href="/${fk}"></a>`; }).join('')}</div>`
201201
: '<div style="color:var(--faint);font-size:.9rem">No follow list indexed.</div>'}
202202
</div>
203203
</div>
@@ -215,7 +215,7 @@ <h2>${esc(c.name || short(pk))}</h2>
215215
}
216216

217217
function route() {
218-
const m = location.pathname.match(/^\/p\/([0-9a-f]{64})$/i);
218+
const m = location.pathname.match(/^\/([0-9a-f]{64})$/i);
219219
if (m) return profile(m[1].toLowerCase());
220220
const h = location.hash.slice(1); // legacy #<hex> links still resolve
221221
if (/^[0-9a-f]{64}$/.test(h)) return profile(h);
@@ -227,7 +227,7 @@ <h2>${esc(c.name || short(pk))}</h2>
227227
const el = e.target.closest('a[data-pk]');
228228
if (!el || e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0) return;
229229
e.preventDefault();
230-
navigate('/p/' + el.dataset.pk);
230+
navigate('/' + el.dataset.pk);
231231
});
232232
$('#q').addEventListener('input', onSearch);
233233
window.addEventListener('popstate', route);

src/server.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,18 @@ export async function startServer(port = process.env.PORT || 3000) {
5050
// home shell (default OGP)
5151
app.get('/', (_req, res) => res.type('html').send(renderShell()));
5252

53-
// per-profile shell with that identity's OGP (crawlable canonical URL)
54-
app.get('/p/:id', async (req, res, next) => {
53+
// per-profile shell at /<pubkey> with that identity's OGP (crawlable canonical
54+
// URL). RegExp route constrained to 64-hex, so it never collides with /api,
55+
// /healthz, /.well-known, or static assets.
56+
app.get(/^\/([0-9a-f]{64})$/, async (req, res, next) => {
5557
try {
56-
const id = String(req.params.id).toLowerCase();
57-
if (!/^[0-9a-f]{64}$/.test(id)) return res.type('html').send(renderShell());
58+
const id = req.params[0].toLowerCase();
5859
const p = await getProfile(id);
5960
let c = {}; try { c = JSON.parse(p?.content || '{}'); } catch { /* malformed */ }
6061
const name = c.name || c.display_name || `did:nostr:${id.slice(0, 8)}…`;
6162
const about = String(c.about || `A did:nostr identity · ${id.slice(0, 16)}…`).replace(/\s+/g, ' ').slice(0, 180);
6263
res.type('html').send(renderShell({
63-
title: `${name} · Beacon`, description: about, url: `${SITE}/p/${id}`,
64+
title: `${name} · Beacon`, description: about, url: `${SITE}/${id}`,
6465
type: 'profile', image: c.picture || '',
6566
}));
6667
} catch (e) { next(e); }

0 commit comments

Comments
 (0)