// Debt-2 proof: an org invite survives a daemon restart. The daemon persists
// the pairing descriptor (pending-pairings.json) and re-registers the blind-
// pairing member on boot (resumeRoomPairing), so an already-shared invite keeps
// working after the owner restarts.
import test from 'brittle'
import process from '#node:process'
import { mkdtempSync } from '#node:fs'
import { join } from '#node:path'
import { tmpdir } from '#node:os'
import b4a from 'b4a'
import createTestnet from '@hyperswarm/testnet'
import { startPearGit } from '../index.js'
let n = 0
const tmpStorage = () => mkdtempSync(join(tmpdir(), 'pgv3-pp-' + (n++) + '-'))
const tmpSock = () => join(mkdtempSync(join(tmpdir(), 'pgv3-pp-sock-' + (n++) + '-')), 'svc.sock')
async function waitFor (pred, ms = 30000) {
const t0 = Date.now()
while (Date.now() - t0 < ms) {
try { if (await pred()) return true } catch {}
await new Promise((r) => setTimeout(r, 100))
}
return false
}
test('org invite survives a daemon restart (persisted descriptor → resume on boot)', async (t) => {
process.env.PGV3_USE_RAW_IDENTITY = '1'
const testnet = await createTestnet(3, t.teardown)
const storage = tmpStorage()
const { Client } = await import('hyper-svc')
// A1: create an org + a contributor invite (persisted), capture it, then CLOSE.
const A1 = await startPearGit({
storage, uds: tmpSock(), http: { port: 0 },
swarm: { swarm: { bootstrap: testnet.bootstrap } }, deploy: false, sync: false
})
const topicHex = b4a.toString(A1.svc.swarm.topic, 'hex')
let invitation
{
const ca = await Client.connectUds(A1.svc.uds.path)
await ca.call('create-org', { name: 'palpha', type: 'group', displayName: 'PA' })
const r = await ca.call('create-org-invite', { name: 'palpha', role: 'contributor' })
invitation = r.invitation
await ca.close()
}
await A1.close()
t.ok(invitation && invitation.startsWith('roompair1:'), 'invite minted + daemon closed')
// A2: reopen the SAME storage → boot reads pending-pairings.json and
// resumeRoomPairing re-registers the member.
const A2 = await startPearGit({
storage, uds: tmpSock(), http: { port: 0 },
swarm: { swarm: { bootstrap: testnet.bootstrap } }, deploy: false, sync: false
})
t.teardown(async () => { try { await A2.close() } catch {} })
t.is(b4a.toString(A2.svc.swarm.topic, 'hex'), topicHex, 'A2 reopened the same identity (raw identity persisted)')
// B: join using the PRE-RESTART invite → still pairs + becomes a writer.
const B = await startPearGit({
storage: tmpStorage(), uds: tmpSock(), http: { port: 0 },
swarm: { swarm: { bootstrap: testnet.bootstrap } }, deploy: false, sync: false
})
t.teardown(async () => { try { await B.close() } catch {} })
const oj = await B.orgs.joinOrg(invitation, { swarm: B.svc.swarm.swarm })
t.is(oj.name, 'palpha', 'B joined via the pre-restart invite')
const writable = await waitFor(() => { const r = B.orgs.getOrgRoom('palpha'); return r && r.writable })
t.ok(writable, 'B became a writer via the RESUMED pairing — invite survived the restart')
})