// Generic hpp post tool — post ONE app.bsky.feed.post to any hpp swarm-device by its control key.
// bare scripts/hpp-post.mjs <controlKeyHex> "your text" [writerSeed]
//
// Connects over Hyperswarm to the device's control key and submits an apply-write over
// hyper-proto-peer/device/v1. The device's lease-holder signs it into the DID's repo; the bridge
// fronts it to bsky. Posting is gated by the device's `writers` allowlist — the writerSeed's pubkey
// must be in it (default = the shared wj62/ashatron test writer). bsky limit: 300 graphemes.
//
// Generalizes wj62-post.mjs (which hardcodes wj62's two control keys) so any DID/device can be
// targeted without a bespoke script. Get a device's control key from its daemon boot log:
// pgh app log hyper-proto-peer | grep controlKey
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 text = globalThis.Bare.argv[3]
const writerSeed = globalThis.Bare.argv[4] || 'wj62-swarm-test-writer-2026-07-05'
if (!ck || !/^[0-9a-f]{64}$/i.test(ck) || !text) {
console.log('usage: bare scripts/hpp-post.mjs <controlKeyHex> "your text" [writerSeed]')
globalThis.Bare.exit(1)
}
const graphemes = [...text].length
if (graphemes > 300) { console.log('too long: ' + graphemes + ' graphemes (bsky limit 300)'); globalThis.Bare.exit(1) }
const swarm = new Hyperswarm({ keyPair: crypto.keyPair(crypto.hash(b4a.from(writerSeed))) })
// langs: without it bsky's custom-feed tuner (FeedTuner.preferredLangOnly) runs the `lande` detector on
// the text and drops anything it mis-reads as non-English — short/technical posts vanish from the feed on
// bsky.app (but not the author feed or getFeed XRPC). Declaring the language skips detection.
const record = { $type: 'app.bsky.feed.post', text, createdAt: new Date().toISOString(), langs: ['en'] }
const done = new Promise((res, rej) => {
const to = setTimeout(() => rej(new Error('timeout — is the daemon up + this control key current + writer allowlisted?')), 40000)
swarm.on('connection', async (conn) => {
if (b4a.toString(conn.remotePublicKey, 'hex') !== ck.toLowerCase()) { conn.destroy(); return }
const rpc = new ProtomuxRPC(conn, { protocol: 'hyper-proto-peer/device/v1', valueEncoding: c.json })
try { const rkey = tidNow(); const r = await rpc.request('apply-write', { action: 'create', collection: 'app.bsky.feed.post', rkey, record }); clearTimeout(to); res({ rkey, r }) } catch (e) { clearTimeout(to); rej(e) }
})
})
swarm.join(b4a.from(ck, 'hex'), { client: true, server: false })
await swarm.flush()
try { const o = await done; console.log('posted: rkey=' + o.rkey + ' (' + graphemes + ' graphemes) — will appear on bsky shortly') } catch (e) { console.log('FAILED: ' + e.message) }
await swarm.destroy()