Backup Bundle

Writes one restorable backup: every included file encrypted under a bundle key, the vault keypair sealed under the operator's passphrase, and a manifest recording what the bundle holds and the digest of each entry.

The passphrase protects the vault key rather than each file, and the bundle key encrypts the files, so a restore derives from the passphrase once and the file count does not multiply the derivations.

The output directory has to be a path that does not exist yet. Writing over an existing one could mix entries from two backups and produce a manifest describing neither, so the call refuses instead of merging.

b.backupBundle.create(opts) #

stable0.1.96
{
  dataDir:          string,   // required; must exist
  outDir:           string,   // required; must not exist
  passphrase:       string,   // required; Buffer or string
  vaultKeyJson:     string,   // required; the in-memory vault keypair JSON
  files:            array,    // required; non-empty include entries
  metadata:         object,   // carried into the manifest
  sign:             boolean,  // false writes the manifest unsigned
  signOptional:     boolean,  // true continues when signing is unavailable
  progressCallback: object,   // function (event) per phase
}

Write a bundle and resolve with { manifest, manifestPath, outDir, bundleSize, fileCount, durationMs }.

dataDir has to exist and outDir has to not: an existing outDir raises backup-bundle/outdir-exists rather than being written into. passphrase seals the vault keypair supplied as vaultKeyJson, which is the in-memory keypair from b.vault.getKeysJson(). files lists what to include and must not be empty.

Each missing requirement has its own code, so a failed call says which one: backup-bundle/no-datadir, backup-bundle/no-outdir, backup-bundle/no-passphrase, backup-bundle/no-vault-key-json and backup-bundle/no-files.

An include entry is refused with backup-bundle/bad-include when it carries no relativePath, backup-bundle/bad-kind for a kind outside the set the manifest accepts, backup-bundle/missing-required when an entry marked required is not on disk, backup-bundle/not-a-file when its path is a directory, backup-bundle/empty when the include list resolves to nothing to write, and backup-bundle/short-read when a file returns fewer bytes than its size said, which would otherwise put a truncated entry in the bundle under a correct digest. A signing failure the signOptional escape does not cover raises backup-bundle/sign-failed.

The manifest is signed unless sign is false. It is a toggle rather than a key: the signature comes from the deployment's audit-signing key, so b.auditSign.init has to have run for a bundle to be signed. When it has not, the bundle is written unsigned and the progress callback reports a manifest-unsigned phase with audit-sign-not-initialized, so an operator can see that the bundle cannot later be proven to be theirs. Any other signing failure raises backup-bundle/sign-failed unless signOptional is true, which records the reason and keeps the backup.

sign and signOptional must be booleans, raising backup-bundle/bad-opt otherwise. A "false" for sign read as "not false" and signed anyway, while one for signOptional read as "not true" and refused the bundle, so a typo in either moved the outcome without saying so.

progressCallback receives a phase per step and a done event carrying the file count, bundle size and duration.

var b = require("@blamejs/core");
var res = await b.backupBundle.create({
  dataDir:      "./data",
  outDir:       "./backups/2026-10-06",
  passphrase:   process.env.BACKUP_PASSPHRASE,
  vaultKeyJson: b.vault.getKeysJson(),
  files:        [{ relativePath: "app.db" }],
});
res.fileCount;                 // → 1
res.manifestPath;              // → the manifest a restore reads first

Last updated 2026-10-12T14:21:56.879Z by seeder.