OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-proto-peer / bin / peer-serve.js

62 lines · javascript ref:
// 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)