@camstack/system 1.2.19 → 1.2.20

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.
@@ -3,6 +3,15 @@ export declare class BackupOrchestratorAddon extends BaseAddon<Record<string, ne
3
3
  private systemBackup;
4
4
  private policies;
5
5
  private dataDir;
6
+ /**
7
+ * Transient build buffer for archive fan-out. The tar is built here
8
+ * ONCE, streamed to every destination via the storage cap's chunked
9
+ * upload, then removed. Lives in the addon's private `ctx.dataDir`
10
+ * (never `api.storage.resolve`, per the AddonContext contract) — a
11
+ * `cache` storage location is never declared, so resolving one threw
12
+ * and aborted every run before a byte was written.
13
+ */
14
+ private stagingDir;
6
15
  private scheduleTimer;
7
16
  /**
8
17
  * Baseline used as the "after" anchor when a policy has a cron but
@@ -47,12 +56,13 @@ export declare class BackupOrchestratorAddon extends BaseAddon<Record<string, ne
47
56
  * unreachable destination doesn't blank out the whole UI.
48
57
  */
49
58
  private aggregatedList;
59
+ private stagingPath;
50
60
  /**
51
- * Build a single archive in the `cache` storage location, then push
61
+ * Build a single archive in the private staging dir, then push
52
62
  * it to every selected destination via the storage cap's chunked
53
63
  * upload protocol. Per-destination errors are logged and counted
54
64
  * via allSettled semantics — one bad sink doesn't kill the run. The
55
- * cache file is deleted in `finally` so a crash mid-fanout doesn't
65
+ * staging file is deleted in `finally` so a crash mid-fanout doesn't
56
66
  * leak.
57
67
  */
58
68
  private triggerBackup;
@@ -99,8 +109,8 @@ export declare class BackupOrchestratorAddon extends BaseAddon<Record<string, ne
99
109
  /**
100
110
  * Schedule a restore for the next boot. Pulls the archive bytes
101
111
  * down from the destination's storage location via the chunked-
102
- * download protocol into the `cache` location, then writes the
103
- * usual restore marker against the cached path so the boot-time
112
+ * download protocol into the private staging dir, then writes the
113
+ * usual restore marker against the staged path so the boot-time
104
114
  * apply hook (in server-backend launcher) extracts before any
105
115
  * addon starts.
106
116
  *
@@ -4587,8 +4587,8 @@ function previewNextRuns(cron, count, after) {
4587
4587
  * that list with the `backup_destination_policies` table to surface
4588
4588
  * `enabled` / `retentionCount` / `label`. The actual archive bytes
4589
4589
  * travel through `api.storage.beginUpload` / `writeChunk` /
4590
- * `finalizeUpload`, with the staging archive built into the `cache`
4591
- * location.
4590
+ * `finalizeUpload`, with the staging archive built into the addon's
4591
+ * private `ctx.dataDir/staging` dir.
4592
4592
  */
4593
4593
  /**
4594
4594
  * Hardcoded seed for newly-discovered `backups` locations. Operators
@@ -4636,6 +4636,15 @@ var BackupOrchestratorAddon = class extends require_dist.BaseAddon {
4636
4636
  systemBackup = null;
4637
4637
  policies = null;
4638
4638
  dataDir = "";
4639
+ /**
4640
+ * Transient build buffer for archive fan-out. The tar is built here
4641
+ * ONCE, streamed to every destination via the storage cap's chunked
4642
+ * upload, then removed. Lives in the addon's private `ctx.dataDir`
4643
+ * (never `api.storage.resolve`, per the AddonContext contract) — a
4644
+ * `cache` storage location is never declared, so resolving one threw
4645
+ * and aborted every run before a byte was written.
4646
+ */
4647
+ stagingDir = "";
4639
4648
  scheduleTimer = null;
