Restore
Restore a backup bundle from storage into a live data directory. b.restore.create binds a storage backend, the backup passphrase and the data directory; the engine it returns lists and inspects bundles, restores one, and reverses a restore through b.restoreRollback.
A restore runs in four steps. The engine pulls the bundle out of storage, decrypts it with b.restoreBundle.extract (checking each file's size and SHA3-512 checksum and the manifest signature), renames the live data directory into the rollback root, and renames the decrypted directory onto the data directory. Both renames stay on one filesystem: the pulled and decrypted copies are written under stagingRoot, which defaults to the parent directory of the rollback root, and run() refuses a layout the renames cannot complete before it decrypts anything.
The framework keeps its files open, so a restore runs as stop framework -> run() -> start framework, the same shape as a database restore. Every outcome lands on b.audit as restore.success or restore.failure unless audit: false.
b.restore.create(opts) #
{
dataDir: string, // required; the live data directory
storage: StorageBackend, // required; b.backup.diskStorage() or custom
passphrase: Buffer | string, // required; the backup passphrase
rollbackRoot: string, // default: .rollbacks
stagingRoot: string, // default: the parent directory of rollbackRoot
audit: boolean, // default true
maxPulledBytes: number, // default 4 GiB
maxPulledFiles: number, // default 100000
requireSignature: boolean, // refuse a bundle whose manifest is unsigned
expectedFingerprint: string, // trust only the key with this fingerprint
verifySignature: boolean, // default true
mountInfoPath: string, // default null — read mount points from this file instead of
// the platform's own, for the cross-device and
// mount-point checks above
}
Build a restore engine bound to a data directory, a storage backend and the backup passphrase. The returned object carries list, inspect, run, rollback, listRollbacks, purgeRollbacks, the wired storage and the resolved rollbackRoot. Building it throws restore/no-datadir when dataDir is absent or empty, and restore/no-passphrase when passphrase is neither a Buffer nor a string.
run({ bundleId }) pulls that bundle, decrypts it, renames the live data directory into the rollback root and renames the decrypted copy onto the data directory. It resolves with { bundleId, fileCount, totalBytes, rollbackPath, vaultKeyJson, durationMs }. A signed manifest is trusted only under expectedFingerprint or an active or rotated b.auditSign key, so a process that does not hold the signing key passes expectedFingerprint. requireSignature: true refuses a bundle with no signature, and combining it with verifySignature: false throws restore/bad-opts.
Both renames must stay on one filesystem. Before pulling anything, run() throws restore/datadir-is-mount-point for a data directory that is a mount point, restore/cross-device for a stagingRoot or rollbackRoot on another filesystem, restore/bad-staging-root or restore/bad-rollback-root for one inside the data directory by either its written path or its canonical one, and restore/datadir-is-symlink for a data directory that is a symbolic link. A failure after decryption removes the decrypted staging directory and rejects with restore/swap-failed; the bundle in storage can be restored again. Every restore-bundle/ failure is reported as restore/.
A storage missing any of readBundle, listBundles and hasBundle throws restore/bad-storage.
var fs = require("node:fs");
var path = require("node:path");
var os = require("node:os");
var root = fs.mkdtempSync(path.join(os.tmpdir(), "restore-store-"));
var engine = b.restore.create({
dataDir: path.join(root, "data"),
storage: b.backup.diskStorage({ root: root }),
passphrase: Buffer.from("operator backup passphrase"),
});
typeof engine.run; // → "function"
typeof engine.rollback; // → "function"