This commit is contained in:
ZacharyZhang-NY committed 2026-04-04 12:03:50 -04:00
1 parent 66158e222e
commit 67c757f481
314 files changed
+37945 -22962

No files matched your search

+121
View File
@@ -0,0 +1,121 @@
import { chmodSync, existsSync, mkdirSync } from "node:fs";
import { copyFile, cp, rm } from "node:fs/promises";
import { join } from "node:path";
import { DatabaseSync, backup as backupDatabase } from "node:sqlite";
async function copyIfExists(source: string, destination: string) {
if (!existsSync(source)) {
return;
}
await copyFile(source, destination);
}
export function buildBackupMethods(
deps: {
getDb: () => DatabaseSync;
setDb: (db: DatabaseSync) => void;
openConnection: () => DatabaseSync;
init: () => void;
close: () => void;
profileDir: string;
dbPath: string;
logsDir: string;
artifactsDir: string;
backupsDir: string;
},
) {
return {
exportBackup(targetDir: string) {
mkdirSync(targetDir, { recursive: true });
deps.getDb().exec("PRAGMA wal_checkpoint(TRUNCATE);");
const copyJobs = [
backupDatabase(deps.getDb(), join(targetDir, "profile.sqlite")),
cp(deps.logsDir, join(targetDir, "logs"), { recursive: true, force: true }),
cp(deps.artifactsDir, join(targetDir, "artifacts"), { recursive: true, force: true }),
copyIfExists(join(deps.profileDir, "vault.key"), join(targetDir, "vault.key")),
copyIfExists(join(deps.profileDir, "agent-api-signing.key"), join(targetDir, "agent-api-signing.key")),
copyIfExists(`${deps.dbPath}-wal`, join(targetDir, "profile.sqlite-wal")),
copyIfExists(`${deps.dbPath}-shm`, join(targetDir, "profile.sqlite-shm")),
];
return Promise.all(copyJobs);
},
async restoreFromBackup(sourceDir: string) {
const sourceDbPath = join(sourceDir, "profile.sqlite");
if (!existsSync(sourceDbPath)) {
throw new Error("Backup directory is missing profile.sqlite.");
}
// Validate
const validationDb = new DatabaseSync(sourceDbPath);
try {
const requiredTables = ["settings", "companies", "connectors"] as const;
for (const table of requiredTables) {
const row = validationDb
.prepare("select name from sqlite_master where type = 'table' and name = ?")
.get(table) as { name: string } | undefined;
if (!row) {
throw new Error(`Backup is missing the required table "${table}".`);
}
}
} finally {
validationDb.close();
}
const recoveryDir = join(deps.backupsDir, `pre-restore-${Date.now()}`);
mkdirSync(recoveryDir, { recursive: true });
deps.getDb().exec("PRAGMA wal_checkpoint(TRUNCATE);");
await Promise.all([
backupDatabase(deps.getDb(), join(recoveryDir, "profile.sqlite")),
cp(deps.logsDir, join(recoveryDir, "logs"), { recursive: true, force: true }),
cp(deps.artifactsDir, join(recoveryDir, "artifacts"), { recursive: true, force: true }),
copyIfExists(join(deps.profileDir, "vault.key"), join(recoveryDir, "vault.key")),
copyIfExists(join(deps.profileDir, "agent-api-signing.key"), join(recoveryDir, "agent-api-signing.key")),
copyIfExists(`${deps.dbPath}-wal`, join(recoveryDir, "profile.sqlite-wal")),
copyIfExists(`${deps.dbPath}-shm`, join(recoveryDir, "profile.sqlite-shm")),
]);
deps.close();
try {
await applyBackup(sourceDir);
} catch (error) {
await applyBackup(recoveryDir);
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Restore failed. Previous profile was recovered from ${recoveryDir}. ${message}`);
}
},
};
async function applyBackup(sourceDir: string) {
await rm(deps.dbPath, { force: true });
await rm(`${deps.dbPath}-wal`, { force: true });
await rm(`${deps.dbPath}-shm`, { force: true });
await copyFile(join(sourceDir, "profile.sqlite"), deps.dbPath);
await copyIfExists(join(sourceDir, "profile.sqlite-wal"), `${deps.dbPath}-wal`);
await copyIfExists(join(sourceDir, "profile.sqlite-shm"), `${deps.dbPath}-shm`);
await rm(deps.logsDir, { recursive: true, force: true });
await rm(deps.artifactsDir, { recursive: true, force: true });
mkdirSync(deps.logsDir, { recursive: true });
mkdirSync(deps.artifactsDir, { recursive: true });
if (existsSync(join(sourceDir, "logs"))) {
await cp(join(sourceDir, "logs"), deps.logsDir, { recursive: true, force: true });
}
if (existsSync(join(sourceDir, "artifacts"))) {
await cp(join(sourceDir, "artifacts"), deps.artifactsDir, { recursive: true, force: true });
}
await copyIfExists(join(sourceDir, "vault.key"), join(deps.profileDir, "vault.key"));
await copyIfExists(join(sourceDir, "agent-api-signing.key"), join(deps.profileDir, "agent-api-signing.key"));
if (existsSync(join(deps.profileDir, "vault.key"))) {
chmodSync(join(deps.profileDir, "vault.key"), 0o600);
}
if (existsSync(join(deps.profileDir, "agent-api-signing.key"))) {
chmodSync(join(deps.profileDir, "agent-api-signing.key"), 0o600);
}
deps.setDb(deps.openConnection());
deps.init();
}
}