@camstack/system 1.2.423 → 1.2.425

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  2. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  3. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/alerts/alerts.addon.js +1 -1
  6. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  7. package/dist/builtins/autotrack/index.js +1 -1
  8. package/dist/builtins/autotrack/index.mjs +1 -1
  9. package/dist/builtins/backup-orchestrator/backup-databases.d.ts +51 -0
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +13 -0
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +248 -17
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +248 -17
  13. package/dist/builtins/backup-orchestrator/manifest-store.d.ts +23 -3
  14. package/dist/builtins/backup-orchestrator/run-queue.d.ts +3 -0
  15. package/dist/builtins/backup-orchestrator/schedule-store.d.ts +7 -1
  16. package/dist/builtins/backup-orchestrator/seed-marker-store.d.ts +34 -0
  17. package/dist/builtins/calendars/calendars.addon.js +1 -1
  18. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  19. package/dist/builtins/camera-grid/index.js +1 -1
  20. package/dist/builtins/camera-grid/index.mjs +1 -1
  21. package/dist/builtins/composer/composer.addon.js +2 -2
  22. package/dist/builtins/composer/composer.addon.mjs +2 -2
  23. package/dist/builtins/console-logging/index.js +1 -1
  24. package/dist/builtins/console-logging/index.mjs +1 -1
  25. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  26. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  27. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  28. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  29. package/dist/builtins/hub-forwarder/index.js +1 -1
  30. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  31. package/dist/builtins/keychain/index.js +3 -3
  32. package/dist/builtins/keychain/index.mjs +3 -3
  33. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  34. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  35. package/dist/builtins/local-auth/local-auth.addon.js +2 -2
  36. package/dist/builtins/local-auth/local-auth.addon.mjs +2 -2
  37. package/dist/builtins/local-network/local-network.addon.js +1 -1
  38. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  39. package/dist/builtins/loki-logging/index.js +1 -1
  40. package/dist/builtins/loki-logging/index.mjs +1 -1
  41. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  42. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  43. package/dist/builtins/platform-probe/index.js +1 -1
  44. package/dist/builtins/platform-probe/index.mjs +1 -1
  45. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  46. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  47. package/dist/builtins/snapshot/index.js +1 -1
  48. package/dist/builtins/snapshot/index.mjs +1 -1
  49. package/dist/builtins/sqlite-storage/database-snapshot-provider.d.ts +18 -0
  50. package/dist/builtins/sqlite-storage/file-host-client.d.ts +59 -0
  51. package/dist/builtins/sqlite-storage/file-host-handlers.d.ts +23 -0
  52. package/dist/builtins/sqlite-storage/file-host-protocol.d.ts +151 -0
  53. package/dist/builtins/sqlite-storage/file-host-worker.d.ts +1 -0
  54. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  55. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  56. package/dist/builtins/sqlite-storage/index.js +21 -20
  57. package/dist/builtins/sqlite-storage/index.mjs +2 -1
  58. package/dist/builtins/sqlite-storage/owned-sqlite-file.d.ts +136 -0
  59. package/dist/builtins/sqlite-storage/placement-errors.d.ts +60 -0
  60. package/dist/builtins/sqlite-storage/placement-router.d.ts +80 -0
  61. package/dist/builtins/sqlite-storage/retired-collections.d.ts +7 -0
  62. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +68 -8
  63. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +23 -26
  64. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  65. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  66. package/dist/builtins/sqlite-storage/vector-provider.d.ts +24 -0
  67. package/dist/builtins/sqlite-storage/wal-maintenance.d.ts +17 -0
  68. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +3 -1
  69. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +3 -1
  70. package/dist/builtins/system-backup/system-backup.service.d.ts +48 -15
  71. package/dist/builtins/system-config/system-config.addon.js +2 -2
  72. package/dist/builtins/system-config/system-config.addon.mjs +2 -2
  73. package/dist/builtins/winston-logging/index.js +1 -1
  74. package/dist/builtins/winston-logging/index.mjs +1 -1
  75. package/dist/{composition-sources-CgiAeG-2.js → composition-sources-197keifF.js} +1 -1
  76. package/dist/{composition-sources-BXDchWFn.mjs → composition-sources-DmzTSy26.mjs} +1 -1
  77. package/dist/{constants-1_7QtPNo.js → constants-B5Jd8Zch.js} +1 -1
  78. package/dist/{constants-C2dhkIuF.mjs → constants-CkNLi-XW.mjs} +1 -1
  79. package/dist/{dist-DimotS8e.mjs → dist-DMWeqeTF.mjs} +863 -750
  80. package/dist/{dist-VIIxVsBW.js → dist-DnALrQF-.js} +866 -747
  81. package/dist/file-host-worker.js +144 -0
  82. package/dist/file-host-worker.mjs +144 -0
  83. package/dist/index.js +9 -8
  84. package/dist/index.mjs +6 -5
  85. package/dist/{jwt-signing-key-C8nMdNYW.mjs → jwt-signing-key-CCHXAtrs.mjs} +1 -1
  86. package/dist/{jwt-signing-key-C8s9syVg.js → jwt-signing-key-DeqG7LD9.js} +1 -1
  87. package/dist/{restore-archive-DjppfrIB.js → restore-archive-C4UhQOsg.js} +156 -65
  88. package/dist/{restore-archive-bOMZwY0D.mjs → restore-archive-GevpOHw8.mjs} +151 -66
  89. package/dist/{retired-settings-keys-_muTvNyh.js → retired-settings-keys-0FOsnzIE.js} +1 -1
  90. package/dist/{retired-settings-keys-BYnjMBE-.mjs → retired-settings-keys-CdVFl7m2.mjs} +1 -1
  91. package/dist/sqlite-snapshot-worker.js +1 -1
  92. package/dist/sqlite-snapshot-worker.mjs +1 -1
  93. package/dist/wal-checkpoint-worker.js +1 -1
  94. package/dist/wal-checkpoint-worker.mjs +1 -1
  95. package/dist/wal-maintenance-BtfyfuT5.mjs +0 -0
  96. package/dist/wal-maintenance-DJV1rde2.js +0 -0
  97. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_dist = require("./dist-VIIxVsBW.js");
