// Runnable hyper-proto-peer daemon — a self-custody atproto peer that serves its repo + signed
// firehose over Hyperswarm and is discoverable by DID (Option 2). First run onboards
// (Peer.init needs PEER_ROOT_MNEMONIC); later runs reload the vault (Peer.load).
//
// PEER_STORAGE=<dir> PEER_ROOT_MNEMONIC="..." PEER_HANDLE=alice.7rnx.net \
// PEER_PDS_URL=https://pds.7rnx.net [PEER_APP_PASSWORD=...] node bin/peer-serve.js
//
// Prints one JSON line with { did, didKey, serverKey, discoveryTopic, repoKey, firehoseKey }
// then stays up. A bridge fronts it with PeerFront.discover(swarm, store, did, {verifyKey}).
import Hyperswarm from 'hyperswarm'
import { existsSync } from 'node:fs'
import { join } from 'node:path'
import { Peer } from '../lib/peer.js'
import { loadOrCreateSwarmKeyPair } from '../lib/swarm-keypair.js'
const storage = process.env.PEER_STORAGE || './peer-data'
const handle = process.env.PEER_HANDLE || 'peer.local'
const pdsUrl = process.env.PEER_PDS_URL || 'https://pds.local'
const appPassword = process.env.PEER_APP_PASSWORD || null
let peer
if (existsSync(join(storage, 'peer-identity.json'))) {
peer = await Peer.load({ storage })
} else {
const rootMnemonic = process.env.PEER_ROOT_MNEMONIC
if (!rootMnemonic) { console.error('first run needs PEER_ROOT_MNEMONIC'); process.exit(1) }
peer = await Peer.init({ storage, rootMnemonic, handle, pdsUrl, appPassword })
}
// ensure at least one signed commit so the peer is frontable + verifiable on connect
if (peer.seq.length === 0) {
await peer.write({
collection: 'app.bsky.feed.post',
rkey: 'hello',
record: { $type: 'app.bsky.feed.post', text: `hello from ${peer.handle}`, createdAt: new Date().toISOString() }
})
}
const swarm = new Hyperswarm({ keyPair: loadOrCreateSwarmKeyPair(storage) })
const serving = peer.serve(swarm, appPassword ? {} : {})
await serving.ready()
console.log(JSON.stringify({
msg: 'peer serving',
did: peer.did,
handle: peer.handle,
didKey: peer.didKey,
serverKey: serving.serverKey,
discoveryTopic: serving.discoveryTopic,
repoKey: peer.repoKeyHex,
firehoseKey: peer.firehoseKeyHex,
firehoseLen: peer.seq.length
}))
const shutdown = async () => {
try { serving.close(); await swarm.destroy(); await peer.close() } catch {}
process.exit(0)
}
process.on('SIGINT', shutdown)
process.on('SIGTERM', shutdown)