#!/usr/bin/env node import { readFileSync } from 'node:fs'; import { resolve } from 'node:path'; import { verifyAppDataArchive } from './lib/appdata-archive.mjs'; const args = parseArgs(process.argv.slice(2)); if (args.help || !args.archive) { printHelp(); process.exit(args.help ? 0 : 1); } const archivePath = resolve(process.cwd(), args.archive); const archive = JSON.parse(readFileSync(archivePath, 'utf8')); const verification = verifyAppDataArchive(archive); if (args.json) { console.log(JSON.stringify(verification, null, 2)); } else if (verification.ok) { console.log(`AppData archive verified: ${archivePath}`); console.log(`Rows: ${verification.summary.rowCount}; keys: ${verification.summary.keys.join(', ') || '(none)'}`); console.log(`Payload checksum: ${verification.summary.payloadChecksum}`); } else { console.error(`AppData archive verification failed: ${archivePath}`); for (const error of verification.errors) { console.error(`- ${error}`); } } process.exit(verification.ok ? 0 : 1); function parseArgs(argv) { const parsed = { help: false, json: false, archive: null }; for (let index = 0; index < argv.length; index += 1) { const arg = argv[index]; if (arg === '--') continue; else if (arg === '--help' || arg === '-h') parsed.help = true; else if (arg === '--json') parsed.json = true; else if (arg === '--archive') parsed.archive = argv[++index]; else if (arg.startsWith('--archive=')) parsed.archive = arg.slice('--archive='.length); else if (!arg.startsWith('-') && !parsed.archive) parsed.archive = arg; else throw new Error(`Unknown argument: ${arg}`); } return parsed; } function printHelp() { console.log(`Usage: pnpm appdata:archive:verify -- --archive backups/appdata-archive.json Verifies key list, per-row SHA-256 checksums, and the archive payload checksum. Options: --archive Archive JSON path. A positional path is also accepted. --json Print machine-readable verification output. -h, --help Show this help. `); }