2
+ const require_dist = require("./dist-DnALrQF-.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  let buffer = require("buffer");
5
5
  let node_fs_promises = require("node:fs/promises");
@@ -3508,6 +3508,11 @@ function isSqlitePath(relPath) {
3508
3508
  const db = databaseOfSidecar(relPath) ?? relPath;
3509
3509
  return SQLITE_DATABASE_SUFFIXES.some((suffix) => db.endsWith(suffix));
3510
3510
  }
3511
+ /**
3512
+ * The databases a run carries when it states none: the minimum (D382). A
3513
+ * schedule, a manual run and `createArchive` all fall back to this one value.
3514
+ */
3515
+ var DEFAULT_BACKUP_DATABASES = ["settings"];
3511
3516
  /** Path of the manifest file embedded inside every archive. */
3512
3517
  var ARCHIVE_MANIFEST_NAME = ".camstack-backup-manifest.json";
3513
3518
  var DEFAULT_STAT_CACHE_TTL_MS = 6e4;
@@ -3596,6 +3601,8 @@ var SystemBackupService = class {
3596
3601
  throwIfCancelled(opts.signal);
3597
3602
  const recipient = opts.encryptTo !== void 0 ? parseBackupPublicKey(opts.encryptTo) : null;
3598
3603
  const requested = opts.locations ?? DEFAULT_BACKUP_LOCATIONS;
3604
+ const selection = new Set(opts.databases ?? DEFAULT_BACKUP_DATABASES);
3605
+ if (!selection.has("settings")) return this.createSnapshotsOnlyArchive(opts, selection, recipient);
3599
3606
  const present = [];
3600
3607
  for (const loc of requested) {
3601
3608
  const abs = node_path.isAbsolute(loc) ? loc : node_path.join(this.dataDir, loc);
@@ -3613,7 +3620,12 @@ var SystemBackupService = class {
3613
3620
  else if (!isExcludedFromBackup(node_path.relative(this.dataDir, abs))) walked.push(toArchiveEntry(abs, this.dataDir, stat));
3614
3621
  }
3615
3622
  const walkedPaths = new Set(walked.map((e) => e.path));
3616
- const owned = walked.some((e) => isSqlitePath(e.path)) ? await this.ownedDatabasesInScope(opts.owner, walkedPaths) : /* @__PURE__ */ new Set();
3623
+ const ownedById = walked.some((e) => isSqlitePath(e.path)) ? await this.ownedDatabasesInScope(opts.owner, walkedPaths) : /* @__PURE__ */ new Map();
3624
+ const owned = new Set(ownedById.keys());
3625
+ const selected = /* @__PURE__ */ new Map();
3626
+ const omitted = /* @__PURE__ */ new Set();
3627
+ for (const [rel, databaseId] of ownedById) if (selection.has(databaseId)) selected.set(rel, databaseId);
3628
+ else omitted.add(databaseId);
3617
3629
  const unowned = /* @__PURE__ */ new Set();
3618
3630
  for (const e of walked) {
3619
3631
  const db = databaseOfSidecar(e.path);
@@ -3627,7 +3639,7 @@ var SystemBackupService = class {
3627
3639
  } });
3628
3640
  throw new BackupSnapshotRefusedError(`live SQLite database ${databases.join(", ")} has no owner that can snapshot it — a copy of its files would be torn; remove its stale -wal/-shm/-journal if nothing has it open, or leave its location out of the backup`);
3629
3641
  }
3630
- const snapshot = owned.size > 0 && opts.owner ? await this.takeOwnerSnapshot(opts.owner, owned, opts.signal) : null;
3642
+ const snapshots = selected.size > 0 && opts.owner ? await this.takeOwnerSnapshots(opts.owner, selected, opts.signal) : [];
3631
3643
  try {
3632
3644
  const liveFiles = /* @__PURE__ */ new Set();
3633
3645
  for (const db of owned) {
@@ -3635,7 +3647,7 @@ var SystemBackupService = class {
3635
3647
  for (const suffix of SQLITE_SIDECAR_SUFFIXES) liveFiles.add(db + suffix);
3636
3648
  }
3637
3649
  const entries = walked.filter((e) => !liveFiles.has(e.path));
3638
- if (snapshot !== null) entries.push(snapshot.entry);
3650
+ for (const snapshot of snapshots) entries.push(snapshot.entry);
3639
3651
  const manifest = {
3640
3652
  archiveVersion: 1,
3641
3653
  createdAt: Date.now(),
@@ -3644,15 +3656,20 @@ var SystemBackupService = class {
3644
3656
  entries,
3645
3657
  totalBytes: entries.reduce((acc, e) => acc + e.sizeBytes, 0),
3646
3658
  totalFiles: entries.filter((e) => e.kind === "file").length,
3647
- ...snapshot !== null ? { sqliteSnapshots: [snapshot.archived] } : {}
3659
+ ...snapshots.length > 0 ? { sqliteSnapshots: snapshots.map((snapshot) => snapshot.archived) } : {},
3660
+ ...omitted.size > 0 ? { omittedDatabases: [...omitted].toSorted() } : {}
3648
3661
  };
3649
- const carriedSnapshot = snapshot?.archived.snapshotPath ?? null;
3662
+ if (omitted.size > 0) this.logger.info("createArchive: owned databases left out of this run", { meta: {
3663
+ omitted: [...omitted].toSorted(),
3664
+ carried: [...selected.values()]
3665
+ } });
3666
+ const carriedSnapshots = new Set(snapshots.map((snapshot) => snapshot.archived.snapshotPath));
3650
3667
  return await this.writeArchive({
3651
3668
  archivePath: opts.archivePath,
3652
3669
  present,
3653
3670
  manifest,
3654
3671
  excluded: (rel) => {
3655
- if (rel === carriedSnapshot) return false;
3672
+ if (carriedSnapshots.has(rel)) return false;
3656
3673
  return liveFiles.has(rel) || isExcludedFromBackup(rel);
3657
3674
  },
3658
3675
  ...opts.signal ? { signal: opts.signal } : {},
@@ -3666,7 +3683,62 @@ var SystemBackupService = class {
3666
3683
  }
3667
3684
  });
3668
3685
  } finally {
3669
- if (snapshot !== null) await this.removeSnapshot(snapshot.absPath);
3686
+ for (const snapshot of snapshots) await this.removeSnapshot(snapshot.absPath);
3687
+ }
3688
+ }
3689
+ /**
3690
+ * An archive of the selected databases' owner snapshots and the manifest —
3691
+ * no data-root walk, no location, no settings (D852). Refused when the owner
3692
+ * has none of the selected files: an archive of nothing must reach no
3693
+ * destination, because its upload prunes an older archive that has them.
3694
+ */
3695
+ async createSnapshotsOnlyArchive(opts, selection, recipient) {
3696
+ if (opts.owner === void 0) throw new BackupSnapshotRefusedError("a snapshots-only archive needs the database owner, and none was given");
3697
+ node_fs.mkdirSync(node_path.dirname(opts.archivePath), { recursive: true });
3698
+ const ownedById = await this.ownedDatabasesInScope(opts.owner, null);
3699
+ const selected = /* @__PURE__ */ new Map();
3700
+ for (const [rel, databaseId] of ownedById) if (selection.has(databaseId)) selected.set(rel, databaseId);
3701
+ if (selected.size === 0) {
3702
+ this.logger.warn("createArchive: the owner has none of the selected databases — no archive built", { meta: {
3703
+ requested: [...selection].toSorted(),
3704
+ archivePath: opts.archivePath
3705
+ } });
3706
+ throw new BackupSnapshotRefusedError(`the owner has none of the selected databases (${[...selection].toSorted().join(", ")})`);
3707
+ }
3708
+ const snapshots = await this.takeOwnerSnapshots(opts.owner, selected, opts.signal);
3709
+ try {
3710
+ const entries = snapshots.map((snapshot) => snapshot.entry);
3711
+ const manifest = {
3712
+ archiveVersion: 1,
3713
+ createdAt: Date.now(),
3714
+ dataDir: this.dataDir,
3715
+ locations: [],
3716
+ entries,
3717
+ totalBytes: entries.reduce((acc, e) => acc + e.sizeBytes, 0),
3718
+ totalFiles: entries.length,
3719
+ sqliteSnapshots: snapshots.map((snapshot) => snapshot.archived)
3720
+ };
3721
+ const carried = snapshots.map((snapshot) => snapshot.archived.snapshotPath);
3722
+ const carriedSet = new Set(carried);
3723
+ const result = await this.writeArchive({
3724
+ archivePath: opts.archivePath,
3725
+ present: [],
3726
+ tarRoots: carried,
3727
+ manifest,
3728
+ excluded: (rel) => rel !== ".camstack-backup-manifest.json" && !carriedSet.has(rel),
3729
+ ...opts.signal ? { signal: opts.signal } : {},
3730
+ ...opts.onArchiveBytes ? { onArchiveBytes: opts.onArchiveBytes } : {},
3731
+ ...opts.encryptTo !== void 0 ? { encryptTo: opts.encryptTo } : {}
3732
+ });
3733
+ return recipient === null ? result : {
3734
+ ...result,
3735
+ encryption: {
3736
+ scheme: BACKUP_ENCRYPTION_SCHEME,
3737
+ keyId: recipient.keyId
3738
+ }
3739
+ };
3740
+ } finally {
3741
+ for (const snapshot of snapshots) await this.removeSnapshot(snapshot.absPath);
3670
3742
  }
3671
3743
  }
3672
3744
  /**
@@ -3700,7 +3772,7 @@ var SystemBackupService = class {
3700
3772
  if (!excludePrefix) return true;
3701
3773
  return norm !== excludePrefix && !norm.startsWith(`${excludePrefix}/`);
3702
3774
  }
3703
- }, [ARCHIVE_MANIFEST_NAME, ...present]);
3775
+ }, [ARCHIVE_MANIFEST_NAME, ...opts.tarRoots ?? present]);
3704
3776
  const sink = node_fs.createWriteStream(opts.archivePath, { mode: 384 });
3705
3777
  try {
3706
3778
  const streamOpts = opts.signal ? { signal: opts.signal } : {};
@@ -3817,12 +3889,13 @@ var SystemBackupService = class {
3817
3889
  if (node_fs.existsSync(markerPath)) node_fs.rmSync(markerPath, { force: true });
3818
3890
  }
3819
3891
  /**
3820
- * The databases the owner declares, archive-relative, that this walk found.
3821
- * One outside this data root is not in scope. An owner that cannot answer
3822
- * stops the archive: without the answer, nothing says which file is live.
3892
+ * The databases the owner declares, archive-relative, that this walk found,
3893
+ * with the id of each. One outside this data root is not in scope. An owner
3894
+ * that cannot answer stops the archive: without the answer, nothing says
3895
+ * which file is live.
3823
3896
  */
3824
3897
  async ownedDatabasesInScope(owner, walked) {
3825
- if (owner === void 0) return /* @__PURE__ */ new Set();
3898
+ if (owner === void 0) return /* @__PURE__ */ new Map();
3826
3899
  let declared;
3827
3900
  try {
3828
3901
  declared = await owner.listDatabases();
@@ -3831,22 +3904,23 @@ var SystemBackupService = class {
3831
3904
  this.logger.error("createArchive: the database owner did not say what it owns — no archive built", { meta: { error: reason } });
3832
3905
  throw new BackupSnapshotRefusedError(`the database owner could not be asked: ${reason}`);
3833
3906
  }
3834
- const inScope = /* @__PURE__ */ new Set();
3835
- for (const abs of declared) {
3836
- const rel = this.archiveRelative(abs);
3837
- if (rel !== null && walked.has(rel)) inScope.add(rel);
3907
+ const inScope = /* @__PURE__ */ new Map();
3908
+ for (const db of declared) {
3909
+ const rel = this.archiveRelative(db.livePath);
3910
+ if (rel !== null && (walked === null || walked.has(rel))) inScope.set(rel, db.databaseId);
3838
3911
  }
3839
3912
  return inScope;
3840
3913
  }
3841
3914
  /**
3842
- * Ask the owner for its snapshot, and place it in this archive. The snapshot
3843
- * must sit on THIS data root — the call is pinned to this node, so a path
3844
- * elsewhere means it reached another host, and that file is not ours to
3845
- * read — beside an owned database in scope, and it must cover EVERY owned
3846
- * database in scope. Anything else is refused.
3915
+ * Ask the owner for one verified snapshot per SELECTED database, one after
3916
+ * the other, and place each in this archive. A snapshot must sit on THIS data
3917
+ * root — the call is pinned to this node, so a path elsewhere means it
3918
+ * reached another host, and that file is not ours to read — beside the very
3919
+ * database it was asked for. Anything else is refused, and the run builds
3920
+ * nothing: the copies already taken are removed.
3847
3921
  *
3848
- * Only ever DELETED here: `<owned db>.backup-snapshot` under this data root,
3849
- * a name this process derives itself. A path the owner ANSWERS is never
3922
+ * Only ever DELETED here: `<selected db>.backup-snapshot` under this data
3923
+ * root, a name this process derives itself. A path the owner ANSWERS is never
3850
3924
  * deleted on its word — answering the live database as the snapshot would
3851
3925
  * otherwise delete the live database. A file at any other path is left to
3852
3926
  * the owner's own sweep.
@@ -3854,62 +3928,73 @@ var SystemBackupService = class {
3854
3928
  * A cancel is honoured while the owner is still copying; the copy it may
3855
3929
  * finish afterwards is removed when that call settles.
3856
3930
  */
3857
- async takeOwnerSnapshot(owner, owned, signal) {
3931
+ async takeOwnerSnapshots(owner, selected, signal) {
3858
3932
  const removeOwnedSnapshots = async () => {
3859
- for (const db of owned) await this.removeSnapshot(node_path.join(this.dataDir, db + require_dist.DATABASE_SNAPSHOT_SUFFIX));
3933
+ for (const db of selected.keys()) await this.removeSnapshot(node_path.join(this.dataDir, db + require_dist.DATABASE_SNAPSHOT_SUFFIX));
3860
3934
  };
3935
+ const taken = [];
3936
+ try {
3937
+ for (const [expectedLive, databaseId] of selected) {
3938
+ throwIfCancelled(signal);
3939
+ taken.push(await this.takeOneSnapshot(owner, databaseId, expectedLive, signal, selected, removeOwnedSnapshots));
3940
+ }
3941
+ } catch (err) {
3942
+ await removeOwnedSnapshots();
3943
+ throw err;
3944
+ }
3945
+ return taken;
3946
+ }
3947
+ async takeOneSnapshot(owner, databaseId, expectedLive, signal, selected, removeOwnedSnapshots) {
3861
3948
  let result;
3862
3949
  try {
3863
- result = await raceAbort(owner.writeSnapshot(), signal, () => {
3864
- this.logger.info("createArchive: run cancelled while the owner copied — its copy is removed when it lands", { meta: { databases: [...owned] } });
3950
+ result = await raceAbort(owner.writeSnapshot(databaseId), signal, () => {
3951
+ this.logger.info("createArchive: run cancelled while the owner copied — its copy is removed when it lands", { meta: {
3952
+ databases: [...selected.values()],
3953
+ database: databaseId
3954
+ } });
3865
3955
  return removeOwnedSnapshots();
3866
3956
  });
3867
3957
  } catch (err) {
3868
3958
  if (err instanceof BackupCancelledError) throw err;
3869
3959
  const reason = err instanceof Error ? err.message : String(err);
3870
3960
  this.logger.error("createArchive: the owner could not snapshot its live database — no archive built", { meta: {
3871
- databases: [...owned],
3961
+ databases: [...selected.values()],
3962
+ database: databaseId,
3872
3963
  error: reason
3873
3964
  } });
3874
- await removeOwnedSnapshots();
3875
- throw new BackupSnapshotRefusedError(reason);
3965
+ throw new BackupSnapshotRefusedError(`${databaseId}: ${reason}`);
3876
3966
  }
3877
- try {
3878
- const livePath = this.archiveRelative(result.livePath);
3879
- const snapshotPath = this.archiveRelative(result.snapshotPath);
3880
- if (livePath === null || snapshotPath === null) {
3881
- this.logger.warn("createArchive: the owner answered a snapshot outside this data root — not touched, left to its sweep", { meta: {
3882
- snapshot: result.snapshotPath,
3883
- dataDir: this.dataDir
3884
- } });
3885
- throw new BackupSnapshotRefusedError(`snapshot ${result.snapshotPath} is not under this archive's data root ${this.dataDir}`);
3886
- }
3887
- if (snapshotPath !== livePath + ".backup-snapshot") throw new BackupSnapshotRefusedError(`snapshot ${snapshotPath} does not sit beside the database ${livePath} it copies`);
3888
- const uncovered = [...owned].filter((db) => db !== livePath);
3889
- if (!owned.has(livePath) || uncovered.length > 0) throw new BackupSnapshotRefusedError(`snapshot copies ${livePath}, but the owned database(s) in this archive are ${[...owned].join(", ")}`);
3890
- const absPath = node_path.join(this.dataDir, snapshotPath);
3891
- const stat = await node_fs_promises.stat(absPath);
3892
- this.logger.info("createArchive: carrying the owner snapshot in place of the live database", { meta: {
3893
- database: livePath,
3894
- snapshot: snapshotPath,
3895
- sizeBytes: stat.size,
3896
- tables: result.tables.length,
3897
- copyMs: result.copyMs,
3898
- verifyMs: result.verifyMs
3967
+ const livePath = this.archiveRelative(result.livePath);
3968
+ const snapshotPath = this.archiveRelative(result.snapshotPath);
3969
+ if (livePath === null || snapshotPath === null) {
3970
+ this.logger.warn("createArchive: the owner answered a snapshot outside this data root — not touched, left to its sweep", { meta: {
3971
+ snapshot: result.snapshotPath,
3972
+ dataDir: this.dataDir
3899
3973
  } });
3900
- return {
3901
- absPath,
3902
- archived: {
3903
- ...result,
3904
- livePath,
3905
- snapshotPath
3906
- },
3907
- entry: toArchiveEntry(absPath, this.dataDir, stat)
3908
- };
3909
- } catch (err) {
3910
- await removeOwnedSnapshots();
3911
- throw err;
3974
+ throw new BackupSnapshotRefusedError(`snapshot ${result.snapshotPath} is not under this archive's data root ${this.dataDir}`);
3912
3975
  }
3976
+ if (snapshotPath !== livePath + ".backup-snapshot") throw new BackupSnapshotRefusedError(`snapshot ${snapshotPath} does not sit beside the database ${livePath} it copies`);
3977
+ if (livePath !== expectedLive || result.databaseId !== databaseId) throw new BackupSnapshotRefusedError(`snapshot copies ${livePath} (${result.databaseId}), but ${databaseId} (${expectedLive}) was asked for`);
3978
+ const absPath = node_path.join(this.dataDir, snapshotPath);
3979
+ const stat = await node_fs_promises.stat(absPath);
3980
+ this.logger.info("createArchive: carrying the owner snapshot in place of the live database", { meta: {
3981
+ database: livePath,
3982
+ databaseId,
3983
+ snapshot: snapshotPath,
3984
+ sizeBytes: stat.size,
3985
+ tables: result.tables.length,
3986
+ copyMs: result.copyMs,
3987
+ verifyMs: result.verifyMs
3988
+ } });
3989
+ return {
3990
+ absPath,
3991
+ archived: {
3992
+ ...result,
3993
+ livePath,
3994
+ snapshotPath
3995
+ },
3996
+ entry: toArchiveEntry(absPath, this.dataDir, stat)
3997
+ };
3913
3998
  }
3914
3999
  async removeSnapshot(absPath) {
3915
4000
  try {
@@ -4089,6 +4174,12 @@ Object.defineProperty(exports, "BackupSnapshotRefusedError", {
4089
4174
  return BackupSnapshotRefusedError;
4090
4175
  }
4091
4176
  });
4177
+ Object.defineProperty(exports, "DEFAULT_BACKUP_DATABASES", {
4178
+ enumerable: true,
4179
+ get: function() {
4180
+ return DEFAULT_BACKUP_DATABASES;
4181
+ }
4182
+ });
4092
4183
  Object.defineProperty(exports, "ENCRYPTED_BACKUP_SUFFIX", {
4093
4184
  enumerable: true,
4094
4185
  get: function() {
@@ -1,4 +1,4 @@
1
- import { g as DATABASE_SNAPSHOT_SUFFIX } from "./dist-DimotS8e.mjs";
1
+ import { g as DATABASE_SNAPSHOT_SUFFIX } from "./dist-DMWeqeTF.mjs";
2
2
  import { createCipheriv, createDecipheriv, createHash, createPrivateKey, createPublicKey, diffieHellman, generateKeyPairSync, hkdfSync, randomBytes } from "node:crypto";
3
3
  import { Buffer as Buffer$1 } from "buffer";
4
4
  import * as fsp from "node:fs/promises";
@@ -3497,6 +3497,11 @@ function isSqlitePath(relPath) {
3497
3497
  const db = databaseOfSidecar(relPath) ?? relPath;
3498
3498
  return SQLITE_DATABASE_SUFFIXES.some((suffix) => db.endsWith(suffix));
3499
3499
  }
3500
+ /**
3501
+ * The databases a run carries when it states none: the minimum (D382). A
3502
+ * schedule, a manual run and `createArchive` all fall back to this one value.
3503
+ */
3504
+ var DEFAULT_BACKUP_DATABASES = ["settings"];
3500
3505
  /** Path of the manifest file embedded inside every archive. */
3501
3506
  var ARCHIVE_MANIFEST_NAME = ".camstack-backup-manifest.json";
3502
3507
  var DEFAULT_STAT_CACHE_TTL_MS = 6e4;
@@ -3585,6 +3590,8 @@ var SystemBackupService = class {
3585
3590
  throwIfCancelled(opts.signal);
3586
3591
  const recipient = opts.encryptTo !== void 0 ? parseBackupPublicKey(opts.encryptTo) : null;
3587
3592
  const requested = opts.locations ?? DEFAULT_BACKUP_LOCATIONS;
3593
+ const selection = new Set(opts.databases ?? DEFAULT_BACKUP_DATABASES);
3594
+ if (!selection.has("settings")) return this.createSnapshotsOnlyArchive(opts, selection, recipient);
3588
3595
  const present = [];
3589
3596
  for (const loc of requested) {
3590
3597
  const abs = path$1.isAbsolute(loc) ? loc : path$1.join(this.dataDir, loc);
@@ -3602,7 +3609,12 @@ var SystemBackupService = class {
3602
3609
  else if (!isExcludedFromBackup(path$1.relative(this.dataDir, abs))) walked.push(toArchiveEntry(abs, this.dataDir, stat));
3603
3610
  }
3604
3611
  const walkedPaths = new Set(walked.map((e) => e.path));
3605
- const owned = walked.some((e) => isSqlitePath(e.path)) ? await this.ownedDatabasesInScope(opts.owner, walkedPaths) : /* @__PURE__ */ new Set();
3612
+ const ownedById = walked.some((e) => isSqlitePath(e.path)) ? await this.ownedDatabasesInScope(opts.owner, walkedPaths) : /* @__PURE__ */ new Map();
3613
+ const owned = new Set(ownedById.keys());
3614
+ const selected = /* @__PURE__ */ new Map();
3615
+ const omitted = /* @__PURE__ */ new Set();
3616
+ for (const [rel, databaseId] of ownedById) if (selection.has(databaseId)) selected.set(rel, databaseId);
3617
+ else omitted.add(databaseId);
3606
3618
  const unowned = /* @__PURE__ */ new Set();
3607
3619
  for (const e of walked) {
3608
3620
  const db = databaseOfSidecar(e.path);
@@ -3616,7 +3628,7 @@ var SystemBackupService = class {
3616
3628
  } });
3617
3629
  throw new BackupSnapshotRefusedError(`live SQLite database ${databases.join(", ")} has no owner that can snapshot it — a copy of its files would be torn; remove its stale -wal/-shm/-journal if nothing has it open, or leave its location out of the backup`);
3618
3630
  }
3619
- const snapshot = owned.size > 0 && opts.owner ? await this.takeOwnerSnapshot(opts.owner, owned, opts.signal) : null;
3631
+ const snapshots = selected.size > 0 && opts.owner ? await this.takeOwnerSnapshots(opts.owner, selected, opts.signal) : [];
3620
3632
  try {
3621
3633
  const liveFiles = /* @__PURE__ */ new Set();
3622
3634
  for (const db of owned) {
@@ -3624,7 +3636,7 @@ var SystemBackupService = class {
3624
3636
  for (const suffix of SQLITE_SIDECAR_SUFFIXES) liveFiles.add(db + suffix);
3625
3637
  }
3626
3638
  const entries = walked.filter((e) => !liveFiles.has(e.path));
3627
- if (snapshot !== null) entries.push(snapshot.entry);
3639
+ for (const snapshot of snapshots) entries.push(snapshot.entry);
3628
3640
  const manifest = {
3629
3641
  archiveVersion: 1,
3630
3642
  createdAt: Date.now(),
@@ -3633,15 +3645,20 @@ var SystemBackupService = class {
3633
3645
  entries,
3634
3646
  totalBytes: entries.reduce((acc, e) => acc + e.sizeBytes, 0),
3635
3647
  totalFiles: entries.filter((e) => e.kind === "file").length,
3636
- ...snapshot !== null ? { sqliteSnapshots: [snapshot.archived] } : {}
3648
+ ...snapshots.length > 0 ? { sqliteSnapshots: snapshots.map((snapshot) => snapshot.archived) } : {},
3649
+ ...omitted.size > 0 ? { omittedDatabases: [...omitted].toSorted() } : {}
3637
3650
  };
3638
- const carriedSnapshot = snapshot?.archived.snapshotPath ?? null;
3651
+ if (omitted.size > 0) this.logger.info("createArchive: owned databases left out of this run", { meta: {
3652
+ omitted: [...omitted].toSorted(),
3653
+ carried: [...selected.values()]
3654
+ } });
3655
+ const carriedSnapshots = new Set(snapshots.map((snapshot) => snapshot.archived.snapshotPath));
3639
3656
  return await this.writeArchive({
3640
3657
  archivePath: opts.archivePath,
3641
3658
  present,
3642
3659
  manifest,
3643
3660
  excluded: (rel) => {
3644
- if (rel === carriedSnapshot) return false;
3661
+ if (carriedSnapshots.has(rel)) return false;
3645
3662
  return liveFiles.has(rel) || isExcludedFromBackup(rel);
3646
3663
  },
3647
3664
  ...opts.signal ? { signal: opts.signal } : {},
@@ -3655,7 +3672,62 @@ var SystemBackupService = class {
3655
3672
  }
3656
3673
  });
3657
3674
  } finally {
3658
- if (snapshot !== null) await this.removeSnapshot(snapshot.absPath);
3675
+ for (const snapshot of snapshots) await this.removeSnapshot(snapshot.absPath);
3676
+ }
3677
+ }
3678
+ /**
3679
+ * An archive of the selected databases' owner snapshots and the manifest —
3680
+ * no data-root walk, no location, no settings (D852). Refused when the owner
3681
+ * has none of the selected files: an archive of nothing must reach no
3682
+ * destination, because its upload prunes an older archive that has them.
3683
+ */
3684
+ async createSnapshotsOnlyArchive(opts, selection, recipient) {
3685
+ if (opts.owner === void 0) throw new BackupSnapshotRefusedError("a snapshots-only archive needs the database owner, and none was given");
3686
+ fs$1.mkdirSync(path$1.dirname(opts.archivePath), { recursive: true });
3687
+ const ownedById = await this.ownedDatabasesInScope(opts.owner, null);
3688
+ const selected = /* @__PURE__ */ new Map();
3689
+ for (const [rel, databaseId] of ownedById) if (selection.has(databaseId)) selected.set(rel, databaseId);
3690
+ if (selected.size === 0) {
3691
+ this.logger.warn("createArchive: the owner has none of the selected databases — no archive built", { meta: {
3692
+ requested: [...selection].toSorted(),
3693
+ archivePath: opts.archivePath
3694
+ } });
3695
+ throw new BackupSnapshotRefusedError(`the owner has none of the selected databases (${[...selection].toSorted().join(", ")})`);
3696
+ }
3697
+ const snapshots = await this.takeOwnerSnapshots(opts.owner, selected, opts.signal);
3698
+ try {
3699
+ const entries = snapshots.map((snapshot) => snapshot.entry);
3700
+ const manifest = {
3701
+ archiveVersion: 1,
3702
+ createdAt: Date.now(),
3703
+ dataDir: this.dataDir,
3704
+ locations: [],
3705
+ entries,
3706
+ totalBytes: entries.reduce((acc, e) => acc + e.sizeBytes, 0),
3707
+ totalFiles: entries.length,
3708
+ sqliteSnapshots: snapshots.map((snapshot) => snapshot.archived)
3709
+ };
3710
+ const carried = snapshots.map((snapshot) => snapshot.archived.snapshotPath);
3711
+ const carriedSet = new Set(carried);
3712
+ const result = await this.writeArchive({
3713
+ archivePath: opts.archivePath,
3714
+ present: [],
3715
+ tarRoots: carried,
3716
+ manifest,
3717
+ excluded: (rel) => rel !== ".camstack-backup-manifest.json" && !carriedSet.has(rel),
3718
+ ...opts.signal ? { signal: opts.signal } : {},
3719
+ ...opts.onArchiveBytes ? { onArchiveBytes: opts.onArchiveBytes } : {},
3720
+ ...opts.encryptTo !== void 0 ? { encryptTo: opts.encryptTo } : {}
3721
+ });
3722
+ return recipient === null ? result : {
3723
+ ...result,
3724
+ encryption: {
3725
+ scheme: BACKUP_ENCRYPTION_SCHEME,
3726
+ keyId: recipient.keyId
3727
+ }
3728
+ };
3729
+ } finally {
3730
+ for (const snapshot of snapshots) await this.removeSnapshot(snapshot.absPath);
3659
3731
  }
3660
3732
  }
3661
3733
  /**
@@ -3689,7 +3761,7 @@ var SystemBackupService = class {
3689
3761
  if (!excludePrefix) return true;
3690
3762
  return norm !== excludePrefix && !norm.startsWith(`${excludePrefix}/`);
3691
3763
  }
3692
- }, [ARCHIVE_MANIFEST_NAME, ...present]);
3764
+ }, [ARCHIVE_MANIFEST_NAME, ...opts.tarRoots ?? present]);
3693
3765
  const sink = fs$1.createWriteStream(opts.archivePath, { mode: 384 });
3694
3766
  try {
3695
3767
  const streamOpts = opts.signal ? { signal: opts.signal } : {};
@@ -3806,12 +3878,13 @@ var SystemBackupService = class {
3806
3878
  if (fs$1.existsSync(markerPath)) fs$1.rmSync(markerPath, { force: true });
3807
3879
  }
3808
3880
  /**
3809
- * The databases the owner declares, archive-relative, that this walk found.
3810
- * One outside this data root is not in scope. An owner that cannot answer
3811
- * stops the archive: without the answer, nothing says which file is live.
3881
+ * The databases the owner declares, archive-relative, that this walk found,
3882
+ * with the id of each. One outside this data root is not in scope. An owner
3883
+ * that cannot answer stops the archive: without the answer, nothing says
3884
+ * which file is live.
3812
3885
  */
3813
3886
  async ownedDatabasesInScope(owner, walked) {
3814
- if (owner === void 0) return /* @__PURE__ */ new Set();
3887
+ if (owner === void 0) return /* @__PURE__ */ new Map();
3815
3888
  let declared;
3816
3889
  try {
3817
3890
  declared = await owner.listDatabases();
@@ -3820,22 +3893,23 @@ var SystemBackupService = class {
3820
3893
  this.logger.error("createArchive: the database owner did not say what it owns — no archive built", { meta: { error: reason } });
3821
3894
  throw new BackupSnapshotRefusedError(`the database owner could not be asked: ${reason}`);
3822
3895
  }
3823
- const inScope = /* @__PURE__ */ new Set();
3824
- for (const abs of declared) {
3825
- const rel = this.archiveRelative(abs);
3826
- if (rel !== null && walked.has(rel)) inScope.add(rel);
3896
+ const inScope = /* @__PURE__ */ new Map();
3897
+ for (const db of declared) {
3898
+ const rel = this.archiveRelative(db.livePath);
3899
+ if (rel !== null && (walked === null || walked.has(rel))) inScope.set(rel, db.databaseId);
3827
3900
  }
3828
3901
  return inScope;
3829
3902
  }
3830
3903
  /**
3831
- * Ask the owner for its snapshot, and place it in this archive. The snapshot
3832
- * must sit on THIS data root — the call is pinned to this node, so a path
3833
- * elsewhere means it reached another host, and that file is not ours to
3834
- * read — beside an owned database in scope, and it must cover EVERY owned
3835
- * database in scope. Anything else is refused.
3904
+ * Ask the owner for one verified snapshot per SELECTED database, one after
3905
+ * the other, and place each in this archive. A snapshot must sit on THIS data
3906
+ * root — the call is pinned to this node, so a path elsewhere means it
3907
+ * reached another host, and that file is not ours to read — beside the very
3908
+ * database it was asked for. Anything else is refused, and the run builds
3909
+ * nothing: the copies already taken are removed.
3836
3910
  *
3837
- * Only ever DELETED here: `<owned db>.backup-snapshot` under this data root,
3838
- * a name this process derives itself. A path the owner ANSWERS is never
3911
+ * Only ever DELETED here: `<selected db>.backup-snapshot` under this data
3912
+ * root, a name this process derives itself. A path the owner ANSWERS is never
3839
3913
  * deleted on its word — answering the live database as the snapshot would
3840
3914
  * otherwise delete the live database. A file at any other path is left to
3841
3915
  * the owner's own sweep.
@@ -3843,62 +3917,73 @@ var SystemBackupService = class {
3843
3917
  * A cancel is honoured while the owner is still copying; the copy it may
3844
3918
  * finish afterwards is removed when that call settles.
3845
3919
  */
3846
- async takeOwnerSnapshot(owner, owned, signal) {
3920
+ async takeOwnerSnapshots(owner, selected, signal) {
3847
3921
  const removeOwnedSnapshots = async () => {
3848
- for (const db of owned) await this.removeSnapshot(path$1.join(this.dataDir, db + DATABASE_SNAPSHOT_SUFFIX));
3922
+ for (const db of selected.keys()) await this.removeSnapshot(path$1.join(this.dataDir, db + DATABASE_SNAPSHOT_SUFFIX));
3849
3923
  };
3924
+ const taken = [];
3925
+ try {
3926
+ for (const [expectedLive, databaseId] of selected) {
3927
+ throwIfCancelled(signal);
3928
+ taken.push(await this.takeOneSnapshot(owner, databaseId, expectedLive, signal, selected, removeOwnedSnapshots));
3929
+ }
3930
+ } catch (err) {
3931
+ await removeOwnedSnapshots();
3932
+ throw err;
3933
+ }
3934
+ return taken;
3935
+ }
3936
+ async takeOneSnapshot(owner, databaseId, expectedLive, signal, selected, removeOwnedSnapshots) {
3850
3937
  let result;
3851
3938
  try {
3852
- result = await raceAbort(owner.writeSnapshot(), signal, () => {
3853
- this.logger.info("createArchive: run cancelled while the owner copied — its copy is removed when it lands", { meta: { databases: [...owned] } });
3939
+ result = await raceAbort(owner.writeSnapshot(databaseId), signal, () => {
3940
+ this.logger.info("createArchive: run cancelled while the owner copied — its copy is removed when it lands", { meta: {
3941
+ databases: [...selected.values()],
3942
+ database: databaseId
3943
+ } });
3854
3944
  return removeOwnedSnapshots();
3855
3945
  });
3856
3946
  } catch (err) {
3857
3947
  if (err instanceof BackupCancelledError) throw err;
3858
3948
  const reason = err instanceof Error ? err.message : String(err);
3859
3949
  this.logger.error("createArchive: the owner could not snapshot its live database — no archive built", { meta: {
3860
- databases: [...owned],
3950
+ databases: [...selected.values()],
3951
+ database: databaseId,
3861
3952
  error: reason
3862
3953
  } });
3863
- await removeOwnedSnapshots();
3864
- throw new BackupSnapshotRefusedError(reason);
3954
+ throw new BackupSnapshotRefusedError(`${databaseId}: ${reason}`);
3865
3955
  }
3866
- try {
3867
- const livePath = this.archiveRelative(result.livePath);
3868
- const snapshotPath = this.archiveRelative(result.snapshotPath);
3869
- if (livePath === null || snapshotPath === null) {
3870
- this.logger.warn("createArchive: the owner answered a snapshot outside this data root — not touched, left to its sweep", { meta: {
3871
- snapshot: result.snapshotPath,
3872
- dataDir: this.dataDir
3873
- } });
3874
- throw new BackupSnapshotRefusedError(`snapshot ${result.snapshotPath} is not under this archive's data root ${this.dataDir}`);
3875
- }
3876
- if (snapshotPath !== livePath + ".backup-snapshot") throw new BackupSnapshotRefusedError(`snapshot ${snapshotPath} does not sit beside the database ${livePath} it copies`);
3877
- const uncovered = [...owned].filter((db) => db !== livePath);
3878
- if (!owned.has(livePath) || uncovered.length > 0) throw new BackupSnapshotRefusedError(`snapshot copies ${livePath}, but the owned database(s) in this archive are ${[...owned].join(", ")}`);
3879
- const absPath = path$1.join(this.dataDir, snapshotPath);
3880
- const stat = await fsp.stat(absPath);
3881
- this.logger.info("createArchive: carrying the owner snapshot in place of the live database", { meta: {
3882
- database: livePath,
3883
- snapshot: snapshotPath,
3884
- sizeBytes: stat.size,
3885
- tables: result.tables.length,
3886
- copyMs: result.copyMs,
3887
- verifyMs: result.verifyMs
3956
+ const livePath = this.archiveRelative(result.livePath);
3957
+ const snapshotPath = this.archiveRelative(result.snapshotPath);
3958
+ if (livePath === null || snapshotPath === null) {
3959
+ this.logger.warn("createArchive: the owner answered a snapshot outside this data root — not touched, left to its sweep", { meta: {
3960
+ snapshot: result.snapshotPath,
3961
+ dataDir: this.dataDir
3888
3962
  } });
3889
- return {
3890
- absPath,
3891
- archived: {
3892
- ...result,
3893
- livePath,
3894
- snapshotPath
3895
- },
3896
- entry: toArchiveEntry(absPath, this.dataDir, stat)
3897
- };
3898
- } catch (err) {
3899
- await removeOwnedSnapshots();
3900
- throw err;
3963
+ throw new BackupSnapshotRefusedError(`snapshot ${result.snapshotPath} is not under this archive's data root ${this.dataDir}`);
3901
3964
  }
3965
+ if (snapshotPath !== livePath + ".backup-snapshot") throw new BackupSnapshotRefusedError(`snapshot ${snapshotPath} does not sit beside the database ${livePath} it copies`);
3966
+ if (livePath !== expectedLive || result.databaseId !== databaseId) throw new BackupSnapshotRefusedError(`snapshot copies ${livePath} (${result.databaseId}), but ${databaseId} (${expectedLive}) was asked for`);
3967
+ const absPath = path$1.join(this.dataDir, snapshotPath);
3968
+ const stat = await fsp.stat(absPath);
3969
+ this.logger.info("createArchive: carrying the owner snapshot in place of the live database", { meta: {
3970
+ database: livePath,
3971
+ databaseId,
3972
+ snapshot: snapshotPath,
3973
+ sizeBytes: stat.size,
3974
+ tables: result.tables.length,
3975
+ copyMs: result.copyMs,
3976
+ verifyMs: result.verifyMs
3977
+ } });
3978
+ return {
3979
+ absPath,
3980
+ archived: {
3981
+ ...result,
3982
+ livePath,
3983
+ snapshotPath
3984
+ },
3985
+ entry: toArchiveEntry(absPath, this.dataDir, stat)
3986
+ };
3902
3987
  }
3903
3988
  async removeSnapshot(absPath) {
3904
3989
  try {
@@ -4042,4 +4127,4 @@ async function prepareRestoreArchive(input) {
4042
4127
  }
4043
4128
  }
4044
4129
  //#endregion
4045
- export { BackupSnapshotRefusedError as a, BackupKeyFormatError as c, generateBackupKeyPair as d, parseBackupPublicKey as f, BackupCancelledError as i, BackupKeyMismatchError as l, readBackupEncryptionHeader as m, precheckRestoreKey as n, SystemBackupService as o, parseBackupSecretKey as p, prepareRestoreArchive as r, BackupDecryptError as s, BackupKeyRequiredError as t, ENCRYPTED_BACKUP_SUFFIX as u };
4130
+ export { BackupSnapshotRefusedError as a, BackupDecryptError as c, ENCRYPTED_BACKUP_SUFFIX as d, generateBackupKeyPair as f, readBackupEncryptionHeader as h, BackupCancelledError as i, BackupKeyFormatError as l, parseBackupSecretKey as m, precheckRestoreKey as n, DEFAULT_BACKUP_DATABASES as o, parseBackupPublicKey as p, prepareRestoreArchive as r, SystemBackupService as s, BackupKeyRequiredError as t, BackupKeyMismatchError as u };