OverviewFilesCommitsIssuesDocsReleasesPeers

atproto-bridge commits / c96e0ce

Phase 1b: repoint the membrane onto the shared DidPeerRouter (prod path verified)
pds-serve.js now constructs the canonical atproto-did-peer DidPeerRouter instead of the bridge-local PeerRouter — owns-swarm + injectable join (keeps atproto-identity out of the shared module's runtime deps) + relay + rpc:true (peer-signs-over-RPC write/session/blob path) + resolveVerifyKey. The shared router's surface is a drop-in for every method pds-serve/server-bare call (front/isFronted/list/resolveHandle; front.getRepo..uploadBlob). - verify-key.js: resolvePlcVerifyKey moved out of the retiring peer-router.js (kept bridge-side so atproto-did-peer needs no atproto-identity runtime dep). - ci.yaml: vendor atproto-did-peer into the published closure (declare-your-deps). - pds/package.json: declare atproto-did-peer where pds-serve imports it (linked by sibling symlink, not npm install — the canonical pattern; lockfile left as the repo's existing state, CI installs at root + vendors). VERIFICATION (smoke is env-blocked locally by bare 1.26<1.27, pre-existing): migrated membrane.test.js + membrane-only.test.js to construct the shared DidPeerRouter EXACTLY as pds-serve does — they drive getRepo/getRecord/listRecords/getRepoStatus/ getLatestCommit + createSession (rpc) + describeServer/listRepos/resolveHandle + 404s + UDS status through the real HTTP membrane. Full pds suite green: 46/46, 188/188. The old peer-router.js/peer-front.js/did-peer.js remain as fixtures for the other 12 tests; their migration + deletion is the staged 1b-cleanup follow-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
c96e0ce95bbfaf87683ef85d5a03ed1bd01db381
by plankatron <fleeky@gmail.com> · 2026-07-23T23:00:14.000Z

Changed files (6) +59 -10

.pear-git/ci.yaml +1 -1
……@@ -37,7 +37,7 @@ steps:
3737 # NOTE: requires the sibling repos present on the build machine (KB path or $HOME).
3838 - name: vendor extracted atproto-repo + atproto-identity siblings
3939 run: |
40 for pkg in atproto-repo atproto-identity atproto-store; do
40 for pkg in atproto-repo atproto-identity atproto-store atproto-did-peer; do
4141 SRC=/storage/projects/code/hypercore-kb/hyper-fleeky/$pkg
4242 [ -d "$SRC" ] || SRC="$HOME/hyper-fleeky/$pkg"
4343 rm -rf "node_modules/$pkg" && cp -rL "$SRC" "node_modules/$pkg" && echo "vendored $pkg from $SRC"
pds/bin/pds-serve.js +19 -3
……@@ -16,7 +16,9 @@ import { openCorestore } from 'atproto-store/lib/corestore.js'
1616import { loadConfig } from '../lib/config.js'
1717import { startControl } from '../lib/control.js'
1818import { FleetRelay } from '../lib/fleet-relay.js'
19import { PeerRouter } from '../lib/peer-router.js'
19import { DidPeerRouter } from 'atproto-did-peer'
20import { resolvePlcVerifyKey } from '../lib/verify-key.js'
21import { discoveryTopic } from 'atproto-identity/lib/discovery.js'
2022
2123const cfg = loadConfig()
2224
……@@ -26,7 +28,7 @@ const isBare = typeof Bare !== 'undefined'
2628const { createPdsServer } = await import(isBare ? '../lib/server-bare.js' : '../lib/server.js')
2729
2830// Bare has no global `fetch`; PLC resolution (verify a fronted peer's DID key before serving
29// it — peer-router.js resolvePlcVerifyKey) needs one. Install the WHATWG-standard bare-fetch
31// it — verify-key.js resolvePlcVerifyKey) needs one. Install the WHATWG-standard bare-fetch
3032// global so it works on the prod (bare) runtime. Without this, front() throws "fetch is not
3133// defined" and NO peer is fronted — silently dropping wj62. Node already has global fetch.
3234if (isBare) await import('bare-fetch/global')
……@@ -58,7 +60,21 @@ const handleMapFile = path.join(cfg.storage, 'handle-map.json')
5860let handles = {}
5961try { handles = JSON.parse(fs.readFileSync(handleMapFile, 'utf8')) || {} } catch {}
6062const persistHandles = (obj) => { try { fs.mkdirSync(cfg.storage, { recursive: true }) } catch {}; fs.writeFileSync(handleMapFile, JSON.stringify(obj)) }
61const peers = new PeerRouter(swarm, frontStore, { fronted: cfg.frontedDids, relay, handles, onHandles: persistHandles })
63// The canonical consumer primitive (atproto-did-peer DidPeerRouter — unified across bridge/favela in
64// EXTRACTION-PLAN Phase 1). Owns-swarm mode: it auto-wires onconnection + joins each fronted topic in its
65// ctor (via `join`) + runs the pull-only refresh/failover timer. `rpc: true` opens one protomux-rpc per
66// connection for the peer-signs-over-RPC write/session/blob path. `resolveVerifyKey` fronts a DID with no
67// pre-seeded key via PLC. `relay` folds the freshest co-owner's firehose into the aggregate subscribeRepos.
68const peers = new DidPeerRouter(frontStore, {
69 swarm,
70 join: (did) => { try { swarm.join(discoveryTopic(did), { server: true, client: true }); swarm.flush().catch(() => {}) } catch {} },
71 fronted: cfg.frontedDids,
72 relay,
73 resolveVerifyKey: resolvePlcVerifyKey,
74 rpc: true,
75 handles,
76 onHandles: persistHandles
77})
6278
6379// 1. bsky HTTP+WS membrane — keyless per-DID routing to the fronted peers.
6480const server = createPdsServer({ peers, serverDid: cfg.serverDid, availableUserDomains: [cfg.userDomain], favelaWebUpstream: cfg.favelaWebUpstream })
pds/lib/verify-key.js +18 -0
……@@ -0,0 +1,18 @@
1// resolvePlcVerifyKey — resolve a DID's atproto signing pubkey from its DID document (PLC). The doc's
2// verificationMethod.publicKeyMultibase is the same multibase multikey as a did:key's suffix, so we decode
3// it via `did:key:<multibase>`. `doFetch` is injectable (bare-fetch in prod, global fetch in node/tests).
4//
5// Kept bridge-side (not in the shared atproto-did-peer module) so that module needs no atproto-identity
6// runtime dep. Moved here from the retired lib/peer-router.js (EXTRACTION-PLAN Phase 1b). Passed to
7// DidPeerRouter as its `resolveVerifyKey` so a fronted DID with no add({verifyKey}) resolves via PLC.
8import { decodeDidKey } from 'atproto-identity/lib/did-key.js'
9
10export async function resolvePlcVerifyKey (did, { plcUrl = 'https://plc.directory', doFetch = fetch } = {}) {
11 const res = await doFetch(`${plcUrl}/${did}`)
12 if (!res.ok) throw new Error(`resolvePlcVerifyKey: PLC ${res.status} for ${did}`)
13 const doc = await res.json()
14 const vm = (doc.verificationMethod || []).find((m) => m.id && m.id.endsWith('#atproto')) || (doc.verificationMethod || [])[0]
15 if (!vm || !vm.publicKeyMultibase) throw new Error(`resolvePlcVerifyKey: no verificationMethod for ${did}`)
16 const { pubkey } = decodeDidKey(`did:key:${vm.publicKeyMultibase}`)
17 return pubkey
18}
pds/package.json +1 -0
……@@ -12,6 +12,7 @@
1212 "atproto-repo": "file:../../atproto-repo",
1313 "atproto-identity": "file:../../atproto-identity",
1414 "atproto-store": "file:../../atproto-store",
15 "atproto-did-peer": "file:../../atproto-did-peer",
1516 "favela-community": "file:../../favela-community",
1617 "protomux": "^3.11.0",
1718 "protomux-rpc": "^1.10.0",
pds/test/membrane-only.test.js +10 -3
……@@ -23,7 +23,7 @@ import { keyFromPrivate } from 'atproto-identity'
2323import { discoveryTopic } from 'atproto-identity/lib/discovery.js'
2424import { createPdsServer } from '../lib/server.js'
2525import { startControl } from '../lib/control.js'
26import { PeerRouter } from '../lib/peer-router.js'
26import { DidPeerRouter } from 'atproto-did-peer'
2727
2828process.env.PGH_SIDECAR_SOCK = join(tmpdir(), `no-sidecar-${process.pid}.sock`) // no registration
2929
……@@ -55,10 +55,17 @@ test('pure membrane (pds=null) fronts a peer, synthesizes describeServer/listRep
5555 })
5656 await peerSwarm.join(discoveryTopic(DID), { server: true, client: false }).flushed()
5757
58 // THE MEMBRANE: no Pds at all — just a PeerRouter fronting DID + the HTTP server with pds=null.
58 // THE MEMBRANE: no Pds at all — the shared DidPeerRouter fronting DID + the HTTP server with pds=null.
59 // Constructed EXACTLY as pds-serve.js does (owns-swarm + join + rpc) — verifies the prod repoint.
5960 const routerStore = openCorestore(mkdtempSync(join(tmpdir(), 'monly-router-')))
6061 const routerSwarm = new Hyperswarm({ bootstrap: testnet.bootstrap })
61 const router = new PeerRouter(routerSwarm, routerStore, { fronted: [DID], resolveVerifyKey: async () => keyFromPrivate(PRIV).publicKey })
62 const router = new DidPeerRouter(routerStore, {
63 swarm: routerSwarm,
64 join: (did) => { try { routerSwarm.join(discoveryTopic(did), { server: true, client: true }); routerSwarm.flush().catch(() => {}) } catch {} },
65 fronted: [DID],
66 resolveVerifyKey: async () => keyFromPrivate(PRIV).publicKey,
67 rpc: true
68 })
6269 const server = createPdsServer({ peers: router, serverDid: SERVER_DID, availableUserDomains: DOMAINS })
6370 await new Promise((r) => server.listen(0, '127.0.0.1', r))
6471 const base = `http://127.0.0.1:${server.address().port}`
pds/test/membrane.test.js +10 -3
……@@ -20,7 +20,7 @@ import { FirehoseSequencer } from 'atproto-store/lib/sequencer.js'
2020import { keyFromPrivate } from 'atproto-identity'
2121import { discoveryTopic } from 'atproto-identity/lib/discovery.js'
2222import { createPdsServer } from '../lib/server.js'
23import { PeerRouter } from '../lib/peer-router.js'
23import { DidPeerRouter } from 'atproto-did-peer'
2424
2525const DID = 'did:plc:membrane'
2626const HANDLE = 'membrane.7rnx.net'
……@@ -48,10 +48,17 @@ test('HTTP membrane routes a fronted DID to its peer (reads + createSession)', a
4848 })
4949 await peerSwarm.join(discoveryTopic(DID), { server: true, client: false }).flushed()
5050
51 // bridge: a keyless membrane — just a PeerRouter fronting DID + the HTTP membrane (no Pds)
51 // bridge: a keyless membrane — the shared DidPeerRouter fronting DID + the HTTP membrane (no Pds).
52 // Constructed EXACTLY as pds-serve.js does (owns-swarm + join + rpc), so this verifies the prod repoint.
5253 const routerStore = openCorestore(mkdtempSync(join(tmpdir(), 'mem-router-')))
5354 const routerSwarm = new Hyperswarm({ bootstrap: testnet.bootstrap })
54 const router = new PeerRouter(routerSwarm, routerStore, { fronted: [DID], resolveVerifyKey: async () => keyFromPrivate(PRIV).publicKey })
55 const router = new DidPeerRouter(routerStore, {
56 swarm: routerSwarm,
57 join: (did) => { try { routerSwarm.join(discoveryTopic(did), { server: true, client: true }); routerSwarm.flush().catch(() => {}) } catch {} },
58 fronted: [DID],
59 resolveVerifyKey: async () => keyFromPrivate(PRIV).publicKey,
60 rpc: true
61 })
5562 const server = createPdsServer({ peers: router, serverDid: 'did:web:pds.7rnx.net' })
5663 await new Promise((r) => server.listen(0, '127.0.0.1', r))
5764 const base = `http://127.0.0.1:${server.address().port}`