import { existsSync } from 'node:fs'; import { join } from 'node:path'; import type { BackupEnv } from '@dorfteich/shared'; import { extractArchive } from './archive.js'; import { archiveFileName, dumpFileName } from './backup-set.js'; import { pgRestore } from './pg.js'; import type { RemoteLogger } from './remote.js'; /** * Restores one local set into the live database and data volumes: * `pg_restore --clean --if-exists` of the dump, then the volume archive * back over the uploads/plugins mounts. Shared by the operator CLI * (restore.js via restore.sh) and the in-app restore orchestrator (#103) — * one restore path, exercised by drills and the app alike. */ export async function performRestore( env: Pick, backupId: string, log: RemoteLogger, ): Promise { const dumpFile = join(env.BACKUPS_DIR, dumpFileName(backupId)); const archiveFile = join(env.BACKUPS_DIR, archiveFileName(backupId)); for (const file of [dumpFile, archiveFile]) { if (!existsSync(file)) { throw new Error(`restore set is incomplete — ${file} not found`); } } log.info({ backupId }, 'restoring database dump'); await pgRestore(env.DATABASE_URL, dumpFile); log.info({ backupId }, 'restoring uploads/plugins archive'); await extractArchive(archiveFile, [env.UPLOADS_DIR, env.PLUGINS_DIR]); }