import { Database } from "bun:sqlite"; import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, } from "node:fs"; import { join, relative } from "node:path"; import { buildTarball } from "../tarball/tar.ts"; import type { BackupBucket, Config } from "./config.ts"; import { notify, setting } from "./db.ts"; const KEEP = 14; const DAY_MS = 24 * 3600 * 1000; const CHECK_MS = 3600 * 1000; const NAME = /^\d{8}T\d{6}Z$/; /** A backup's name: its UTC time, `20260926T031500Z`, so names sort in time order. */ function stamp(ms: number): string { return new Date(ms).toISOString().replace(/[-:]|\.\d{3}/g, ""); } /** The backups in `data/backups/`, oldest first. */ export function backups(dataDir: string): string[] { const root = join(dataDir, "backups"); // Not a folder is no backups, so the console still shows why the next one fails. return existsSync(root) && statSync(root).isDirectory() ? readdirSync(root) .filter((name) => NAME.test(name)) .sort() : []; } /** * §19's backup: `VACUUM INTO` of kepr.db and a copy of `assets/`, built in a hidden folder and * renamed into `data/backups/