@camstack/system 1.2.328 → 1.2.329
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.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/autotrack/index.js +1 -1
- package/dist/builtins/autotrack/index.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +7 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +294 -79
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +294 -79
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/composer/composer.addon.js +2 -2
- package/dist/builtins/composer/composer.addon.mjs +2 -2
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
- package/dist/builtins/device-manager/device-manager.addon.js +2 -2
- package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
- 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/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- 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/sqlite-settings.addon.d.ts +4 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
- package/dist/builtins/sqlite-storage/sqlite-snapshot-protocol.d.ts +49 -0
- package/dist/builtins/sqlite-storage/sqlite-snapshot-worker.d.ts +33 -0
- package/dist/builtins/sqlite-storage/sqlite-snapshotter.d.ts +98 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-backup/system-backup.service.d.ts +74 -20
- 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/{composition-sources-GkgXF6B9.js → composition-sources-B7hfTiPS.js} +1 -1
- package/dist/{composition-sources-I8Rx7woY.mjs → composition-sources-BHPqf6So.mjs} +1 -1
- package/dist/{dist-BUejKKBm.js → dist-CSs0cFDN.js} +496 -337
- package/dist/{dist-DWq17vC8.mjs → dist-CV7IqaYq.mjs} +467 -338
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{retired-settings-keys-DBPEzGop.js → retired-settings-keys-CGQnAoRx.js} +1 -1
- package/dist/{retired-settings-keys-BfHclEyd.mjs → retired-settings-keys-DSUs7U6l.mjs} +1 -1
- package/dist/sqlite-snapshot-protocol-2QaTouWV.mjs +34 -0
- package/dist/sqlite-snapshot-protocol-B9OndqZv.js +51 -0
- package/dist/sqlite-snapshot-worker.js +185 -0
- package/dist/sqlite-snapshot-worker.mjs +179 -0
- package/package.json +5 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as __require, o as __toESM, t as __commonJSMin } from "../../chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { B as UserRecordSchema, En as userManagementCapability, F as ScopedTokenSchema, G as authProviderCapability, Zn as BaseAddon, r as ApiKeyRecordSchema } from "../../dist-CV7IqaYq.mjs";
|
|
3
3
|
import * as crypto$2 from "node:crypto";
|
|
4
4
|
import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
|
|
5
5
|
import nodeCrypto from "crypto";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("../../dist-
|
|
3
|
+
const require_dist = require("../../dist-CSs0cFDN.js");
|
|
4
4
|
const require_tls = require("../../tls-D_wUeOTD.js");
|
|
5
5
|
let node_fs_promises = require("node:fs/promises");
|
|
6
6
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Sr as EventCategory, Ut as localNetworkCapability, Zn as BaseAddon } from "../../dist-CV7IqaYq.mjs";
|
|
2
2
|
import { S as readLanHttpState, _ as DEFAULT_LAN_HTTP_PORT, a as writeTlsMode, i as writeExtraSans, l as reissueTlsLeaf, n as readTlsAccessStatus, o as validateUploadedTls, r as readTlsMode, s as ensureTlsCert, t as readExtraSans, y as applyLanHttp } from "../../tls-IM-v7JV4.mjs";
|
|
3
3
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
4
|
import { join } from "node:path";
|
|
@@ -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-CSs0cFDN.js");
|
|
7
7
|
//#region src/builtins/loki-logging/loki-payload.ts
|
|
8
8
|
/**
|
|
9
9
|
* Loki rejects a label name that is not a valid Prometheus label
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Gt as logDestinationCapability, Zn as BaseAddon } from "../../dist-CV7IqaYq.mjs";
|
|
2
2
|
//#region src/builtins/loki-logging/loki-payload.ts
|
|
3
3
|
/**
|
|
4
4
|
* Loki rejects a label name that is not a valid Prometheus label
|
|
@@ -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-CSs0cFDN.js");
|
|
7
7
|
const require_proc_stat = require("../../proc-stat-DL-WUOhl.js");
|
|
8
8
|
let node_fs_promises = require("node:fs/promises");
|
|
9
9
|
let node_fs = require("node:fs");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { At as foldSnapshotByFunction, Sr as EventCategory, Xn as errMsg, Zn as BaseAddon, Zt as metricsProviderCapability, cn as reducePoints, sr as createEvent, un as resolveBucketMs } from "../../dist-CV7IqaYq.mjs";
|
|
2
2
|
import { a as parseProcStat, i as nodeProcReader, n as elapsedSecSince, o as parseProcStatusRss, r as lifetimeCpuPercent, t as commandFromCmdline } from "../../proc-stat-CbC55Kqi.mjs";
|
|
3
3
|
import { access, readFile, readdir } from "node:fs/promises";
|
|
4
4
|
import * as fs from "node:fs";
|
|
@@ -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-CSs0cFDN.js");
|
|
7
7
|
let node_fs = require("node:fs");
|
|
8
8
|
node_fs = require_chunk.__toESM(node_fs);
|
|
9
9
|
let node_child_process = require("node:child_process");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { o as __toESM } from "../../chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { Sr as EventCategory, St as enumerateInferenceDevices, Xn as errMsg, Zn as BaseAddon, an as platformProbeCapability, gn as scoreRuntimes, lr as emitReadiness } from "../../dist-CV7IqaYq.mjs";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import { execFile } from "node:child_process";
|
|
5
5
|
import * as os from "node:os";
|
|
@@ -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-CSs0cFDN.js");
|
|
7
7
|
//#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
|
|
8
8
|
/**
|
|
9
9
|
* Reconcile the durable `enabledProviders` set against authoritative
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Sr as EventCategory, Zn as BaseAddon } from "../../dist-CV7IqaYq.mjs";
|
|
2
2
|
//#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
|
|
3
3
|
/**
|
|
4
4
|
* Reconcile the durable `enabledProviders` set against authoritative
|
|
@@ -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-CSs0cFDN.js");
|
|
7
7
|
const require_snapshot_courtesy = require("../../snapshot-courtesy-Cqs7GkOV.js");
|
|
8
8
|
let zod = require("zod");
|
|
9
9
|
let node_crypto = require("node:crypto");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { J as batteryCapability, Sr as EventCategory, Tn as streamQualityLabel, Xn as errMsg, Xt as memoizePinnedFfmpeg, Yn as DeviceType, Zn as BaseAddon, a as BatteryStatusSchema, mr as nodePin, mt as deriveBatteryPresence, q as bareAddonId, qn as DeviceFeature, yn as snapshotCapability } from "../../dist-CV7IqaYq.mjs";
|
|
2
2
|
import { i as renderCourtesyOverlayJpeg, n as courtesyCacheKey, r as renderCourtesyJpeg } from "../../snapshot-courtesy-CZPvteq2.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
@@ -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-CSs0cFDN.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
let node_fs_promises = require("node:fs/promises");
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cn as storageProviderCapability, Zn as BaseAddon, kt as filesystemBrowseCapability } from "../../dist-CV7IqaYq.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { mkdir, readdir, realpath, statfs } from "node:fs/promises";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -11,6 +11,10 @@ import { SqliteVecVectorIndex } from './vector-index-vec.js';
|
|
|
11
11
|
* engine only through the door — which is the point, because it is what
|
|
12
12
|
* makes the engine replaceable.
|
|
13
13
|
*
|
|
14
|
+
* It also serves `database-snapshot` (singleton, internal): the verified copy
|
|
15
|
+
* of its database that the nightly backup archives in place of the live files
|
|
16
|
+
* (D693).
|
|
17
|
+
*
|
|
14
18
|
* It ALSO serves `vector-store` (singleton, internal), from the same database
|
|
15
19
|
* file and the same open handle. That capability first shipped as its own addon
|
|
16
20
|
* and the separation cost two round trips per write — caller → door → engine —
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { DatabaseSnapshotTable } from '@camstack/types';
|
|
2
|
+
/** `workerData` of one snapshot thread. The `kind` tells it apart from any other worker. */
|
|
3
|
+
export interface SnapshotWorkerData {
|
|
4
|
+
readonly kind: 'sqlite-snapshot';
|
|
5
|
+
/** The live database — opened read-only, through this thread's own connection. */
|
|
6
|
+
readonly livePath: string;
|
|
7
|
+
/** Where the copy is written. Lives in a work directory nothing else uses. */
|
|
8
|
+
readonly copyPath: string;
|
|
9
|
+
/** Pages per backup step. Every step reads the same pinned transaction. */
|
|
10
|
+
readonly pagesPerStep: number;
|
|
11
|
+
}
|
|
12
|
+
/** What a copy that passed every check holds. */
|
|
13
|
+
export interface VerifiedCopy {
|
|
14
|
+
readonly takenAt: number;
|
|
15
|
+
readonly tables: readonly DatabaseSnapshotTable[];
|
|
16
|
+
readonly pageCount: number;
|
|
17
|
+
readonly pageSize: number;
|
|
18
|
+
readonly copyMs: number;
|
|
19
|
+
readonly verifyMs: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Why a copy was refused:
|
|
23
|
+
* - `integrity` — `PRAGMA integrity_check` on the copy answered anything but `ok`;
|
|
24
|
+
* - `row-count` — a table of the copy holds a different number of rows than the
|
|
25
|
+
* pinned source did, or the table sets differ;
|
|
26
|
+
* - `failed` — the copy could not be taken at all (open, I/O, busy, deadline);
|
|
27
|
+
* - `no-space` — the live database's disk cannot take the copy and keep its
|
|
28
|
+
* reserve, or its free space could not be measured (decided before the
|
|
29
|
+
* thread starts, by the snapshotter).
|
|
30
|
+
*/
|
|
31
|
+
export type SnapshotRefusalReason = 'integrity' | 'row-count' | 'failed' | 'no-space';
|
|
32
|
+
export interface SnapshotDone {
|
|
33
|
+
readonly kind: 'done';
|
|
34
|
+
readonly copy: VerifiedCopy;
|
|
35
|
+
}
|
|
36
|
+
export interface SnapshotRefused {
|
|
37
|
+
readonly kind: 'refused';
|
|
38
|
+
readonly reason: SnapshotRefusalReason;
|
|
39
|
+
readonly detail: string;
|
|
40
|
+
}
|
|
41
|
+
export type SnapshotWorkerMessage = SnapshotDone | SnapshotRefused;
|
|
42
|
+
/** Thrown inside the worker by a check that refuses the copy. */
|
|
43
|
+
export declare class SnapshotRefusedError extends Error {
|
|
44
|
+
readonly reason: SnapshotRefusalReason;
|
|
45
|
+
readonly detail: string;
|
|
46
|
+
constructor(reason: SnapshotRefusalReason, detail: string);
|
|
47
|
+
}
|
|
48
|
+
export declare function isSnapshotWorkerData(value: unknown): value is SnapshotWorkerData;
|
|
49
|
+
export declare function isSnapshotWorkerMessage(value: unknown): value is SnapshotWorkerMessage;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { DatabaseSnapshotTable } from '@camstack/types';
|
|
2
|
+
import { default as Database } from 'better-sqlite3';
|
|
3
|
+
import { SnapshotWorkerData, VerifiedCopy } from './sqlite-snapshot-protocol.js';
|
|
4
|
+
/** The pinned half: when it was taken, what it holds, how long it took. */
|
|
5
|
+
export interface PinnedCopy {
|
|
6
|
+
readonly takenAt: number;
|
|
7
|
+
readonly tables: readonly DatabaseSnapshotTable[];
|
|
8
|
+
readonly copyMs: number;
|
|
9
|
+
}
|
|
10
|
+
/** The checked half. */
|
|
11
|
+
export interface CopyCheck {
|
|
12
|
+
readonly pageCount: number;
|
|
13
|
+
readonly pageSize: number;
|
|
14
|
+
readonly verifyMs: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Copy `source` into `copyPath` from ONE read transaction. `onStep` observes
|
|
18
|
+
* each backup step (a spec interleaves writes there).
|
|
19
|
+
*/
|
|
20
|
+
export declare function copyPinned(source: Database.Database, copyPath: string, pagesPerStep: number, onStep?: () => void): Promise<PinnedCopy>;
|
|
21
|
+
/**
|
|
22
|
+
* The answer of `PRAGMA journal_mode = DELETE` must be `delete`. SQLite answers
|
|
23
|
+
* the mode it is IN, so a switch it could not make comes back as `wal` with no
|
|
24
|
+
* error — and a copy left in WAL needs sidecars that will not travel with it.
|
|
25
|
+
*/
|
|
26
|
+
export declare function requireRollbackJournal(answer: unknown): void;
|
|
27
|
+
/**
|
|
28
|
+
* Check a copy against what the pinned source held. Makes the copy one
|
|
29
|
+
* self-contained file first. Throws {@link SnapshotRefusedError}.
|
|
30
|
+
*/
|
|
31
|
+
export declare function verifyCopy(copyPath: string, expected: readonly DatabaseSnapshotTable[]): CopyCheck;
|
|
32
|
+
/** The whole job: open the live database read-only, copy it pinned, check the copy. */
|
|
33
|
+
export declare function takeVerifiedCopy(data: SnapshotWorkerData): Promise<VerifiedCopy>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { DatabaseSnapshotResult, IScopedLogger } from '@camstack/types';
|
|
2
|
+
import { SnapshotWorkerData } from './sqlite-snapshot-protocol.js';
|
|
3
|
+
/**
|
|
4
|
+
* Pages per backup step. Every step reads the same pinned transaction, so the
|
|
5
|
+
* size only trades yields against per-step overhead: 1024 pages is 4 MiB at the
|
|
6
|
+
* default page size.
|
|
7
|
+
*/
|
|
8
|
+
export declare const SNAPSHOT_PAGES_PER_STEP = 1024;
|
|
9
|
+
/**
|
|
10
|
+
* How long the snapshot thread may run before it is terminated. A minute under
|
|
11
|
+
* the capability's own timeout, so the runner gives up — and says why — before
|
|
12
|
+
* the caller's call does.
|
|
13
|
+
*/
|
|
14
|
+
export declare const SNAPSHOT_DEADLINE_MS: number;
|
|
15
|
+
/** The least headroom left on the disk AFTER the copy, whatever the database's size. */
|
|
16
|
+
export declare const SNAPSHOT_MIN_RESERVE_BYTES: number;
|
|
17
|
+
/**
|
|
18
|
+
* Free bytes a snapshot needs before it may start: the copy (at most the
|
|
19
|
+
* database plus its WAL), then a reserve the size of the database (at least
|
|
20
|
+
* {@link SNAPSHOT_MIN_RESERVE_BYTES}) for the live writes and the WAL growth
|
|
21
|
+
* the pinned read causes while the copy runs.
|
|
22
|
+
*/
|
|
23
|
+
export declare function snapshotSpaceNeeded(databaseBytes: number, walBytes: number): number;
|
|
24
|
+
/** The `statfs` fields the space check reads. */
|
|
25
|
+
export interface DiskSpace {
|
|
26
|
+
readonly bavail: number | bigint;
|
|
27
|
+
readonly bsize: number | bigint;
|
|
28
|
+
}
|
|
29
|
+
export type StatfsFn = (dir: string) => Promise<DiskSpace>;
|
|
30
|
+
/**
|
|
31
|
+
* Where the built worker entry lives: `dist/sqlite-snapshot-worker.js` at the
|
|
32
|
+
* package root, next to `wal-checkpoint-worker.js` (see `wal-checkpointer.ts`
|
|
33
|
+
* for why it resolves through the package's own `package.json`).
|
|
34
|
+
*/
|
|
35
|
+
export declare function defaultSnapshotWorkerPath(): string;
|
|
36
|
+
/**
|
|
37
|
+
* The members of a snapshot thread this class uses. Structural, so a spec can
|
|
38
|
+
* hand in a thread whose `terminate()` never settles — the stall a native call
|
|
39
|
+
* that never returns would cause.
|
|
40
|
+
*/
|
|
41
|
+
export interface SnapshotWorkerHandle {
|
|
42
|
+
onMessage(listener: (message: unknown) => void): void;
|
|
43
|
+
onError(listener: (err: Error) => void): void;
|
|
44
|
+
onExit(listener: (code: number) => void): void;
|
|
45
|
+
terminate(): Promise<unknown>;
|
|
46
|
+
}
|
|
47
|
+
export type SnapshotWorkerFactory = (data: SnapshotWorkerData) => SnapshotWorkerHandle;
|
|
48
|
+
export interface SqliteSnapshotterOptions {
|
|
49
|
+
/** The live database this process owns. */
|
|
50
|
+
readonly livePath: string;
|
|
51
|
+
readonly logger: IScopedLogger;
|
|
52
|
+
readonly pagesPerStep?: number;
|
|
53
|
+
/** Overrides the built entry — a spec points this at the TypeScript source. */
|
|
54
|
+
readonly workerPath?: string;
|
|
55
|
+
/** Extra `execArgv` for the thread — a spec passes a loader here. */
|
|
56
|
+
readonly workerExecArgv?: readonly string[];
|
|
57
|
+
/** Overrides {@link SNAPSHOT_DEADLINE_MS}. */
|
|
58
|
+
readonly deadlineMs?: number;
|
|
59
|
+
/** Overrides `fs.statfs` — a spec answers the space question here. */
|
|
60
|
+
readonly statfs?: StatfsFn;
|
|
61
|
+
/** Overrides the thread itself — a spec hands in one that never terminates. */
|
|
62
|
+
readonly spawnWorker?: SnapshotWorkerFactory;
|
|
63
|
+
/** Overrides the directory fsync — a spec makes it fail. */
|
|
64
|
+
readonly syncDirectory?: (dir: string) => Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
export declare class SqliteSnapshotter {
|
|
67
|
+
private readonly livePath;
|
|
68
|
+
private readonly logger;
|
|
69
|
+
private readonly pagesPerStep;
|
|
70
|
+
private readonly deadlineMs;
|
|
71
|
+
private readonly statfs;
|
|
72
|
+
private readonly spawnWorker;
|
|
73
|
+
private readonly syncDirectory;
|
|
74
|
+
private inFlight;
|
|
75
|
+
/**
|
|
76
|
+
* Set while a thread the deadline gave up on is still being terminated. A
|
|
77
|
+
* native SQLite call cannot be interrupted, so `terminate()` may take as long
|
|
78
|
+
* as that call — or never settle. Until it does, a new snapshot is refused
|
|
79
|
+
* at once (never joined, never started beside a thread that may still hold
|
|
80
|
+
* a pinned read), and the work directory stays until nobody writes into it.
|
|
81
|
+
*/
|
|
82
|
+
private draining;
|
|
83
|
+
constructor(options: SqliteSnapshotterOptions);
|
|
84
|
+
/** The database this snapshotter copies, absolute. */
|
|
85
|
+
get database(): string;
|
|
86
|
+
/** Write `<db>.backup-snapshot`. Joins a snapshot already running. */
|
|
87
|
+
write(): Promise<DatabaseSnapshotResult>;
|
|
88
|
+
/**
|
|
89
|
+
* Remove a snapshot nobody collected and a work directory a crash left.
|
|
90
|
+
* Called at boot; {@link write} does the same before it starts.
|
|
91
|
+
*/
|
|
92
|
+
sweep(): Promise<void>;
|
|
93
|
+
private refuse;
|
|
94
|
+
/** Refuses with `no-space` unless the disk can take the copy and keep its reserve. */
|
|
95
|
+
private checkSpace;
|
|
96
|
+
private run;
|
|
97
|
+
private runWorker;
|
|
98
|
+
}
|
|
@@ -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-CSs0cFDN.js");
|
|
7
7
|
const require_hub_cap_forward = require("../../hub-cap-forward-DmHNjbB0.js");
|
|
8
8
|
let zod = require("zod");
|
|
9
9
|
let node_crypto = require("node:crypto");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $ as collectSecretConfigKeys, A as REDACTED_SECRET, Et as evictionPolicyOfLocation, Ft as isLocationEnabled, I as StorageCleanupJobSchema, Jt as mayReadLocation, L as StorageLocationModeSchema, Mt as gbToBytes, Qt as modeMayWrite, R as StorageLocationTypeSchema, Sr as EventCategory, Vt as legacyModeOf, Yt as mayWriteToLocation, Zn as BaseAddon, _n as settingsStoreCapability, bn as storageCapability, dn as resolveLocationMode, hr as parseJsonObject, jn as withLocationMode, w as LegacyStorageLocationDefaultSchema, xn as storageMigrationCapability, z as StorageMigrationJobSchema } from "../../dist-CV7IqaYq.mjs";
|
|
2
2
|
import { t as HUB_CAP_FWD_ACTION } from "../../hub-cap-forward-BdT320dq.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IScopedLogger } from '@camstack/types';
|
|
1
|
+
import { ArchiveSqliteSnapshot, DatabaseSnapshotResult, IScopedLogger } from '@camstack/types';
|
|
2
2
|
/**
|
|
3
3
|
* Thrown when an archive build (or a backup run driving one) is
|
|
4
4
|
* stopped via its `AbortSignal`. Callers use `instanceof` to tell a
|
|
@@ -8,6 +8,15 @@ import { IScopedLogger } from '@camstack/types';
|
|
|
8
8
|
export declare class BackupCancelledError extends Error {
|
|
9
9
|
constructor(message?: string);
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Thrown when an archive would carry a live database and its owner could not
|
|
13
|
+
* produce a verified snapshot of it (D693). Nothing was built: a run that
|
|
14
|
+
* "succeeded" without the database — or with a torn copy of it — would push
|
|
15
|
+
* the oldest good archive out of every destination's retention.
|
|
16
|
+
*/
|
|
17
|
+
export declare class BackupSnapshotRefusedError extends Error {
|
|
18
|
+
constructor(reason: string);
|
|
19
|
+
}
|
|
11
20
|
/**
|
|
12
21
|
* Default set of paths considered part of a "system backup". Includes
|
|
13
22
|
* everything that isn't pure backend code — config, sqlite, addons
|
|
@@ -42,6 +51,16 @@ export declare const DEFAULT_BACKUP_EXCLUDES: readonly ["addons-data/backup-orch
|
|
|
42
51
|
* trailing `/`) and backslash separators.
|
|
43
52
|
*/
|
|
44
53
|
export declare function isExcludedFromBackup(relPath: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* The OWNER of the live databases in a data root (D693): it says which files
|
|
56
|
+
* it snapshots, and writes the snapshot. `backup-orchestrator` answers it with
|
|
57
|
+
* the `database-snapshot` capability, pinned to its own node.
|
|
58
|
+
*/
|
|
59
|
+
export interface DatabaseOwner {
|
|
60
|
+
/** Absolute paths of the databases the owner snapshots. */
|
|
61
|
+
listDatabases(): Promise<readonly string[]>;
|
|
62
|
+
writeSnapshot(): Promise<DatabaseSnapshotResult>;
|
|
63
|
+
}
|
|
45
64
|
/** Path of the manifest file embedded inside every archive. */
|
|
46
65
|
export declare const ARCHIVE_MANIFEST_NAME = ".camstack-backup-manifest.json";
|
|
47
66
|
export type ArchiveEntryKind = 'file' | 'dir' | 'symlink';
|
|
@@ -69,6 +88,11 @@ export interface ArchiveManifest {
|
|
|
69
88
|
/** Sum of file `sizeBytes` (uncompressed). */
|
|
70
89
|
totalBytes: number;
|
|
71
90
|
totalFiles: number;
|
|
91
|
+
/**
|
|
92
|
+
* Live databases carried as their owner's verified snapshot instead of as
|
|
93
|
+
* files (D693). Paths are archive-relative.
|
|
94
|
+
*/
|
|
95
|
+
sqliteSnapshots?: ArchiveSqliteSnapshot[];
|
|
72
96
|
}
|
|
73
97
|
export interface CreateArchiveResult {
|
|
74
98
|
archivePath: string;
|
|
@@ -159,33 +183,37 @@ export declare class SystemBackupService {
|
|
|
159
183
|
locations?: readonly string[];
|
|
160
184
|
signal?: AbortSignal;
|
|
161
185
|
onArchiveBytes?: (bytesWritten: number) => void;
|
|
186
|
+
/**
|
|
187
|
+
* The OWNER of the data root's live databases (D693). Asked only when the
|
|
188
|
+
* walk finds a SQLite file: which databases it owns (authoritative — a
|
|
189
|
+
* cleanly closed database has no sidecar and is just as owned), then for
|
|
190
|
+
* one verified snapshot. Each owned database in scope is archived as that
|
|
191
|
+
* snapshot in place of its `.db` / `-wal` / `-shm` / `-journal`, and the
|
|
192
|
+
* snapshot is deleted once the archive is built.
|
|
193
|
+
*
|
|
194
|
+
* Nothing is built — {@link BackupSnapshotRefusedError} — when the owner
|
|
195
|
+
* fails, or when a live database (one with a sidecar) has no owner: an
|
|
196
|
+
* archive without the settings database must never reach a destination,
|
|
197
|
+
* because its upload prunes an older archive that HAS it.
|
|
198
|
+
*/
|
|
199
|
+
owner?: DatabaseOwner;
|
|
162
200
|
}): Promise<CreateArchiveResult>;
|
|
201
|
+
/**
|
|
202
|
+
* Tar `present` (filtered by `excluded`) plus the staged manifest into
|
|
203
|
+
* `archivePath`.
|
|
204
|
+
*/
|
|
205
|
+
private writeArchive;
|
|
163
206
|
/**
|
|
164
207
|
* without extracting payload files. Streams the tar.gz, parses the
|
|
165
208
|
* one entry we care about, then aborts.
|
|
166
209
|
*/
|
|
167
210
|
readArchiveManifest(archivePath: string): Promise<ArchiveManifest | null>;
|
|
168
|
-
/**
|
|
169
|
-
* Extract a previously-created archive over `targetDir`. Used at boot
|
|
170
|
-
* by the restore hook — never call from a running server (would
|
|
171
|
-
* corrupt sqlite mid-run).
|
|
172
|
-
*
|
|
173
|
-
* `locations` is an optional whitelist: only entries whose path
|
|
174
|
-
* starts with one of the locations get extracted. Used by the
|
|
175
|
-
* partial-restore flow where the operator picks a subset of the
|
|
176
|
-
* archive contents to apply (e.g. "restore my devices but keep
|
|
177
|
-
* my current TLS certs").
|
|
178
|
-
*/
|
|
179
|
-
extractArchive(opts: {
|
|
180
|
-
archivePath: string;
|
|
181
|
-
targetDir: string;
|
|
182
|
-
locations?: readonly string[];
|
|
183
|
-
}): Promise<void>;
|
|
184
211
|
/**
|
|
185
212
|
* Schedule a restore for the next boot by writing a marker file.
|
|
186
|
-
* `locations` (optional) carries through to the boot-time
|
|
187
|
-
*
|
|
188
|
-
* choice survives the process
|
|
213
|
+
* `locations` (optional) carries through to the launcher's boot-time
|
|
214
|
+
* restore (`server/backend/src/launcher.ts`, the only restore there is)
|
|
215
|
+
* so the operator's "restore only X and Y" choice survives the process
|
|
216
|
+
* restart.
|
|
189
217
|
*/
|
|
190
218
|
scheduleRestoreMarker(opts: {
|
|
191
219
|
archivePath: string;
|
|
@@ -196,6 +224,32 @@ export declare class SystemBackupService {
|
|
|
196
224
|
readPendingMarker(): RestoreMarker | null;
|
|
197
225
|
/** Drop the marker after a successful boot-time restore. */
|
|
198
226
|
clearPendingMarker(): void;
|
|
227
|
+
/**
|
|
228
|
+
* The databases the owner declares, archive-relative, that this walk found.
|
|
229
|
+
* One outside this data root is not in scope. An owner that cannot answer
|
|
230
|
+
* stops the archive: without the answer, nothing says which file is live.
|
|
231
|
+
*/
|
|
232
|
+
private ownedDatabasesInScope;
|
|
233
|
+
/**
|
|
234
|
+
* Ask the owner for its snapshot, and place it in this archive. The snapshot
|
|
235
|
+
* must sit on THIS data root — the call is pinned to this node, so a path
|
|
236
|
+
* elsewhere means it reached another host, and that file is not ours to
|
|
237
|
+
* read — beside an owned database in scope, and it must cover EVERY owned
|
|
238
|
+
* database in scope. Anything else is refused.
|
|
239
|
+
*
|
|
240
|
+
* Only ever DELETED here: `<owned db>.backup-snapshot` under this data root,
|
|
241
|
+
* a name this process derives itself. A path the owner ANSWERS is never
|
|
242
|
+
* deleted on its word — answering the live database as the snapshot would
|
|
243
|
+
* otherwise delete the live database. A file at any other path is left to
|
|
244
|
+
* the owner's own sweep.
|
|
245
|
+
*
|
|
246
|
+
* A cancel is honoured while the owner is still copying; the copy it may
|
|
247
|
+
* finish afterwards is removed when that call settles.
|
|
248
|
+
*/
|
|
249
|
+
private takeOwnerSnapshot;
|
|
250
|
+
private removeSnapshot;
|
|
251
|
+
/** `abs` relative to the data root, or null when it lies outside it. */
|
|
252
|
+
private archiveRelative;
|
|
199
253
|
private getRestoreMarkerPath;
|
|
200
254
|
/**
|
|
201
255
|
* Absolute-path form of {@link isExcludedFromBackup}, anchored on
|
|
@@ -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-CSs0cFDN.js");
|
|
7
7
|
//#region src/builtins/system-config/system-config.addon.ts
|
|
8
8
|
/**
|
|
9
9
|
* Built-in `system-config` addon — Phase 4 of the settings redesign.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Xn as errMsg, Zn as BaseAddon, dr as hydrateSchema } from "../../dist-CV7IqaYq.mjs";
|
|
2
2
|
//#region src/builtins/system-config/system-config.addon.ts
|
|
3
3
|
/**
|
|
4
4
|
* Built-in `system-config` addon — Phase 4 of the settings redesign.
|
|
@@ -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-CSs0cFDN.js");
|
|
7
7
|
const require_formatter = require("../../formatter-DqAKDlvN.js");
|
|
8
8
|
let node_path = require("node:path");
|
|
9
9
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Gt as logDestinationCapability, Zn as BaseAddon } from "../../dist-CV7IqaYq.mjs";
|
|
2
2
|
import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
|
|
3
3
|
import * as path$1 from "node:path";
|
|
4
4
|
import path from "node:path";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Hn as compositionSourceKey, Xn as errMsg } from "./dist-CV7IqaYq.mjs";
|
|
2
2
|
//#region src/builtins/core-blocks/composition-sources.ts
|
|
3
3
|
/**
|
|
4
4
|
* Describe what a composition reads and writes for SAVE-time validation
|