OverviewFilesCommitsIssuesDocsReleasesPeers

favela-surface commits / 986fed1

0.0.64: show this node's identity root on settings and status
Settings named nothing but the feed key — a locator that changes with a feed migration — and status said "linked" without saying which identity. The identity every post is signed under (the keet / hyperident root, the authority of every favela:// URI) already reached the surface as profiles[feed].root from the founder record; both pages dropped it. Settings: "Your identity <prefix>…" with the full key one click away (keyline, as every key), or a warning when the node has no identity yet. Status: the root next to "linked". Verified the daemon side on a live node: tabertron's favela-peer returns its own feed in `profiles` with root 33480a56f618…. Tests red first (3), suite 242/242. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
986fed12ec830901faf171a45381b42f9cc9eead
by plankatron <fleeky@gmail.com> · 2026-10-13T16:47:54.000Z

Changed files (3) +42 -4

lib/pages.js +18 -3
……@@ -1674,8 +1674,19 @@ export function settings (profile, message, handle = null, namespace = null, tok
16741674 const shownBanner = p.banner
16751675 ? '<p><img class="banner-lg" src="/avatar/' + esc(p.banner) + '" alt="your banner"></p>'
16761676 : ''
1677 // ⛔ THE IDENTITY ROOT, which settings never showed. It named nothing but the feed key — a LOCATOR
1678 // that changes with a feed migration — while the identity every post is signed under (the keet /
1679 // hyperident public key, the authority of every `favela://` URI) was already in `profile.root` from
1680 // the founder record and dropped here. Demoted like every key (keys.test.js): a short prefix in view,
1681 // the whole thing one click away and selectable.
1682 const identity = p.root
1683 ? '<p>Your identity <code>' + esc(String(p.root).slice(0, 12)) + '…</code></p>' +
1684 keyline('full identity key', p.root) +
1685 '<p class="who">The key your posts are signed under. It stays the same across devices and feed ' +
1686 'moves, and it is what other people verify you by.</p>'
1687 : '<p class="warn">This node has no identity yet, so it cannot post or claim a name.</p>'
16771688 return layout('settings', note + updateSettings(update) + blueskySection(did, reach) + fediverseSection(reach) +
1678 '<h1>Settings</h1>' + shown +
1689 '<h1>Settings</h1>' + identity + shown +
16791690 '<form method="post" action="/settings" enctype="multipart/form-data">' +
16801691 '<p><label>Display name<br><input type="text" name="name" value="' + esc(p.name || '') +
16811692 '" placeholder="what people see instead of 64 hex characters"></label></p>' +
……@@ -1861,6 +1872,8 @@ export function status ({ me = null, ns = null, following = [], missing = [], pr
18611872 const row = (k, v, why) => '<tr><td class="who">' + esc(k) + '</td><td>' + v +
18621873 (why ? '<br><span class="who">' + esc(why) + '</span>' : '') + '</td></tr>'
18631874
1875 // The identity root of THIS node, from the same `profiles` map every byline uses.
1876 const myRoot = me && me.feed && profiles && profiles[me.feed] ? profiles[me.feed].root || null : null
18641877 const held = (following || []).map((f) => (typeof f === 'string' ? f : f && f.feed)).filter(Boolean)
18651878 const gone = new Set((missing || []).map((f) => (typeof f === 'string' ? f : f && f.feed)).filter(Boolean))
18661879
……@@ -1884,8 +1897,10 @@ export function status ({ me = null, ns = null, following = [], missing = [], pr
18841897
18851898 '<h2>This node</h2><table>' +
18861899 row('feed', me && me.feed ? '<code>' + short(me.feed) + '</code>' : '<span class="who">unknown</span>') +
1887 row('identity', me && me.linked ? 'linked' : '<span class="warn-inline">not linked</span>',
1888 me && me.linked ? '' : 'This node cannot claim a name or sign until an identity is minted.') +
1900 row('identity', me && me.linked
1901 ? 'linked' + (myRoot ? ' — <code>' + short(myRoot) + '</code>' + keyline('full identity key', myRoot) : '')
1902 : '<span class="warn-inline">not linked</span>',
1903 me && me.linked ? '' : 'This node cannot claim a name or sign until an identity is minted.') +
18891904 '</table>' +
18901905
18911906 '<h2>Namespace</h2><table>' +
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "favela-surface",
3 "version": "0.0.63",
3 "version": "0.0.64",
44 "description": "The favela renderer \u2014 server-side HTML over the daemon's socket. No storage, no keys, no swarm.",
55 "type": "module",
66 "main": "index.js",
test/pages.test.js +23 -0
……@@ -864,3 +864,26 @@ test('★ an exempt phone is not nagged', (t) => {
864864 t.absent(/freeze the node/.test(h))
865865 t.absent(/<button id="app-battery">/.test(h))
866866})
867
868// ⛔ THE IDENTITY IS THE ROOT, AND THE NODE NEVER SHOWED IT. Settings and status named the FEED key (a
869// locator: it changes with a feed migration) and said "linked", but never the identity root — the
870// keet / hyperident public key every post is signed under and every `favela://` URI names. The daemon
871// already sends it (`profiles[feed].root`, from the founder record); the pages dropped it.
872test('settings shows this node\'s identity root, copyable in full', async (t) => {
873 const root = 'ef'.repeat(32)
874 const html = settings({ name: 'Alice', root }, null, null, null)
875 t.ok(html.includes(root), 'the whole 64-character root is on the page')
876 t.ok(/identity/i.test(html), 'labelled as the identity')
877})
878
879test('settings without a root says so instead of showing nothing', async (t) => {
880 const html = settings({ name: 'Alice' }, null, null, null)
881 t.ok(/no identity/i.test(html), 'an unlinked node is told it has no identity yet')
882})
883
884test('status shows the identity root next to "linked"', async (t) => {
885 const feed = 'a'.repeat(64)
886 const root = 'ef'.repeat(32)
887 const html = status({ me: { feed, linked: true }, profiles: { [feed]: { root } } })
888 t.ok(html.includes(root), 'the root is on the status page')
889})