// bench-e2e — profile a hosted DID: e2e post LATENCY to bsky + STORAGE state + head advance.
// bare scripts/bench-e2e.mjs <controlKeyHex> <did> [handle] [writerSeed]
//
// Posts one timestamped marker via the device's apply-write (control swarm), then polls the DID's PDS
// (com.atproto.repo.getRecord) until the record resolves — measuring the peer→bridge→relay→AppView
// latency. Reads get-state before/after for record count + head. Prints a JSON profile line.
import '../lib/bare-globals.js'
import Hyperswarm from 'hyperswarm'
import crypto from 'hypercore-crypto'
import b4a from 'b4a'
import c from 'compact-encoding'
import ProtomuxRPC from 'protomux-rpc'
import { tidNow } from 'atproto-store/lib/tid.js'
const ck = globalThis.Bare.argv[2]
const did = globalThis.Bare.argv[3]
const handle = globalThis.Bare.argv[4] || did
const writerSeed = globalThis.Bare.argv[5] || 'wj62-swarm-test-writer-2026-07-05'
if (!ck || !did) { console.log('usage: bare scripts/bench-e2e.mjs <controlKeyHex> <did> [handle] [writerSeed]'); globalThis.Bare.exit(1) }
const now = () => Date.now()
const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
async function pdsFor (did) {
try {
const doc = await (await fetch('https://plc.directory/' + did)).json()
const svc = (doc.service || []).find((s) => (s.id || '').endsWith('atproto_pds'))
return svc ? svc.serviceEndpoint : null
} catch { return null }
}
// Connect AS the authorized writer — apply-write is writer-gated on the connection's remotePublicKey,
// so the client swarm keypair MUST be the writer seed's keypair (get-state is public, works either way).
async function rpc (ck, method, params, keyPair) {
const swarm = new Hyperswarm({ keyPair })
const done = new Promise((res) => {
const to = setTimeout(() => res({ error: 'timeout' }), 30000)
swarm.on('connection', async (conn) => {
if (b4a.toString(conn.remotePublicKey, 'hex') !== ck.toLowerCase()) { conn.destroy(); return }
const r = new ProtomuxRPC(conn, { protocol: 'hyper-proto-peer/device/v1', valueEncoding: c.json })
try { const out = await r.request(method, params); clearTimeout(to); res({ out }) } catch (e) { clearTimeout(to); res({ error: e.message }) }
})
})
swarm.join(b4a.from(ck, 'hex'), { client: true, server: false })
await swarm.flush()
const r = await done
await swarm.destroy()
return r
}
async function main () {
const writerKp = crypto.keyPair(crypto.hash(b4a.from(writerSeed))) // the allowlisted writer identity
const pds = await pdsFor(did)
const before = (await rpc(ck, 'get-state', {}, writerKp)).out || {}
const rkey = tidNow()
const text = `bench ${new Date().toISOString()} — e2e latency probe`
const record = { $type: 'app.bsky.feed.post', text, createdAt: new Date().toISOString(), langs: ['en'] }
const t0 = now()
const posted = await rpc(ck, 'apply-write', { action: 'create', collection: 'app.bsky.feed.post', rkey, record }, writerKp)
const tPosted = now()
if (posted.error) { console.log(JSON.stringify({ did, error: 'apply-write: ' + posted.error })); globalThis.Bare.exit(1) }
// poll the PDS until the record resolves (peer→bridge→relay→AppView propagation)
let latencyMs = null
if (pds) {
const url = `${pds}/xrpc/com.atproto.repo.getRecord?repo=${did}&collection=app.bsky.feed.post&rkey=${rkey}`
for (let i = 0; i < 60; i++) { // up to ~90s
try { const r = await fetch(url); if (r.ok) { latencyMs = now() - t0; break } } catch {}
await sleep(1500)
}
}
const after = (await rpc(ck, 'get-state', {}, writerKp)).out || {}
console.log(JSON.stringify({
did, handle, rkey,
applyWriteMs: tPosted - t0,
bskyLatencyMs: latencyMs, // null = did not appear within ~90s
recordCountBefore: before.recordCount ?? null,
recordCountAfter: after.recordCount ?? null,
headBefore: before.head ? before.head.rev : null,
headAfter: after.head ? after.head.rev : null,
writable: after.writable ?? null,
indexers: after.indexers ?? null,
pds
}, null, 2))
globalThis.Bare.exit(0)
}
main()