// lib/transport.js — the two communication planes (SPEC §2, §3). SCAFFOLD (P1).
//
// DURABLE : replicate the pool Autobase over each hyperswarm connection.
// HOT PATH : unordered datagrams (conn.trySend / 'message') for ephemeral
// task-available / claiming / result-ready signals. No HOL, no ack.
//
// HOT-PATH GATE: drop any connection whose remotePublicKey is not in member/*.
//
// ⚠️ OPEN (SPEC §10): verify hyperswarm `connection` forwards trySend()/'message'
// to secret-stream's unordered path un-wrapped. If not, drop to a dedicated
// secret-stream or the raw udx stream. Test before relying on it.
const { isMember } = require('./membership')
function startTransport (swarm, node, { gate = true } = {}) {
swarm.join(node.base.discoveryKey, { server: true, client: true })
node.peers = new Set()
swarm.on('connection', async (conn) => {
// 1) replicate the durable plane
node.store.replicate(conn)
// 2) hot-path membership gate
if (gate && !(await isMember(node.base, conn.remotePublicKey))) {
// conn.destroy(); return // enable once enrollment is the only join path
}
// 3) DATA PLANE: unordered datagrams (the latency win) — see OPEN note above
conn.on('message', (buf) => {
try { node.onDatagram && node.onDatagram(conn, JSON.parse(buf.toString())) } catch {}
})
node.peers.add(conn)
conn.on('close', () => node.peers.delete(conn))
})
}
// fire-and-forget datagram to all connected peers (the hot path)
function broadcast (node, dgram) {
const buf = Buffer.from(JSON.stringify(dgram))
for (const conn of node.peers || []) {
if (typeof conn.trySend === 'function') conn.trySend(buf)
}
}
module.exports = { startTransport, broadcast }