import { createShade } from '@shade/sdk'; import { readFileSync, writeFileSync } from 'fs'; import { loadConfig } from '../config.js'; /** * Export the current Shade state to a file. * * Usage: shade backup export [--addresses bob,charlie] */ export async function backupExportCommand( file: string, options: { addresses?: string[] } = {}, ): Promise { const config = loadConfig(); const shade = await createShade({ prekeyServer: config.prekeyServer, storage: config.storage, address: config.address, autoReplenish: false, }); try { // Prompt for passphrase via stdin (simple prompt, no hiding) process.stdout.write('Backup passphrase (min 12 chars): '); const passphrase = await readLine(); const backupString = await shade.exportBackup(passphrase, options.addresses ?? []); writeFileSync(file, backupString); console.log(`\n\x1b[32m✓\x1b[0m Backup written to ${file}`); console.log(` Size: ${backupString.length} bytes`); console.log(` Keep this passphrase safe — it's the only way to restore.`); } finally { await shade.shutdown(); } } /** * Restore a backup file into the current Shade storage. * * Usage: shade backup restore */ export async function backupRestoreCommand(file: string): Promise { const config = loadConfig(); const backupString = readFileSync(file, 'utf-8').trim(); const shade = await createShade({ prekeyServer: config.prekeyServer, storage: config.storage, address: config.address, autoReplenish: false, }); try { process.stdout.write('Passphrase: '); const passphrase = await readLine(); await shade.importBackup(backupString, passphrase); console.log(`\n\x1b[32m✓\x1b[0m Backup restored`); console.log(` Fingerprint: ${await shade.fingerprint}`); } finally { await shade.shutdown(); } } async function readLine(): Promise { const decoder = new TextDecoder(); const buffer: string[] = []; for await (const chunk of Bun.stdin.stream()) { const text = decoder.decode(chunk as Uint8Array); const newlineIdx = text.indexOf('\n'); if (newlineIdx >= 0) { buffer.push(text.slice(0, newlineIdx)); break; } buffer.push(text); } return buffer.join('').trim(); }