// probe-local-db.js — open a keet-cli identity dir's local HyperDB (a
// RocksDB column family inside <identity>/0/db) and dump @local/identity,
// @local/rooms, @local/writers WITHOUT booting keet-core. This bypasses
// the onlineBoot deadlock so we can see what state the autocreate-then-
// crash actually left on disk.
//
// Usage:
// bare test/probe-local-db.js <identity-dir>
// e.g. bare test/probe-local-db.js ~/.config/keet-cli/identity-1
//
// SAFETY: opens read-only. Will refuse if the RocksDB LOCK file shows
// another process is currently using the dir.
import path from 'bare-path'
import fs from 'bare-fs'
import CorestoreStorage from 'hypercore-storage'
import HyperDB from 'hyperdb'
import spec from '../node_modules/@holepunchto/keet-core/schema/spec/index.js'
function truncBuf (v) {
if (v && typeof v === 'object' && v.type === 'Buffer' && Array.isArray(v.data)) {
const buf = Buffer.from(v.data)
return buf.toString('hex').slice(0, 64) + (buf.length > 32 ? '…(' + buf.length + 'b)' : '')
}
return v
}
function jsonify (obj) {
return JSON.parse(JSON.stringify(obj, (k, v) => {
if (Buffer.isBuffer(v)) return v.toString('hex').slice(0, 64) + (v.length > 32 ? '…(' + v.length + 'b)' : '')
if (v && v.type === 'Buffer' && Array.isArray(v.data)) {
const buf = Buffer.from(v.data)
return buf.toString('hex').slice(0, 64) + (buf.length > 32 ? '…(' + buf.length + 'b)' : '')
}
return v
}))
}
async function dumpCollection (db, name) {
console.log('\n--- ' + name + ' ---')
try {
const entries = await db.find(name).toArray()
console.log('count: ' + entries.length)
for (let i = 0; i < entries.length; i++) {
console.log('[' + i + ']', JSON.stringify(jsonify(entries[i]), null, 2))
}
} catch (err) {
console.log('ERROR reading ' + name + ': ' + err.message)
}
}
async function main () {
const dir = Bare.argv[2]
if (!dir) {
console.error('usage: bare test/probe-local-db.js <identity-dir>')
Bare.exit(1)
}
const profileDir = path.join(dir, '0')
if (!fs.existsSync(profileDir)) {
console.error('not found: ' + profileDir)
Bare.exit(1)
}
console.log('[probe] opening (readOnly):', profileDir)
const storage = new CorestoreStorage(profileDir, { readOnly: true })
// Register the column family BEFORE storage.ready() flushes the schema —
// rocksdb-native only auto-creates column families pre-flush.
const cf = storage.rocks.columnFamily('keet/local-database')
await storage.ready()
console.log('[probe] storage ready')
const db = HyperDB.rocks(cf, spec.local.hyperdb)
await db.ready()
console.log('[probe] hyperdb ready (version ' + (db.version || '?') + ')')
await dumpCollection(db, '@local/identity')
await dumpCollection(db, '@local/rooms')
await dumpCollection(db, '@local/writers')
await dumpCollection(db, '@local/devices')
await dumpCollection(db, '@local/migrations')
await db.close()
await storage.close()
console.log('\n[probe] done')
Bare.exit(0)
}
main().catch(err => {
console.error('[probe] uncaught:', err && err.message)
if (err && err.stack) console.error(err.stack)
Bare.exit(1)
})