OverviewFilesCommitsIssuesDocsReleasesPeers

atproto-did-peer commits / 45f9386

0.2.4: the ROUTER also gated on repoKey — a stateless peer was never fronted
0.2.3 made repoKey optional in DidPeer.onAnnounce, but DidPeerRouter._onAnnounce had its OWN gate: if (!a || !a.did || !a.repoKey || !a.firehoseKey) return The router dispatches first, so a stateless peer's announce ({firehoseKey, repoKey:null}) was dropped before it ever reached the DidPeer. Verified live: after flipping tabertron's wj62 to projectRepoCore:false the node came up healthy and kept serving, but the bridge showed its front live=false and never re-fronted it — the fix in DidPeer alone was not enough. Only the firehose key is genuinely required: it is the trust anchor (it carries the signed commits). The repo is the derivable half. Also fixes a second-order hole on the EXISTING-front path. A front that already holds a repo-core replica keeps it when the peer stops projecting; that replica then freezes while the head advances, so getRepoFromCommit's data-root assertion fails — safe, but permanently broken, with no route to the RPC fallback. The router now drops the stale replica when an announce arrives with repoKey:null, so getRepo takes the derive-over-RPC path. The firehose is untouched. Suite green: commitops + router + co-owned + no-repo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
45f93861b043f1a700e0c3668091f9bae1b4ec61
by plankatron <fleeky@gmail.com> · 2026-07-26T23:57:49.000Z

Changed files (2) +18 -2

lib/did-peer.js +17 -1
……@@ -475,7 +475,13 @@ export class DidPeerRouter {
475475 // Learn a (did, firehoseKey) co-owner from a PUSHED announce; open its front (best-effort). A DIFFERENT
476476 // firehoseKey under the same DID is a DISTINCT co-owner (tracked, never evicting the other).
477477 async _onAnnounce (a, rpc, conn) {
478 if (!a || !a.did || !a.repoKey || !a.firehoseKey) return
478 // repoKey is OPTIONAL — same contract as DidPeer.onAnnounce. A peer running the stateless virtual
479 // device (serve-membrane projectRepoCore:false) publishes no membrane-repo core and announces
480 // { firehoseKey, repoKey: null }; its repo is DERIVED over the get-repo-car RPC. Requiring repoKey
481 // HERE silently dropped that announce before it ever reached the DidPeer, so the peer went live:false
482 // and was never fronted — the fix in DidPeer.onAnnounce alone was not enough, because the router
483 // gates first. The firehose key is the only thing genuinely required: it is the trust anchor.
484 if (!a || !a.did || !a.firehoseKey) return
479485 const did = a.did
480486 const fhKeyHex = a.firehoseKey
481487 if (a.handle) this._setHandle(a.handle, did)
……@@ -486,6 +492,16 @@ export class DidPeerRouter {
486492 if (existing) { // refresh write rpc + handle; nudge fetch (cores re-replicate via corestore regardless)
487493 if (this._useRpc && rpc) existing.rpc = rpc
488494 if (a.handle) existing.handle = a.handle
495 // The peer went STATELESS while we still hold a repo-core replica (it used to project, now it
496 // announces repoKey:null). That replica is frozen at whatever it last replicated, so once the head
497 // advances getRepoFromCommit's data-root assertion fails — safe, but permanently broken. Drop it so
498 // getRepo takes the derive-over-RPC path instead. The firehose (the trust anchor) is untouched.
499 if (!a.repoKey && existing.repo) {
500 const stale = existing.repo
501 existing.repo = null
502 existing._repoKey = null
503 try { await stale.close() } catch {}
504 }
489505 if (existing.seq) existing.seq.core.update().catch(() => {})
490506 this._wake(did)
491507 return
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "atproto-did-peer",
3 "version": "0.2.3",
3 "version": "0.2.4",
44 "description": "Keyless, direction-free P2P reader/seeder for an atproto DID's repo+firehose Hypercores: announce-push discovery + event-driven head reconciliation + a keyless read surface. The shared primitive beneath atproto-bridge, atproto-relay and favela (extracted from atproto-bridge did-peer.js).",
55 "type": "module",
66 "main": "index.js",