4640
4649
  /**
4641
4650
  * Baseline used as the "after" anchor when a policy has a cron but
@@ -4650,6 +4659,7 @@ var BackupOrchestratorAddon = class extends require_dist.BaseAddon {
4650
4659
  }
4651
4660
  async onInitialize() {
4652
4661
  this.dataDir = this.ctx.nodeDataDir;
4662
+ this.stagingDir = node_path.join(this.ctx.dataDir, "staging");
4653
4663
  this.systemBackup = new SystemBackupService(this.dataDir, this.ctx.logger);
4654
4664
  this.policies = this.resolvePolicyService();
4655
4665
  if (this.policies) try {
@@ -4826,12 +4836,16 @@ var BackupOrchestratorAddon = class extends require_dist.BaseAddon {
4826
4836
  }
4827
4837
  return out;
4828
4838
  }
4839
+ async stagingPath(filename) {
4840
+ await node_fs_promises.mkdir(this.stagingDir, { recursive: true });
4841
+ return node_path.join(this.stagingDir, filename);
4842
+ }
4829
4843
  /**
4830
- * Build a single archive in the `cache` storage location, then push
4844
+ * Build a single archive in the private staging dir, then push
4831
4845
  * it to every selected destination via the storage cap's chunked
4832
4846
  * upload protocol. Per-destination errors are logged and counted
4833
4847
  * via allSettled semantics — one bad sink doesn't kill the run. The
4834
- * cache file is deleted in `finally` so a crash mid-fanout doesn't
4848
+ * staging file is deleted in `finally` so a crash mid-fanout doesn't
4835
4849
  * leak.
4836
4850
  */
