// Step 1(c) — the EVENT-DRIVEN sign trigger. The daemon replaced its 2s poll with a single
// sb.watch(tick) that fires on every StateBase advance (a local write, a replicated #commit) AND on a
// signer-presence change. This proves the primary trigger: a write fires the watcher (so the signer
// materializes exactly when there's something to sign), and unwatch() cleanly stops it (close() path).
// (Presence-change → watch is proven by composition: SignerPresence.onChange fires on connect/disconnect
// [signer-presence unit] and StateBase wires it to _fireWatchers — the SAME fan-out a write uses here.)
import '../lib/bare-globals.js'
import test from 'brittle'
import crypto from 'hypercore-crypto'
import fs from 'bare-fs'
import { StateBaseV3 } from 'atproto-room/lib/state-base.js'
const tmp = () => { const d = '/tmp/hpp-ev-' + Math.floor(Math.random() * 1e9); fs.mkdirSync(d, { recursive: true }); return d }
test('sb.watch fires on a write (event-driven sign trigger) + unwatch stops it', async (t) => {
const sb = new StateBaseV3(tmp(), crypto.randomBytes(32), { roomSeed: crypto.randomBytes(32), network: false })
await sb.ready()
t.teardown(() => sb.close())
let fires = 0
const unwatch = sb.watch(() => { fires++ })
await sb.set('app.bsky.feed.post/1', { $type: 'app.bsky.feed.post', text: 'hi' })
t.ok(fires >= 1, 'a write fires the watcher → the signer would re-materialize event-driven (no timer)')
const before = fires
await sb.set('app.bsky.feed.post/2', { $type: 'app.bsky.feed.post', text: 'yo' })
t.ok(fires > before, 'a second write fires the watcher again')
unwatch()
const afterUnwatch = fires
await sb.set('app.bsky.feed.post/3', { $type: 'app.bsky.feed.post', text: 'no' })
t.is(fires, afterUnwatch, 'unwatch() stops the subscription — clean teardown (close() path)')
})