OverviewFilesCommitsIssuesDocsReleasesPeers

favela-surface commits / d701ac0

0.0.61: record the fediverse name a bridge granted
⛔ RECORDED, NOT CLAIMED. Asking a bridge for a name means reaching for a projection, which test/boundary.test.js forbids this package outright — 'the surface holds a socket and nothing else'. Recording the answer is just data. ⚠ Deliberately its own field, not folded in beside the DID. identity.md §5.1's `credential` is the designated ATPROTO one, and the networks are not symmetric: on bsky you hold the key, on the fediverse a bridge holds it and you hold a grant. One input each, labelled for what it is — which is also why nothing secret is entered for the fediverse. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
d701ac0d609ebfaaa832eee1cf4c31f406a84540
by plankatron <fleeky@gmail.com> · 2026-09-10T22:16:14.000Z

Changed files (3) +21 -3

lib/pages.js +17 -1
……@@ -1525,6 +1525,22 @@ export function reachSettings (reach) {
15251525 : '<p class="warn">No Bluesky identity is designated, so nothing is published there even ' +
15261526 'with the box ticked. Paste a DID this node holds, or leave it empty to keep it off.</p>')
15271527
1528 // ⛔ A NAME YOU HOLD, RECORDED — not a claim performed here. Asking a bridge for a name means
1529 // reaching for a projection, which `test/boundary.test.js` forbids this package outright ("the
1530 // surface holds a socket and nothing else"). Recording the answer is just data, and the daemon
1531 // already stores it beside `networks`.
1532 //
1533 // ⚠ It is deliberately NOT beside the DID field. §5.1's `credential` is the designated ATPROTO one
1534 // and the two networks are not symmetric: on bsky you hold the key, on the fediverse a bridge
1535 // holds it and you hold a grant. One input each, labelled for what it actually is.
1536 const fedi = '<p><label>Fediverse name<br>' +
1537 '<input type="text" name="fediverse" value="' + esc(reach.fediverse || '') + '" ' +
1538 'placeholder="name@bridge" autocomplete="off"></label></p>' +
1539 (reach.fediverse
1540 ? '<p class="who">Publishing to the fediverse as <code>' + esc(reach.fediverse) + '</code></p>'
1541 : '<p class="who">A bridge serves your feed under this name. It holds the signing key; you ' +
1542 'hold the name — which is why nothing secret goes here.</p>')
1543
15281544 return '<h2>Publishing</h2>' +
15291545 (on.size === 0
15301546 ? '<p class="who">Nothing you write leaves favela.</p>'
……@@ -1532,7 +1548,7 @@ export function reachSettings (reach) {
15321548 '<form method="post" action="/reach">' +
15331549 box('bsky', 'Bluesky', 'Plain text only, up to 300 characters. Longer posts are withheld, not shortened.') +
15341550 box('fediverse', 'Mastodon and the fediverse', 'Keeps headings, lists and links. No length limit.') +
1535 cred +
1551 cred + fedi +
15361552 '<p class="who">⛔ A post sent to either network cannot be recalled from it. Turning a network ' +
15371553 'off stops future posts; it does not retract the ones already sent.</p>' +
15381554 '<button>save</button></form>'
lib/router.js +3 -1
……@@ -870,8 +870,10 @@ export async function route (req, res, ctx) {
870870 // withholding is the fail-closed state. Leaving it unsendable would make "stop publishing under
871871 // this identity" impossible from the only surface that can say it.
872872 const credential = String(form.credential || '').trim() || null
873 // The name a bridge grant produced. Recorded, never claimed here — see reachSettings().
874 const fediverse = String(form.fediverse || '').trim() || null
873875 try {
874 await client.call('set-reach', { networks, credential })
876 await client.call('set-reach', { networks, credential, fediverse })
875877 } catch (err) {
876878 return seeOther(res, '/settings?m=' + encodeURIComponent(err.message))
877879 }
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "favela-surface",
3 "version": "0.0.60",
3 "version": "0.0.61",
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",