feat(appdata): 增加归档导出校验脚本
This commit is contained in:
87
scripts/export-appdata-archive.mjs
Normal file
87
scripts/export-appdata-archive.mjs
Normal file
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env node
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { createRequire } from 'node:module';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { buildAppDataArchive } from './lib/appdata-archive.mjs';
|
||||
|
||||
const root = dirname(fileURLToPath(new URL('../package.json', import.meta.url)));
|
||||
const args = parseArgs(process.argv.slice(2));
|
||||
|
||||
if (args.help) {
|
||||
printHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const outPath = resolve(root, args.out ?? defaultArchiveName());
|
||||
const serverRequire = createRequire(resolve(root, 'apps/server/package.json'));
|
||||
const { PrismaClient } = serverRequire('@prisma/client');
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
try {
|
||||
const rows = await prisma.appData.findMany({
|
||||
orderBy: { key: 'asc' },
|
||||
select: { key: true, value: true, updatedAt: true },
|
||||
});
|
||||
const archive = buildAppDataArchive(rows, {
|
||||
appVersion: process.env.APP_VERSION || readPackageVersion(),
|
||||
appBuildTime: process.env.APP_BUILD_TIME || null,
|
||||
sourceCommit: process.env.GITHUB_SHA || readGitCommit(),
|
||||
});
|
||||
|
||||
mkdirSync(dirname(outPath), { recursive: true });
|
||||
writeFileSync(outPath, `${JSON.stringify(archive, null, 2)}\n`);
|
||||
console.log(`AppData archive exported: ${outPath}`);
|
||||
console.log(`Rows: ${archive.metadata.rowCount}; keys: ${archive.keys.join(', ') || '(none)'}`);
|
||||
console.log(`Payload checksum: ${archive.metadata.payloadChecksum}`);
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
const parsed = { help: false, out: 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 === '--out') parsed.out = argv[++index];
|
||||
else if (arg.startsWith('--out=')) parsed.out = arg.slice('--out='.length);
|
||||
else throw new Error(`Unknown argument: ${arg}`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function defaultArchiveName() {
|
||||
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||
return `appdata-archive-${stamp}.json`;
|
||||
}
|
||||
|
||||
function readPackageVersion() {
|
||||
try {
|
||||
const pkg = JSON.parse(readFileSync(resolve(root, 'apps/server/package.json'), 'utf8'));
|
||||
return pkg.version || 'unknown';
|
||||
} catch {
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
function readGitCommit() {
|
||||
try {
|
||||
return execFileSync('git', ['rev-parse', 'HEAD'], { cwd: root, encoding: 'utf8' }).trim();
|
||||
} catch {
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
function printHelp() {
|
||||
console.log(`Usage: pnpm appdata:archive:export -- --out backups/appdata-archive.json
|
||||
|
||||
Exports every row from app_data to a JSON archive with key list, app version metadata,
|
||||
per-row SHA-256 checksums, and a payload checksum.
|
||||
|
||||
Options:
|
||||
--out <path> Output archive path. Defaults to appdata-archive-<timestamp>.json.
|
||||
-h, --help Show this help.
|
||||
`);
|
||||
}
|
||||
Reference in New Issue
Block a user