4837
4851
  async triggerBackup(input) {
@@ -4844,11 +4858,7 @@ var BackupOrchestratorAddon = class extends require_dist.BaseAddon {
4844
4858
  const policies = await this.loadPoliciesIndexed(targets.map((t) => t.id));
4845
4859
  const archiveId = (0, node_crypto.randomUUID)();
4846
4860
  const archiveFilename = `${archiveId}.tar.gz`;
4847
- const cacheRelativePath = `${archiveId}.tar.gz`;
4848
- const cachePath = await this.ctx.api.storage.resolve.query({
4849
- location: "cache",
4850
- relativePath: cacheRelativePath
4851
- });
4861
+ const cachePath = await this.stagingPath(archiveFilename);
4852
4862
  const result = await this.systemBackup.createArchive({
4853
4863
  archivePath: cachePath,
4854
4864
  ...input?.locations ? { locations: input.locations } : {}
@@ -5092,8 +5102,8 @@ var BackupOrchestratorAddon = class extends require_dist.BaseAddon {
5092
5102
  /**
5093
5103
  * Schedule a restore for the next boot. Pulls the archive bytes
5094
5104
  * down from the destination's storage location via the chunked-
5095
- * download protocol into the `cache` location, then writes the
5096
- * usual restore marker against the cached path so the boot-time
5105
+ * download protocol into the private staging dir, then writes the
5106
+ * usual restore marker against the staged path so the boot-time
5097
5107
  * apply hook (in server-backend launcher) extracts before any
5098
5108
  * addon starts.
5099
5109
  *
@@ -5104,10 +5114,7 @@ var BackupOrchestratorAddon = class extends require_dist.BaseAddon {
5104
5114
  if (!this.systemBackup) throw new Error("orchestrator not initialized");
5105
5115
  const entry = (await readLocationManifest(this.storageApi(), input.destinationId)).archives.find((a) => a.id === input.backupId);
5106
5116
  if (!entry) throw new Error(`backup restore: backup "${input.backupId}" not found at location "${input.destinationId}"`);
5107
- const cachePath = await this.ctx.api.storage.resolve.query({
5108
- location: "cache",
5109
- relativePath: `restore-${input.backupId}.tar.gz`
5110
- });
5117
+ const cachePath = await this.stagingPath(`restore-${input.backupId}.tar.gz`);
5111
5118
  await downloadArchiveToCache({
5112
5119
  api: this.ctx.api.storage,
5113
5120
  locationId: input.destinationId,
@@ -4572,8 +4572,8 @@ function previewNextRuns(cron, count, after) {
4572
4572
  * that list with the `backup_destination_policies` table to surface
4573
4573
  * `enabled` / `retentionCount` / `label`. The actual archive bytes
4574
4574
  * travel through `api.storage.beginUpload` / `writeChunk` /
4575
- * `finalizeUpload`, with the staging archive built into the `cache`
4576
- * location.
4575
+ * `finalizeUpload`, with the staging archive built into the addon's
4576
+ * private `ctx.dataDir/staging` dir.
4577
4577
  */
4578
4578
  /**
4579
4579
  * Hardcoded seed for newly-discovered `backups` locations. Operators
@@ -4621,6 +4621,15 @@ var BackupOrchestratorAddon = class extends BaseAddon {
4621
4621
  systemBackup = null;
4622
4622
  policies = null;
4623
4623
  dataDir = "";
4624
+ /**
4625
+ * Transient build buffer for archive fan-out. The tar is built here
4626
+ * ONCE, streamed to every destination via the storage cap's chunked
4627
+ * upload, then removed. Lives in the addon's private `ctx.dataDir`
4628
+ * (never `api.storage.resolve`, per the AddonContext contract) — a
4629
+ * `cache` storage location is never declared, so resolving one threw
4630
+ * and aborted every run before a byte was written.
4631
+ */
4632
+ stagingDir = "";
4624
4633
  scheduleTimer = null;
4625
4634
  /**
4626
4635
  * Baseline used as the "after" anchor when a policy has a cron but
@@ -4635,6 +4644,7 @@ var BackupOrchestratorAddon = class extends BaseAddon {
4635
4644
  }
4636
4645
  async onInitialize() {
4637
4646
  this.dataDir = this.ctx.nodeDataDir;
4647
+ this.stagingDir = path$1.join(this.ctx.dataDir, "staging");
4638
4648
  this.systemBackup = new SystemBackupService(this.dataDir, this.ctx.logger);
4639
4649
  this.policies = this.resolvePolicyService();
4640
4650
  if (this.policies) try {
@@ -4811,12 +4821,16 @@ var BackupOrchestratorAddon = class extends BaseAddon {
4811
4821
  }
4812
4822
  return out;
4813
4823
  }
4824
+ async stagingPath(filename) {
4825
+ await fsp.mkdir(this.stagingDir, { recursive: true });
4826
+ return path$1.join(this.stagingDir, filename);
4827
+ }
4814
4828
  /**
4815
- * Build a single archive in the `cache` storage location, then push
4829
+ * Build a single archive in the private staging dir, then push
4816
4830
  * it to every selected destination via the storage cap's chunked
4817
4831
  * upload protocol. Per-destination errors are logged and counted
4818
4832
  * via allSettled semantics — one bad sink doesn't kill the run. The
4819
- * cache file is deleted in `finally` so a crash mid-fanout doesn't
4833
+ * staging file is deleted in `finally` so a crash mid-fanout doesn't
4820
4834
  * leak.
4821
4835
  */
4822
4836
  async triggerBackup(input) {
@@ -4829,11 +4843,7 @@ var BackupOrchestratorAddon = class extends BaseAddon {
4829
4843
  const policies = await this.loadPoliciesIndexed(targets.map((t) => t.id));
4830
4844
  const archiveId = randomUUID();
4831
4845
  const archiveFilename = `${archiveId}.tar.gz`;
4832
- const cacheRelativePath = `${archiveId}.tar.gz`;
4833
- const cachePath = await this.ctx.api.storage.resolve.query({
4834
- location: "cache",
4835
- relativePath: cacheRelativePath
4836
- });
4846
+ const cachePath = await this.stagingPath(archiveFilename);
4837
4847
  const result = await this.systemBackup.createArchive({
4838
4848
  archivePath: cachePath,
4839
4849
  ...input?.locations ? { locations: input.locations } : {}
@@ -5077,8 +5087,8 @@ var BackupOrchestratorAddon = class extends BaseAddon {
5077
5087
  /**
5078
5088
  * Schedule a restore for the next boot. Pulls the archive bytes
5079
5089
  * down from the destination's storage location via the chunked-
5080
- * download protocol into the `cache` location, then writes the
5081
- * usual restore marker against the cached path so the boot-time
5090
+ * download protocol into the private staging dir, then writes the
5091
+ * usual restore marker against the staged path so the boot-time
5082
5092
  * apply hook (in server-backend launcher) extracts before any
5083
5093
  * addon starts.
5084
5094
  *
@@ -5089,10 +5099,7 @@ var BackupOrchestratorAddon = class extends BaseAddon {
5089
5099
  if (!this.systemBackup) throw new Error("orchestrator not initialized");
5090
5100
  const entry = (await readLocationManifest(this.storageApi(), input.destinationId)).archives.find((a) => a.id === input.backupId);
5091
5101
  if (!entry) throw new Error(`backup restore: backup "${input.backupId}" not found at location "${input.destinationId}"`);
5092
- const cachePath = await this.ctx.api.storage.resolve.query({
5093
- location: "cache",
5094
- relativePath: `restore-${input.backupId}.tar.gz`
5095
- });
5102
+ const cachePath = await this.stagingPath(`restore-${input.backupId}.tar.gz`);
5096
5103
  await downloadArchiveToCache({
5097
5104
  api: this.ctx.api.storage,
5098
5105
  locationId: input.destinationId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.19",
3
+ "version": "1.2.20",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",