@camstack/system 1.2.30 → 1.2.32
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.
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.d.ts +10 -0
- package/dist/builtins/alerts/alerts.addon.js +60 -1
- package/dist/builtins/alerts/alerts.addon.mjs +60 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +135 -92
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +135 -92
- package/dist/builtins/backup-orchestrator/destination-policy.d.ts +12 -14
- package/dist/builtins/backup-orchestrator/schedule-store.d.ts +6 -6
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +1 -1
- package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/index.d.ts +2 -0
- package/dist/builtins/liveness-monitor/index.js +6 -0
- package/dist/builtins/liveness-monitor/index.mjs +2 -0
- package/dist/builtins/liveness-monitor/liveness-checks.d.ts +67 -0
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.d.ts +32 -0
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +216 -0
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +212 -0
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/integration-registry.d.ts +3 -3
- package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +6 -8
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +3 -25
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +3 -25
- package/dist/builtins/storage-orchestrator/location-store.d.ts +17 -24
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +0 -6
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +130 -121
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +130 -121
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-Dr_P0DOB.mjs → dist-BL_FHWPP.mjs} +33 -2
- package/dist/{dist-VIwdvws5.js → dist-CSs1A90r.js} +33 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +365 -224
- package/dist/index.mjs +365 -225
- package/package.json +10 -1
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-CSs1A90r.js");
|
|
7
7
|
const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
|
|
8
8
|
let node_fs = require("node:fs");
|
|
9
9
|
node_fs = require_chunk.__toESM(node_fs);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Mt as EventCategory, at as errMsg, ot as BaseAddon, p as addonPagesCapability } from "../../dist-
|
|
1
|
+
import { Mt as EventCategory, at as errMsg, ot as BaseAddon, p as addonPagesCapability } from "../../dist-BL_FHWPP.mjs";
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-CSs1A90r.js");
|
|
7
7
|
const require_settle_sources = require("../../settle-sources-Bhsy57y-.js");
|
|
8
8
|
let node_fs = require("node:fs");
|
|
9
9
|
node_fs = require_chunk.__toESM(node_fs);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Mt as EventCategory, at as errMsg, h as addonWidgetsCapability, ot as BaseAddon } from "../../dist-
|
|
1
|
+
import { Mt as EventCategory, at as errMsg, h as addonWidgetsCapability, ot as BaseAddon } from "../../dist-BL_FHWPP.mjs";
|
|
2
2
|
import { t as settleSourcesWithTimeout } from "../../settle-sources-CDtNC8ub.mjs";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -57,6 +57,16 @@ export declare class AlertCenterAddon extends BaseAddon<AlertCenterConfig> {
|
|
|
57
57
|
* Dismiss the matching alert so the operator's badge count drops.
|
|
58
58
|
*/
|
|
59
59
|
private handleAddonLoadRecovered;
|
|
60
|
+
/**
|
|
61
|
+
* SystemLivenessFailed — a liveness invariant of this node is false.
|
|
62
|
+
*
|
|
63
|
+
* `findingId` is already stable across ticks (`liveness:no-devices`,
|
|
64
|
+
* `liveness:no-footage:<deviceId>`, …), so it IS the alert id: an ongoing
|
|
65
|
+
* fault updates one alert instead of producing one every five minutes.
|
|
66
|
+
*/
|
|
67
|
+
private handleLivenessFailed;
|
|
68
|
+
/** SystemLivenessRecovered — the invariant holds again; drop the alert. */
|
|
69
|
+
private handleLivenessRecovered;
|
|
60
70
|
private buildMessage;
|
|
61
71
|
private emitAlert;
|
|
62
72
|
private updateAlert;
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-CSs1A90r.js");
|
|
7
7
|
//#region src/builtins/alerts/prune-policy.ts
|
|
8
8
|
/**
|
|
9
9
|
* Ids older than `cutoffMs`, oldest first.
|
|
@@ -93,6 +93,10 @@ var CATEGORY_MAPPINGS = {
|
|
|
93
93
|
severity: "error",
|
|
94
94
|
titleTemplate: "Addon failed to load"
|
|
95
95
|
},
|
|
96
|
+
"system.liveness-failed": {
|
|
97
|
+
severity: "error",
|
|
98
|
+
titleTemplate: "Node liveness"
|
|
99
|
+
},
|
|
96
100
|
"addon.load-recovered": {
|
|
97
101
|
severity: "info",
|
|
98
102
|
titleTemplate: "Addon recovered"
|
|
@@ -289,6 +293,14 @@ var AlertCenterAddon = class extends require_dist.BaseAddon {
|
|
|
289
293
|
await this.handleAddonLoadRecovered(event);
|
|
290
294
|
return;
|
|
291
295
|
}
|
|
296
|
+
if (category === require_dist.EventCategory.SystemLivenessFailed) {
|
|
297
|
+
await this.handleLivenessFailed(event);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
if (category === require_dist.EventCategory.SystemLivenessRecovered) {
|
|
301
|
+
await this.handleLivenessRecovered(event);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
292
304
|
const mapping = CATEGORY_MAPPINGS[category];
|
|
293
305
|
if (!mapping) return;
|
|
294
306
|
if (this.shouldSuppressByRate(category, event)) return;
|
|
@@ -480,6 +492,53 @@ var AlertCenterAddon = class extends require_dist.BaseAddon {
|
|
|
480
492
|
} });
|
|
481
493
|
}
|
|
482
494
|
}
|
|
495
|
+
/**
|
|
496
|
+
* SystemLivenessFailed — a liveness invariant of this node is false.
|
|
497
|
+
*
|
|
498
|
+
* `findingId` is already stable across ticks (`liveness:no-devices`,
|
|
499
|
+
* `liveness:no-footage:<deviceId>`, …), so it IS the alert id: an ongoing
|
|
500
|
+
* fault updates one alert instead of producing one every five minutes.
|
|
501
|
+
*/
|
|
502
|
+
async handleLivenessFailed(event) {
|
|
503
|
+
const data = event.data;
|
|
504
|
+
const findingId = String(data["findingId"] ?? "");
|
|
505
|
+
if (!findingId) return;
|
|
506
|
+
const deviceId = typeof data["deviceId"] === "number" ? data["deviceId"] : void 0;
|
|
507
|
+
const severity = data["severity"] === "warning" ? "warning" : "error";
|
|
508
|
+
const alert = {
|
|
509
|
+
id: findingId,
|
|
510
|
+
category: require_dist.EventCategory.SystemLivenessFailed,
|
|
511
|
+
severity,
|
|
512
|
+
title: String(data["title"] ?? "Node liveness"),
|
|
513
|
+
message: String(data["message"] ?? ""),
|
|
514
|
+
status: "active",
|
|
515
|
+
read: false,
|
|
516
|
+
createdAt: Date.now(),
|
|
517
|
+
updatedAt: Date.now(),
|
|
518
|
+
source: {
|
|
519
|
+
type: "liveness",
|
|
520
|
+
id: findingId
|
|
521
|
+
},
|
|
522
|
+
metadata: {
|
|
523
|
+
findingId,
|
|
524
|
+
...deviceId !== void 0 ? { deviceId } : {}
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
await this.emitAlert(alert);
|
|
528
|
+
}
|
|
529
|
+
/** SystemLivenessRecovered — the invariant holds again; drop the alert. */
|
|
530
|
+
async handleLivenessRecovered(event) {
|
|
531
|
+
const findingId = String(event.data["findingId"] ?? "");
|
|
532
|
+
if (!findingId) return;
|
|
533
|
+
try {
|
|
534
|
+
await this.dismiss(findingId);
|
|
535
|
+
} catch (err) {
|
|
536
|
+
this.ctx.logger?.debug("LivenessRecovered: dismiss failed (likely already dismissed)", { meta: {
|
|
537
|
+
findingId,
|
|
538
|
+
error: require_dist.errMsg(err)
|
|
539
|
+
} });
|
|
540
|
+
}
|
|
541
|
+
}
|
|
483
542
|
buildMessage(category, data, sourceId) {
|
|
484
543
|
const addonId = data.addonId ?? sourceId;
|
|
485
544
|
const deviceId = data.deviceId;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Mt as EventCategory, at as errMsg, g as alertsCapability, n as AlertSchema, ot as BaseAddon, yt as createEvent } from "../../dist-
|
|
1
|
+
import { Mt as EventCategory, at as errMsg, g as alertsCapability, n as AlertSchema, ot as BaseAddon, yt as createEvent } from "../../dist-BL_FHWPP.mjs";
|
|
2
2
|
//#region src/builtins/alerts/prune-policy.ts
|
|
3
3
|
/**
|
|
4
4
|
* Ids older than `cutoffMs`, oldest first.
|
|
@@ -88,6 +88,10 @@ var CATEGORY_MAPPINGS = {
|
|
|
88
88
|
severity: "error",
|
|
89
89
|
titleTemplate: "Addon failed to load"
|
|
90
90
|
},
|
|
91
|
+
"system.liveness-failed": {
|
|
92
|
+
severity: "error",
|
|
93
|
+
titleTemplate: "Node liveness"
|
|
94
|
+
},
|
|
91
95
|
"addon.load-recovered": {
|
|
92
96
|
severity: "info",
|
|
93
97
|
titleTemplate: "Addon recovered"
|
|
@@ -284,6 +288,14 @@ var AlertCenterAddon = class extends BaseAddon {
|
|
|
284
288
|
await this.handleAddonLoadRecovered(event);
|
|
285
289
|
return;
|
|
286
290
|
}
|
|
291
|
+
if (category === EventCategory.SystemLivenessFailed) {
|
|
292
|
+
await this.handleLivenessFailed(event);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (category === EventCategory.SystemLivenessRecovered) {
|
|
296
|
+
await this.handleLivenessRecovered(event);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
287
299
|
const mapping = CATEGORY_MAPPINGS[category];
|
|
288
300
|
if (!mapping) return;
|
|
289
301
|
if (this.shouldSuppressByRate(category, event)) return;
|
|
@@ -475,6 +487,53 @@ var AlertCenterAddon = class extends BaseAddon {
|
|
|
475
487
|
} });
|
|
476
488
|
}
|
|
477
489
|
}
|
|
490
|
+
/**
|
|
491
|
+
* SystemLivenessFailed — a liveness invariant of this node is false.
|
|
492
|
+
*
|
|
493
|
+
* `findingId` is already stable across ticks (`liveness:no-devices`,
|
|
494
|
+
* `liveness:no-footage:<deviceId>`, …), so it IS the alert id: an ongoing
|
|
495
|
+
* fault updates one alert instead of producing one every five minutes.
|
|
496
|
+
*/
|
|
497
|
+
async handleLivenessFailed(event) {
|
|
498
|
+
const data = event.data;
|
|
499
|
+
const findingId = String(data["findingId"] ?? "");
|
|
500
|
+
if (!findingId) return;
|
|
501
|
+
const deviceId = typeof data["deviceId"] === "number" ? data["deviceId"] : void 0;
|
|
502
|
+
const severity = data["severity"] === "warning" ? "warning" : "error";
|
|
503
|
+
const alert = {
|
|
504
|
+
id: findingId,
|
|
505
|
+
category: EventCategory.SystemLivenessFailed,
|
|
506
|
+
severity,
|
|
507
|
+
title: String(data["title"] ?? "Node liveness"),
|
|
508
|
+
message: String(data["message"] ?? ""),
|
|
509
|
+
status: "active",
|
|
510
|
+
read: false,
|
|
511
|
+
createdAt: Date.now(),
|
|
512
|
+
updatedAt: Date.now(),
|
|
513
|
+
source: {
|
|
514
|
+
type: "liveness",
|
|
515
|
+
id: findingId
|
|
516
|
+
},
|
|
517
|
+
metadata: {
|
|
518
|
+
findingId,
|
|
519
|
+
...deviceId !== void 0 ? { deviceId } : {}
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
await this.emitAlert(alert);
|
|
523
|
+
}
|
|
524
|
+
/** SystemLivenessRecovered — the invariant holds again; drop the alert. */
|
|
525
|
+
async handleLivenessRecovered(event) {
|
|
526
|
+
const findingId = String(event.data["findingId"] ?? "");
|
|
527
|
+
if (!findingId) return;
|
|
528
|
+
try {
|
|
529
|
+
await this.dismiss(findingId);
|
|
530
|
+
} catch (err) {
|
|
531
|
+
this.ctx.logger?.debug("LivenessRecovered: dismiss failed (likely already dismissed)", { meta: {
|
|
532
|
+
findingId,
|
|
533
|
+
error: errMsg(err)
|
|
534
|
+
} });
|
|
535
|
+
}
|
|
536
|
+
}
|
|
478
537
|
buildMessage(category, data, sourceId) {
|
|
479
538
|
const addonId = data.addonId ?? sourceId;
|
|
480
539
|
const deviceId = data.deviceId;
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-CSs1A90r.js");
|
|
7
7
|
let node_fs = require("node:fs");
|
|
8
8
|
let node_fs$1 = require_chunk.__toESM(node_fs, 1);
|
|
9
9
|
node_fs = require_chunk.__toESM(node_fs);
|
|
@@ -4204,8 +4204,8 @@ function previewNextRuns(cron, count, after) {
|
|
|
4204
4204
|
}
|
|
4205
4205
|
//#endregion
|
|
4206
4206
|
//#region src/builtins/backup-orchestrator/destination-policy.ts
|
|
4207
|
-
var
|
|
4208
|
-
var
|
|
4207
|
+
var BACKUP_DESTINATION_POLICIES = "backup_destination_policies";
|
|
4208
|
+
var BACKUP_DESTINATION_POLICIES_COLUMNS = [
|
|
4209
4209
|
{
|
|
4210
4210
|
name: "location_id",
|
|
4211
4211
|
type: "TEXT",
|
|
@@ -4235,64 +4235,81 @@ var BACKUP_DESTINATION_POLICIES_SCHEMA = { columns: [
|
|
|
4235
4235
|
name: "last_run_at",
|
|
4236
4236
|
type: "INTEGER"
|
|
4237
4237
|
}
|
|
4238
|
-
]
|
|
4238
|
+
];
|
|
4239
4239
|
var BackupDestinationPolicyService = class {
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
constructor(
|
|
4243
|
-
this.
|
|
4240
|
+
store;
|
|
4241
|
+
declared = false;
|
|
4242
|
+
constructor(store) {
|
|
4243
|
+
this.store = store;
|
|
4244
4244
|
}
|
|
4245
4245
|
/**
|
|
4246
|
-
* Lazy `
|
|
4247
|
-
*
|
|
4248
|
-
*
|
|
4249
|
-
*
|
|
4250
|
-
* `initialize()` step that callers could forget.
|
|
4246
|
+
* Lazy `declareCollection` — called from every read/write path.
|
|
4247
|
+
* `declareCollection` is idempotent, so repeated calls collapse to a no-op
|
|
4248
|
+
* after the first. This keeps the constructor synchronous and avoids a
|
|
4249
|
+
* separate `initialize()` step that callers could forget.
|
|
4251
4250
|
*/
|
|
4252
4251
|
async initialize() {
|
|
4253
|
-
await this.
|
|
4252
|
+
await this.ensureDeclared();
|
|
4254
4253
|
}
|
|
4255
|
-
async
|
|
4256
|
-
if (this.
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4254
|
+
async ensureDeclared() {
|
|
4255
|
+
if (this.declared) return;
|
|
4256
|
+
await this.store.declareCollection({
|
|
4257
|
+
collection: BACKUP_DESTINATION_POLICIES,
|
|
4258
|
+
columns: BACKUP_DESTINATION_POLICIES_COLUMNS
|
|
4259
|
+
});
|
|
4260
|
+
this.declared = true;
|
|
4260
4261
|
}
|
|
4261
4262
|
async list() {
|
|
4262
|
-
await this.
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4263
|
+
await this.ensureDeclared();
|
|
4264
|
+
const rows = await this.store.query({
|
|
4265
|
+
collection: BACKUP_DESTINATION_POLICIES,
|
|
4266
|
+
filter: { orderBy: {
|
|
4267
|
+
field: "location_id",
|
|
4268
|
+
direction: "asc"
|
|
4269
|
+
} }
|
|
4270
|
+
});
|
|
4268
4271
|
const out = [];
|
|
4269
4272
|
for (const row of rows) {
|
|
4270
|
-
const mapped = mapRowToPolicy(row);
|
|
4273
|
+
const mapped = mapRowToPolicy(row.data);
|
|
4271
4274
|
if (mapped) out.push(mapped);
|
|
4272
4275
|
}
|
|
4273
4276
|
return out;
|
|
4274
4277
|
}
|
|
4275
4278
|
async get(locationId) {
|
|
4276
|
-
await this.
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4279
|
+
await this.ensureDeclared();
|
|
4280
|
+
const rows = await this.store.query({
|
|
4281
|
+
collection: BACKUP_DESTINATION_POLICIES,
|
|
4282
|
+
filter: {
|
|
4283
|
+
where: { location_id: locationId },
|
|
4284
|
+
limit: 1
|
|
4285
|
+
}
|
|
4286
|
+
});
|
|
4287
|
+
return rows[0] ? mapRowToPolicy(rows[0].data) : null;
|
|
4280
4288
|
}
|
|
4281
4289
|
/**
|
|
4282
|
-
* Replace-or-insert. Implemented as
|
|
4283
|
-
* `SqliteLocationStore` contract
|
|
4284
|
-
* `tableUpdate` still work.
|
|
4290
|
+
* Replace-or-insert. Implemented as delete + insert, mirroring the
|
|
4291
|
+
* `SqliteLocationStore` contract.
|
|
4285
4292
|
*/
|
|
4286
4293
|
async upsert(p) {
|
|
4287
|
-
await this.
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4294
|
+
await this.ensureDeclared();
|
|
4295
|
+
await this.store.deleteWhere({
|
|
4296
|
+
collection: BACKUP_DESTINATION_POLICIES,
|
|
4297
|
+
filter: { where: { location_id: p.locationId } }
|
|
4298
|
+
});
|
|
4299
|
+
await this.store.insert({
|
|
4300
|
+
collection: BACKUP_DESTINATION_POLICIES,
|
|
4301
|
+
record: {
|
|
4302
|
+
id: p.locationId,
|
|
4303
|
+
data: mapPolicyToRow(p)
|
|
4304
|
+
}
|
|
4305
|
+
});
|
|
4291
4306
|
}
|
|
4292
4307
|
async delete(locationId) {
|
|
4293
|
-
await this.
|
|
4294
|
-
|
|
4295
|
-
|
|
4308
|
+
await this.ensureDeclared();
|
|
4309
|
+
await this.store.deleteWhere({
|
|
4310
|
+
collection: BACKUP_DESTINATION_POLICIES,
|
|
4311
|
+
filter: { where: { location_id: locationId } }
|
|
4312
|
+
});
|
|
4296
4313
|
}
|
|
4297
4314
|
/**
|
|
4298
4315
|
* Auto-create a default policy for a `backups` location seen for the
|
|
@@ -4573,8 +4590,8 @@ var LocationManifestLock = class {
|
|
|
4573
4590
|
};
|
|
4574
4591
|
//#endregion
|
|
4575
4592
|
//#region src/builtins/backup-orchestrator/schedule-store.ts
|
|
4576
|
-
var
|
|
4577
|
-
var
|
|
4593
|
+
var BACKUP_SCHEDULES = "backup_schedules";
|
|
4594
|
+
var BACKUP_SCHEDULES_COLUMNS = [
|
|
4578
4595
|
{
|
|
4579
4596
|
name: "id",
|
|
4580
4597
|
type: "TEXT",
|
|
@@ -4600,7 +4617,7 @@ var BACKUP_SCHEDULES_SCHEMA = { columns: [
|
|
|
4600
4617
|
},
|
|
4601
4618
|
{
|
|
4602
4619
|
name: "location_ids",
|
|
4603
|
-
type: "
|
|
4620
|
+
type: "JSON",
|
|
4604
4621
|
notNull: true,
|
|
4605
4622
|
defaultValue: "[]"
|
|
4606
4623
|
},
|
|
@@ -4612,59 +4629,78 @@ var BACKUP_SCHEDULES_SCHEMA = { columns: [
|
|
|
4612
4629
|
},
|
|
4613
4630
|
{
|
|
4614
4631
|
name: "data_sources",
|
|
4615
|
-
type: "
|
|
4632
|
+
type: "JSON"
|
|
4616
4633
|
},
|
|
4617
4634
|
{
|
|
4618
4635
|
name: "last_run_at",
|
|
4619
4636
|
type: "INTEGER"
|
|
4620
4637
|
}
|
|
4621
|
-
]
|
|
4638
|
+
];
|
|
4622
4639
|
var BackupScheduleService = class {
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
constructor(
|
|
4626
|
-
this.
|
|
4640
|
+
store;
|
|
4641
|
+
declared = false;
|
|
4642
|
+
constructor(store) {
|
|
4643
|
+
this.store = store;
|
|
4627
4644
|
}
|
|
4628
4645
|
async initialize() {
|
|
4629
|
-
await this.
|
|
4646
|
+
await this.ensureDeclared();
|
|
4630
4647
|
}
|
|
4631
|
-
async
|
|
4632
|
-
if (this.
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4648
|
+
async ensureDeclared() {
|
|
4649
|
+
if (this.declared) return;
|
|
4650
|
+
await this.store.declareCollection({
|
|
4651
|
+
collection: BACKUP_SCHEDULES,
|
|
4652
|
+
columns: BACKUP_SCHEDULES_COLUMNS
|
|
4653
|
+
});
|
|
4654
|
+
this.declared = true;
|
|
4636
4655
|
}
|
|
4637
4656
|
async list() {
|
|
4638
|
-
await this.
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4657
|
+
await this.ensureDeclared();
|
|
4658
|
+
const rows = await this.store.query({
|
|
4659
|
+
collection: BACKUP_SCHEDULES,
|
|
4660
|
+
filter: { orderBy: {
|
|
4661
|
+
field: "id",
|
|
4662
|
+
direction: "asc"
|
|
4663
|
+
} }
|
|
4664
|
+
});
|
|
4644
4665
|
const out = [];
|
|
4645
4666
|
for (const row of rows) {
|
|
4646
|
-
const mapped = mapRowToSchedule(row);
|
|
4667
|
+
const mapped = mapRowToSchedule(row.data);
|
|
4647
4668
|
if (mapped) out.push(mapped);
|
|
4648
4669
|
}
|
|
4649
4670
|
return out;
|
|
4650
4671
|
}
|
|
4651
4672
|
async get(id) {
|
|
4652
|
-
await this.
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4673
|
+
await this.ensureDeclared();
|
|
4674
|
+
const rows = await this.store.query({
|
|
4675
|
+
collection: BACKUP_SCHEDULES,
|
|
4676
|
+
filter: {
|
|
4677
|
+
where: { id },
|
|
4678
|
+
limit: 1
|
|
4679
|
+
}
|
|
4680
|
+
});
|
|
4681
|
+
return rows[0] ? mapRowToSchedule(rows[0].data) : null;
|
|
4656
4682
|
}
|
|
4657
4683
|
/** Replace-or-insert (delete + insert — mirrors the policy store). */
|
|
4658
4684
|
async upsert(s) {
|
|
4659
|
-
await this.
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4685
|
+
await this.ensureDeclared();
|
|
4686
|
+
await this.store.deleteWhere({
|
|
4687
|
+
collection: BACKUP_SCHEDULES,
|
|
4688
|
+
filter: { where: { id: s.id } }
|
|
4689
|
+
});
|
|
4690
|
+
await this.store.insert({
|
|
4691
|
+
collection: BACKUP_SCHEDULES,
|
|
4692
|
+
record: {
|
|
4693
|
+
id: s.id,
|
|
4694
|
+
data: mapScheduleToRow(s)
|
|
4695
|
+
}
|
|
4696
|
+
});
|
|
4663
4697
|
}
|
|
4664
4698
|
async delete(id) {
|
|
4665
|
-
await this.
|
|
4666
|
-
|
|
4667
|
-
|
|
4699
|
+
await this.ensureDeclared();
|
|
4700
|
+
await this.store.deleteWhere({
|
|
4701
|
+
collection: BACKUP_SCHEDULES,
|
|
4702
|
+
filter: { where: { id } }
|
|
4703
|
+
});
|
|
4668
4704
|
}
|
|
4669
4705
|
};
|
|
4670
4706
|
function mapScheduleToRow(s) {
|
|
@@ -4673,27 +4709,36 @@ function mapScheduleToRow(s) {
|
|
|
4673
4709
|
label: s.label,
|
|
4674
4710
|
cron: s.cron,
|
|
4675
4711
|
enabled: s.enabled ? 1 : 0,
|
|
4676
|
-
location_ids:
|
|
4712
|
+
location_ids: [...s.locationIds],
|
|
4677
4713
|
retention_count: s.retentionCount,
|
|
4678
|
-
data_sources: s.dataSources ?
|
|
4714
|
+
data_sources: s.dataSources ? [...s.dataSources] : null,
|
|
4679
4715
|
last_run_at: s.lastRunAt ?? null
|
|
4680
4716
|
};
|
|
4681
4717
|
}
|
|
4718
|
+
/**
|
|
4719
|
+
* `location_ids` / `data_sources` are `JSON` columns, so the surface hands
|
|
4720
|
+
* back real arrays. A STRING still arrives for rows an older build wrote and
|
|
4721
|
+
* nothing has rewritten since — a schedule whose fan-out set silently read as
|
|
4722
|
+
* empty would back up to nowhere, so both shapes are accepted.
|
|
4723
|
+
*/
|
|
4682
4724
|
function parseStringArray(raw) {
|
|
4683
|
-
|
|
4725
|
+
const value = typeof raw === "string" ? tryParseJson(raw) : raw;
|
|
4726
|
+
if (!Array.isArray(value)) return [];
|
|
4727
|
+
return value.filter((v) => typeof v === "string");
|
|
4728
|
+
}
|
|
4729
|
+
function tryParseJson(raw) {
|
|
4730
|
+
if (raw.length === 0) return null;
|
|
4684
4731
|
try {
|
|
4685
|
-
|
|
4686
|
-
if (!Array.isArray(parsed)) return [];
|
|
4687
|
-
return parsed.filter((v) => typeof v === "string");
|
|
4732
|
+
return JSON.parse(raw);
|
|
4688
4733
|
} catch {
|
|
4689
|
-
return
|
|
4734
|
+
return null;
|
|
4690
4735
|
}
|
|
4691
4736
|
}
|
|
4692
4737
|
function mapRowToSchedule(row) {
|
|
4693
4738
|
const id = String(row["id"] ?? "");
|
|
4694
4739
|
if (!id) return null;
|
|
4695
4740
|
const dataSourcesRaw = row["data_sources"];
|
|
4696
|
-
const dataSources =
|
|
4741
|
+
const dataSources = dataSourcesRaw === null || dataSourcesRaw === void 0 ? void 0 : parseStringArray(dataSourcesRaw);
|
|
4697
4742
|
const lastRunRaw = row["last_run_at"];
|
|
4698
4743
|
const lastRunAt = typeof lastRunRaw === "number" && lastRunRaw > 0 ? lastRunRaw : void 0;
|
|
4699
4744
|
return {
|
|
@@ -5451,24 +5496,22 @@ var BackupOrchestratorAddon = class extends require_dist.BaseAddon {
|
|
|
5451
5496
|
resolveScheduleService() {
|
|
5452
5497
|
const reg = this.ctx.kernel.capabilityRegistry;
|
|
5453
5498
|
if (!reg) return null;
|
|
5454
|
-
const
|
|
5455
|
-
if (!
|
|
5456
|
-
|
|
5457
|
-
|
|
5499
|
+
const store = reg.getSingleton("settings-store");
|
|
5500
|
+
if (!store) {
|
|
5501
|
+
this.ctx.logger.warn("backup-orchestrator: no settings-store provider — backup schedules will not persist");
|
|
5502
|
+
return null;
|
|
5503
|
+
}
|
|
5504
|
+
return new BackupScheduleService(store);
|
|
5458
5505
|
}
|
|
5459
5506
|
resolvePolicyService() {
|
|
5460
5507
|
const reg = this.ctx.kernel.capabilityRegistry;
|
|
5461
5508
|
if (!reg) return null;
|
|
5462
|
-
const
|
|
5463
|
-
if (!
|
|
5509
|
+
const store = reg.getSingleton("settings-store");
|
|
5510
|
+
if (!store) {
|
|
5464
5511
|
this.ctx.logger.warn("backup-orchestrator: no settings-store provider — destination policies will not persist");
|
|
5465
5512
|
return null;
|
|
5466
5513
|
}
|
|
5467
|
-
|
|
5468
|
-
this.ctx.logger.warn("backup-orchestrator: settings backend lacks structured-table support — destination policies will not persist");
|
|
5469
|
-
return null;
|
|
5470
|
-
}
|
|
5471
|
-
return new BackupDestinationPolicyService(backend);
|
|
5514
|
+
return new BackupDestinationPolicyService(store);
|
|
5472
5515
|
}
|
|
5473
5516
|
/**
|
|
5474
5517
|
* Narrow `ctx.api.storage` to the subset the manifest helpers need.
|