// Persistent Hyperswarm keypair for this bridge.
//
// ⛔ A BRIDGE ADDRESS IS ONLY MEANINGFUL IF IT IS STABLE. `new Hyperswarm()` mints a RANDOM keypair
// per boot, so the key this bridge tells peers to find it on changed on every restart. A peer that
// recorded it would silently stop being able to reach the bridge — and "the bridge did not answer"
// looks identical to "the bridge is down", which is the worst available failure mode.
//
// Measured, not assumed: booting with the swarm door wired printed a different `bridgeKey` each run.
//
// ⚠ A TRANSPORT identity, not account key material. It is a DHT/Noise identity that never signs a
// record, never touches a DID and grants nothing on its own; it only makes this bridge NAMEABLE so a
// peer can choose to ask it for something. Kept as a plain file beside the held-feed store so it
// survives a corestore reset.
//
// ⚠ This is the THIRD copy of this utility in the tree (hyper-proto-peer and atproto-bridge have the
// same one, and atproto-bridge's says so of hpp's). It stays local because there is no shared home
// for transport identity — favela-identity is about who someone IS, not how to reach them — and
// inventing one to hold thirty lines is a bigger change than the thing it would tidy.
import fs from 'bare-fs'
import { dirname } from 'bare-path'
import b4a from 'b4a'
import crypto from 'hypercore-crypto'
export function loadOrCreateSwarmKeyPair (file) {
try {
const seed = b4a.from(fs.readFileSync(file, 'utf8').trim(), 'hex')
if (seed.length === 32) return crypto.keyPair(seed)
} catch { /* first boot, or unreadable — mint below */ }
const seed = crypto.randomBytes(32)
fs.mkdirSync(dirname(file), { recursive: true })
// 0600: it is not account key material, but it is still this bridge's name and nobody else's.
fs.writeFileSync(file, b4a.toString(seed, 'hex') + '\n', { mode: 0o600 })
return crypto.keyPair(seed)
}
export default { loadOrCreateSwarmKeyPair }