@camstack/system 1.2.443 → 1.2.445
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/assets/record-entries/icon.svg +8 -0
- package/dist/addon-runner.js +81 -42
- package/dist/addon-runner.mjs +82 -43
- package/dist/{agent-https-DlpTMDqA.js → agent-https-CiOW0-sj.js} +810 -12
- package/dist/{agent-https-U0d4uvn2.mjs → agent-https-D4Q8iFNd.mjs} +697 -13
- package/dist/auth/admin-token-manager.d.ts +9 -3
- package/dist/auth/api-key-manager.d.ts +9 -3
- package/dist/auth/auth-audit-log.d.ts +9 -3
- package/dist/auth/device-credential-manager.d.ts +5 -1
- package/dist/auth/external-identity-manager.d.ts +8 -21
- package/dist/auth/login-session-manager.d.ts +11 -3
- package/dist/auth/scoped-token-manager.d.ts +8 -52
- package/dist/auth/totp-manager.d.ts +11 -3
- package/dist/auth/user-manager.d.ts +10 -17
- 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/alert-store.d.ts +32 -0
- package/dist/builtins/alerts/alerts.addon.d.ts +19 -4
- package/dist/builtins/alerts/alerts.addon.js +331 -159
- package/dist/builtins/alerts/alerts.addon.mjs +330 -159
- package/dist/builtins/alerts/record-kinds.d.ts +15 -0
- 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 +1 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +134 -193
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +134 -193
- package/dist/builtins/backup-orchestrator/destination-policy.d.ts +4 -2
- package/dist/builtins/backup-orchestrator/encryption-key-store.d.ts +4 -2
- package/dist/builtins/backup-orchestrator/record-kinds.d.ts +58 -0
- package/dist/builtins/backup-orchestrator/schedule-store.d.ts +4 -2
- package/dist/builtins/backup-orchestrator/seed-marker-store.d.ts +4 -2
- package/dist/builtins/calendars/calendar-prefs-store.d.ts +13 -5
- package/dist/builtins/calendars/calendars.addon.d.ts +2 -2
- package/dist/builtins/calendars/calendars.addon.js +67 -64
- package/dist/builtins/calendars/calendars.addon.mjs +59 -64
- package/dist/builtins/calendars/record-kinds.d.ts +18 -0
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/cluster-agent/record-kinds.d.ts +36 -0
- 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/block-settings-store.d.ts +8 -4
- package/dist/builtins/core-blocks/core-block-store.d.ts +8 -16
- package/dist/builtins/core-blocks/core-blocks.addon.js +85 -112
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +86 -113
- package/dist/builtins/core-blocks/index.mjs +1 -1
- package/dist/builtins/core-blocks/record-kinds.d.ts +26 -0
- package/dist/builtins/device-manager/device-manager.addon.js +111 -187
- package/dist/builtins/device-manager/device-manager.addon.mjs +110 -187
- package/dist/builtins/device-manager/device-tombstone-store.d.ts +9 -48
- package/dist/builtins/device-manager/record-kinds.d.ts +14 -0
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/keychain/index.js +152 -22
- package/dist/builtins/keychain/index.mjs +152 -22
- package/dist/builtins/keychain/keychain-service.d.ts +3 -2
- package/dist/builtins/keychain/keychain-store.d.ts +13 -2
- package/dist/builtins/keychain/record-kinds.d.ts +16 -0
- 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/auth-schema.d.ts +3 -1
- package/dist/builtins/local-auth/local-auth.addon.js +2903 -2123
- package/dist/builtins/local-auth/local-auth.addon.mjs +2904 -2124
- package/dist/builtins/local-auth/oauth-session-manager.d.ts +8 -48
- package/dist/builtins/local-auth/record-kinds.d.ts +141 -0
- package/dist/builtins/local-network/local-network.addon.js +2 -2
- package/dist/builtins/local-network/local-network.addon.mjs +2 -2
- 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/record-entries/entries-service.d.ts +42 -0
- package/dist/builtins/record-entries/index.d.ts +1 -0
- package/dist/builtins/record-entries/index.js +142 -0
- package/dist/builtins/record-entries/index.mjs +136 -0
- package/dist/builtins/record-entries/record-entries.addon.d.ts +13 -0
- package/dist/builtins/records/legacy-table-row-count.d.ts +5 -0
- package/dist/builtins/records/phase6-declare-gate.d.ts +28 -0
- package/dist/builtins/records-isolated.d.ts +10 -0
- 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/file-host-client.d.ts +2 -0
- package/dist/builtins/sqlite-storage/file-host-handlers.d.ts +4 -0
- package/dist/builtins/sqlite-storage/file-host-protocol.d.ts +7 -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/index.js +1 -1
- package/dist/builtins/sqlite-storage/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/integration-record-kinds.d.ts +30 -0
- package/dist/builtins/sqlite-storage/integration-registry.d.ts +10 -16
- package/dist/builtins/sqlite-storage/owned-sqlite-file.d.ts +7 -0
- package/dist/builtins/sqlite-storage/placement-router.d.ts +5 -0
- package/dist/builtins/sqlite-storage/records/count-settings-array-legacy.d.ts +5 -0
- package/dist/builtins/sqlite-storage/records/count-settings-brokers-legacy.d.ts +6 -0
- package/dist/builtins/sqlite-storage/records/records-catalog.d.ts +29 -0
- package/dist/builtins/sqlite-storage/records/records-engine-types.d.ts +51 -0
- package/dist/builtins/sqlite-storage/records/records-engine.d.ts +94 -0
- package/dist/builtins/sqlite-storage/records/records-explain.d.ts +18 -0
- package/dist/builtins/sqlite-storage/records/records-plan.d.ts +90 -0
- package/dist/builtins/sqlite-storage/records/records-probe.d.ts +33 -0
- package/dist/builtins/sqlite-storage/records/records-provider.d.ts +63 -0
- package/dist/builtins/sqlite-storage/records/records-rows.d.ts +46 -0
- package/dist/builtins/sqlite-storage/records/records-sql.d.ts +41 -0
- package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +17 -10
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +8 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +446 -5
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +446 -5
- package/dist/builtins/sqlite-storage/storage-admin-provider.d.ts +15 -1
- package/dist/builtins/storage-orchestrator/drain-state-store.d.ts +5 -2
- package/dist/builtins/storage-orchestrator/location-store.d.ts +7 -2
- package/dist/builtins/storage-orchestrator/record-kinds.d.ts +38 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +2 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +196 -5
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +195 -6
- package/dist/builtins/system-config/record-kinds.d.ts +32 -0
- package/dist/builtins/system-config/system-config.addon.js +53 -618
- package/dist/builtins/system-config/system-config.addon.mjs +29 -577
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{composition-sources-C8tUG2uL.mjs → composition-sources-BMt5cFYb.mjs} +1 -1
- package/dist/{composition-sources-BUXX1e8j.js → composition-sources-D3fi9Xns.js} +1 -1
- package/dist/{constants-CGwVaAV3.mjs → constants-BMHCxRzb.mjs} +1 -1
- package/dist/{constants-DWmm7_of.js → constants-Br879Axi.js} +1 -1
- package/dist/{device-ca-DGayRmC0.js → device-ca-CnJ_va7i.js} +1 -1
- package/dist/{device-ca-DBfiJ_SB.mjs → device-ca-T8osSMos.mjs} +1 -1
- package/dist/{dist-Bxt_S-9a.mjs → dist-BNunRyXT.mjs} +1133 -93
- package/dist/{dist-D9qT3jHr.js → dist-DgOG8flk.js} +1354 -92
- package/dist/file-host-worker.js +11 -1
- package/dist/file-host-worker.mjs +11 -1
- package/dist/{hub-mdns-ciao-B-wk9nzx.js → hub-mdns-ciao-BIkTHq-n.js} +2 -2
- package/dist/{hub-mdns-ciao-DpPcQDg-.mjs → hub-mdns-ciao-D16oRQ9K.mjs} +2 -2
- package/dist/index.d.ts +7 -0
- package/dist/index.js +3111 -2806
- package/dist/index.mjs +3083 -2795
- package/dist/kernel/index.d.ts +2 -0
- package/dist/kernel/moleculer/event-bus.d.ts +3 -1
- package/dist/kernel/moleculer/mesh-mtls/mesh-certificate-registry.d.ts +5 -1
- package/dist/kernel/moleculer/records-api-transport.d.ts +9 -0
- package/dist/kernel/moleculer/remote-logger.d.ts +2 -2
- package/dist/kernel/settings-view-types.d.ts +0 -7
- package/dist/kernel/transport/cap-route-resolver.d.ts +9 -38
- package/dist/phase6-declare-gate-Ci1-8uUn.js +98 -0
- package/dist/phase6-declare-gate-tkKOEitw.mjs +93 -0
- package/dist/read-all-rows-CVoO1ONM.js +29 -0
- package/dist/read-all-rows-TaPqdWNF.mjs +25 -0
- package/dist/records/read-all-rows.d.ts +6 -0
- package/dist/{restore-archive-9CGgeBzD.mjs → restore-archive-DR9MtO7J.mjs} +339 -9
- package/dist/{restore-archive-BMNXwWWD.js → restore-archive-DjJnCgap.js} +353 -5
- package/dist/tls/agent-https-names.d.ts +9 -13
- package/dist/{wal-maintenance-cRHR4rUY.js → wal-maintenance-CODGqhKY.js} +0 -0
- package/dist/{wal-maintenance-sIB32ONp.mjs → wal-maintenance-CfvgtQ7C.mjs} +0 -0
- package/package.json +22 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $r as RECORD_SWEEP_INTERVAL_MS, Ft as databaseSnapshotCapability, Ji as parseSettingsArrayAdoptsFrom, Jr as NoCallerError, Lr as errMsg, Pt as dataStoreProviderCapability, Q as STORAGE_ADMIN_SCOPED_BASES, Rr as BaseAddon, S as DATA_STORE_DATABASES, Vn as recordsCapability, Wi as normalizeSecretOwner, Wr as DeclarationRefusedError, Yi as parseSettingsBrokersAdoptsFrom, Z as STORAGE_ADMIN_MOVED_COLLECTIONS, ai as RecordKindDeclarationSchema, b as DATABASE_SNAPSHOT_SUFFIX, br as vectorStoreCapability, fi as UnknownRecordKindError, ht as bareAddonId, ni as RUNTIME_DEFAULTS, sr as storageAdminCapability, x as DATABASE_SNAPSHOT_TIMEOUT_MS, y as DATABASE_SNAPSHOT_PARTIAL_SUFFIX } from "../../dist-BNunRyXT.mjs";
|
|
2
2
|
import { i as retiredKeyStoreOf, n as purgeRetiredSettingsKeys } from "../../retired-settings-keys-Bhwe4ymb.mjs";
|
|
3
|
-
import { C as
|
|
3
|
+
import { C as callControl, D as controlTargetOf, E as callVector, S as RecordsEngine, T as callRecords, _ as isFileHostMessage, a as WalMaintenance, c as SqliteSettingsBackend, d as DatabaseBusyError, f as DuplicatePlacementError, g as collectTransferables, l as CollectionPlacementError, o as createVectorIndex, p as rehydrateError, s as vectorProviderOf, u as CrossDatabaseTransactError, w as callData, x as trustResult } from "../../wal-maintenance-CfvgtQ7C.mjs";
|
|
4
4
|
import { r as isSnapshotWorkerMessage } from "../../sqlite-snapshot-protocol-2QaTouWV.mjs";
|
|
5
5
|
import { a as isWorkerMessage, t as WAL_CHECKPOINT_LARGE_PASS_FRAMES } from "../../wal-checkpoint-policy-BahrTtyD.mjs";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
@@ -101,6 +101,13 @@ var FileHostClient = class {
|
|
|
101
101
|
input
|
|
102
102
|
});
|
|
103
103
|
}
|
|
104
|
+
records(op, input) {
|
|
105
|
+
return this.request({
|
|
106
|
+
kind: "records",
|
|
107
|
+
op,
|
|
108
|
+
input
|
|
109
|
+
});
|
|
110
|
+
}
|
|
104
111
|
control(op, input) {
|
|
105
112
|
return this.request({
|
|
106
113
|
kind: "control",
|
|
@@ -863,6 +870,7 @@ var InlineOwnedFile = class extends OwnedFileBase {
|
|
|
863
870
|
vectorIndex = null;
|
|
864
871
|
vectorProvider = null;
|
|
865
872
|
maintenance = null;
|
|
873
|
+
recordsEngine = null;
|
|
866
874
|
constructor(spec, deps) {
|
|
867
875
|
super(spec, deps);
|
|
868
876
|
this.backend = new SqliteSettingsBackend(spec.livePath, deps.runtimeDefaults === void 0 ? {} : { ...deps.runtimeDefaults }, this.log("Query"), {
|
|
@@ -880,6 +888,11 @@ var InlineOwnedFile = class extends OwnedFileBase {
|
|
|
880
888
|
this.vectorIndex = vectorIndex;
|
|
881
889
|
this.vectorProvider = vectorProviderOf(vectorIndex);
|
|
882
890
|
}
|
|
891
|
+
const handle = this.backend.getDatabase();
|
|
892
|
+
if (handle !== null) this.recordsEngine = new RecordsEngine(handle, {
|
|
893
|
+
databaseId: this.spec.databaseId,
|
|
894
|
+
logger: this.log("Records")
|
|
895
|
+
});
|
|
883
896
|
await this.deps.afterOpen?.(this);
|
|
884
897
|
const db = this.backend.getDatabase();
|
|
885
898
|
if (db !== null) {
|
|
@@ -901,6 +914,10 @@ var InlineOwnedFile = class extends OwnedFileBase {
|
|
|
901
914
|
if (op === "declareCollection") this.declared = this.backend.declaredCollectionNames();
|
|
902
915
|
return result;
|
|
903
916
|
}
|
|
917
|
+
async records(op, input) {
|
|
918
|
+
if (this.recordsEngine === null) throw new Error(`database "${this.databaseId}" is not open`);
|
|
919
|
+
return callRecords(this.recordsEngine, op, input);
|
|
920
|
+
}
|
|
904
921
|
async vector(op, input) {
|
|
905
922
|
if (this.vectorProvider === null) throw new Error(`database "${this.databaseId}" does not serve vector calls`);
|
|
906
923
|
return callVector(this.vectorProvider, op, input);
|
|
@@ -956,6 +973,9 @@ var WorkerOwnedFile = class extends OwnedFileBase {
|
|
|
956
973
|
vector(op, input) {
|
|
957
974
|
return this.client.vector(op, input);
|
|
958
975
|
}
|
|
976
|
+
records(op, input) {
|
|
977
|
+
return this.client.records(op, input);
|
|
978
|
+
}
|
|
959
979
|
declaredCollections() {
|
|
960
980
|
return this.client.declaredCollections();
|
|
961
981
|
}
|
|
@@ -1088,6 +1108,14 @@ var PlacementRouter = class {
|
|
|
1088
1108
|
databaseOf(table) {
|
|
1089
1109
|
return this.placement.get(table) ?? "settings";
|
|
1090
1110
|
}
|
|
1111
|
+
/**
|
|
1112
|
+
* The file that hosts records of `databaseId`, created by the first
|
|
1113
|
+
* declaration that names it (`events`). `history` never hosts records.
|
|
1114
|
+
*/
|
|
1115
|
+
async recordsFileFor(databaseId) {
|
|
1116
|
+
if (databaseId === "history") throw new Error("placement: history.db is device-history's and never hosts records");
|
|
1117
|
+
return this.openFile(databaseId);
|
|
1118
|
+
}
|
|
1091
1119
|
/** The files currently open, settings first. */
|
|
1092
1120
|
openFiles() {
|
|
1093
1121
|
return DATA_STORE_DATABASES.flatMap((id) => {
|
|
@@ -1198,6 +1226,368 @@ var PlacementRouter = class {
|
|
|
1198
1226
|
}
|
|
1199
1227
|
};
|
|
1200
1228
|
//#endregion
|
|
1229
|
+
//#region src/builtins/sqlite-storage/records/count-settings-array-legacy.ts
|
|
1230
|
+
function isRecord$1(value) {
|
|
1231
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1232
|
+
}
|
|
1233
|
+
function unwrapValue$1(raw) {
|
|
1234
|
+
if (isRecord$1(raw) && "value" in raw) return raw["value"];
|
|
1235
|
+
return raw;
|
|
1236
|
+
}
|
|
1237
|
+
function legacyRowId(item) {
|
|
1238
|
+
const id = item["id"];
|
|
1239
|
+
if (typeof id === "string" && id.length > 0) return id;
|
|
1240
|
+
const username = item["username"];
|
|
1241
|
+
if (typeof username === "string" && username.length > 0) return username;
|
|
1242
|
+
return null;
|
|
1243
|
+
}
|
|
1244
|
+
async function countSettingsArrayLegacy(router, addonId, settingsKey) {
|
|
1245
|
+
const list = unwrapValue$1(await router.get({
|
|
1246
|
+
collection: "addon-settings",
|
|
1247
|
+
key: `${addonId}.${settingsKey}`
|
|
1248
|
+
}));
|
|
1249
|
+
if (!Array.isArray(list)) return 0;
|
|
1250
|
+
let n = 0;
|
|
1251
|
+
for (const item of list) {
|
|
1252
|
+
if (!isRecord$1(item)) continue;
|
|
1253
|
+
if (legacyRowId(item) !== null) n += 1;
|
|
1254
|
+
}
|
|
1255
|
+
return n;
|
|
1256
|
+
}
|
|
1257
|
+
//#endregion
|
|
1258
|
+
//#region src/builtins/sqlite-storage/records/count-settings-brokers-legacy.ts
|
|
1259
|
+
function isRecord(value) {
|
|
1260
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1261
|
+
}
|
|
1262
|
+
function unwrapValue(raw) {
|
|
1263
|
+
if (isRecord(raw) && "value" in raw) return raw["value"];
|
|
1264
|
+
return raw;
|
|
1265
|
+
}
|
|
1266
|
+
async function countSettingsBrokersLegacy(router, addonId) {
|
|
1267
|
+
const list = unwrapValue(await router.get({
|
|
1268
|
+
collection: "addon-settings",
|
|
1269
|
+
key: `${addonId}.brokers`
|
|
1270
|
+
}));
|
|
1271
|
+
if (!Array.isArray(list)) return 0;
|
|
1272
|
+
let n = 0;
|
|
1273
|
+
for (const item of list) if (isRecord(item) && typeof item["id"] === "string") n += 1;
|
|
1274
|
+
return n;
|
|
1275
|
+
}
|
|
1276
|
+
//#endregion
|
|
1277
|
+
//#region src/builtins/sqlite-storage/records/records-provider.ts
|
|
1278
|
+
/**
|
|
1279
|
+
* The `records` capability of the engine (D881): resolves WHO is calling and
|
|
1280
|
+
* WHICH file a kind lives in, then hands the call to that file's records engine.
|
|
1281
|
+
*
|
|
1282
|
+
* - **Owner** = the transport-stamped `callerAddonId` (as device-history's
|
|
1283
|
+
* `not-owner` and the keychain). It is never a field of any input; a call with
|
|
1284
|
+
* no stamp is refused `records/no-caller`.
|
|
1285
|
+
* - **Placement**: a kind's file is its declaration's `database`. The map is
|
|
1286
|
+
* rebuilt from each open file's own `_record_kinds` at boot and updated on
|
|
1287
|
+
* declaration. A kind declared for another file than the one it lives in is
|
|
1288
|
+
* refused (the engine never moves data, D853).
|
|
1289
|
+
* - **The boot guard**: after a declaration, a kind with `adoptsFrom` that is
|
|
1290
|
+
* EMPTY while its legacy table still holds rows is reported `adoptionPending`;
|
|
1291
|
+
* `ctx.records.declare` turns that into a refusal to start.
|
|
1292
|
+
*/
|
|
1293
|
+
/** The caller the transport stamped, or a refusal. */
|
|
1294
|
+
function recordsCallerOf(input) {
|
|
1295
|
+
const raw = input !== null && typeof input === "object" ? Reflect.get(input, "callerAddonId") : void 0;
|
|
1296
|
+
if (typeof raw !== "string" || raw.length === 0) throw new NoCallerError("the call carries no caller identity; records are reached through ctx.records");
|
|
1297
|
+
return normalizeSecretOwner(raw);
|
|
1298
|
+
}
|
|
1299
|
+
function keyOf(owner, kind) {
|
|
1300
|
+
return `${owner}\u0000${kind}`;
|
|
1301
|
+
}
|
|
1302
|
+
var RecordsProvider = class {
|
|
1303
|
+
router;
|
|
1304
|
+
logger;
|
|
1305
|
+
placement = /* @__PURE__ */ new Map();
|
|
1306
|
+
constructor(router, logger) {
|
|
1307
|
+
this.router = router;
|
|
1308
|
+
this.logger = logger;
|
|
1309
|
+
}
|
|
1310
|
+
/** Rebuild the placement map from every open file's catalog. Call once, after the files are open. */
|
|
1311
|
+
async init() {
|
|
1312
|
+
this.placement.clear();
|
|
1313
|
+
for (const file of this.router.openFiles()) {
|
|
1314
|
+
if (file.databaseId === "history") continue;
|
|
1315
|
+
const kinds = await file.records("listKinds", {});
|
|
1316
|
+
for (const k of kinds) {
|
|
1317
|
+
if (k.state === "dropped") continue;
|
|
1318
|
+
const key = keyOf(k.owner, k.kind);
|
|
1319
|
+
const other = this.placement.get(key);
|
|
1320
|
+
if (other !== void 0 && other !== file.databaseId) throw new DeclarationRefusedError(`kind "${k.kind}" of "${k.owner}" is in both "${other}" and "${file.databaseId}"; the layout is corrupt and is not served`);
|
|
1321
|
+
this.placement.set(key, file.databaseId);
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
this.logger.info("records: catalog loaded", { meta: { kinds: this.placement.size } });
|
|
1325
|
+
}
|
|
1326
|
+
fileOf(owner, kind) {
|
|
1327
|
+
const database = this.placement.get(keyOf(owner, kind));
|
|
1328
|
+
if (database === void 0) return Promise.reject(new UnknownRecordKindError(`"${owner}" declared no kind "${kind}"`));
|
|
1329
|
+
return this.router.recordsFileFor(database);
|
|
1330
|
+
}
|
|
1331
|
+
async declareKinds(input) {
|
|
1332
|
+
const owner = recordsCallerOf(input);
|
|
1333
|
+
const byDatabase = /* @__PURE__ */ new Map();
|
|
1334
|
+
for (const [kind, raw] of Object.entries(input.kinds)) {
|
|
1335
|
+
const declaration = RecordKindDeclarationSchema.parse(raw);
|
|
1336
|
+
const known = this.placement.get(keyOf(owner, kind));
|
|
1337
|
+
if (known !== void 0 && known !== declaration.database) throw new DeclarationRefusedError(`kind "${kind}" of "${owner}" lives in "${known}", declared for "${declaration.database}" - the engine never moves data`);
|
|
1338
|
+
const group = byDatabase.get(declaration.database) ?? {};
|
|
1339
|
+
byDatabase.set(declaration.database, {
|
|
1340
|
+
...group,
|
|
1341
|
+
[kind]: declaration
|
|
1342
|
+
});
|
|
1343
|
+
}
|
|
1344
|
+
const merged = {};
|
|
1345
|
+
for (const [database, kinds] of byDatabase) {
|
|
1346
|
+
const { kinds: results } = await (await this.router.recordsFileFor(database)).records("declareKinds", {
|
|
1347
|
+
owner,
|
|
1348
|
+
kinds
|
|
1349
|
+
});
|
|
1350
|
+
for (const [kind, result] of Object.entries(results)) {
|
|
1351
|
+
this.placement.set(keyOf(owner, kind), database);
|
|
1352
|
+
merged[kind] = result;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
return { kinds: await this.withAdoption(owner, input.kinds, merged) };
|
|
1356
|
+
}
|
|
1357
|
+
/** The boot guard: empty kind + a legacy table that still has rows = adoption pending. */
|
|
1358
|
+
async withAdoption(owner, declared, results) {
|
|
1359
|
+
const out = { ...results };
|
|
1360
|
+
for (const [kind, raw] of Object.entries(declared)) {
|
|
1361
|
+
const legacy = raw.adoptsFrom;
|
|
1362
|
+
const result = results[kind];
|
|
1363
|
+
if (legacy === void 0 || result === void 0) continue;
|
|
1364
|
+
if ((await (await this.fileOf(owner, kind)).records("adoptionState", {
|
|
1365
|
+
owner,
|
|
1366
|
+
kind
|
|
1367
|
+
})).adoptedAt !== null) continue;
|
|
1368
|
+
const settingsBrokersAddon = parseSettingsBrokersAdoptsFrom(legacy);
|
|
1369
|
+
if (settingsBrokersAddon !== null) {
|
|
1370
|
+
const legacyRows = await countSettingsBrokersLegacy(this.router, settingsBrokersAddon);
|
|
1371
|
+
if (legacyRows > 0) out[kind] = {
|
|
1372
|
+
...result,
|
|
1373
|
+
adoptionPending: {
|
|
1374
|
+
legacyTable: legacy,
|
|
1375
|
+
legacyRows
|
|
1376
|
+
}
|
|
1377
|
+
};
|
|
1378
|
+
continue;
|
|
1379
|
+
}
|
|
1380
|
+
const settingsArray = parseSettingsArrayAdoptsFrom(legacy);
|
|
1381
|
+
if (settingsArray !== null) {
|
|
1382
|
+
const legacyRows = await countSettingsArrayLegacy(this.router, settingsArray.addonId, settingsArray.settingsKey);
|
|
1383
|
+
if (legacyRows > 0) out[kind] = {
|
|
1384
|
+
...result,
|
|
1385
|
+
adoptionPending: {
|
|
1386
|
+
legacyTable: legacy,
|
|
1387
|
+
legacyRows
|
|
1388
|
+
}
|
|
1389
|
+
};
|
|
1390
|
+
continue;
|
|
1391
|
+
}
|
|
1392
|
+
const legacyRows = await (await this.router.recordsFileFor("settings")).records("legacyRowCount", { table: legacy });
|
|
1393
|
+
if (legacyRows !== null && legacyRows > 0) out[kind] = {
|
|
1394
|
+
...result,
|
|
1395
|
+
adoptionPending: {
|
|
1396
|
+
legacyTable: legacy,
|
|
1397
|
+
legacyRows
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
return out;
|
|
1402
|
+
}
|
|
1403
|
+
async get(input) {
|
|
1404
|
+
const owner = recordsCallerOf(input);
|
|
1405
|
+
return (await this.fileOf(owner, input.kind)).records("get", {
|
|
1406
|
+
...input,
|
|
1407
|
+
owner
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
async getMany(input) {
|
|
1411
|
+
const owner = recordsCallerOf(input);
|
|
1412
|
+
return (await this.fileOf(owner, input.kind)).records("getMany", {
|
|
1413
|
+
...input,
|
|
1414
|
+
owner
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
async secretRefs(input) {
|
|
1418
|
+
const owner = recordsCallerOf(input);
|
|
1419
|
+
return (await this.fileOf(owner, input.kind)).records("secretRefs", {
|
|
1420
|
+
...input,
|
|
1421
|
+
owner
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
async put(input) {
|
|
1425
|
+
const owner = recordsCallerOf(input);
|
|
1426
|
+
return (await this.fileOf(owner, input.kind)).records("put", {
|
|
1427
|
+
...input,
|
|
1428
|
+
owner
|
|
1429
|
+
});
|
|
1430
|
+
}
|
|
1431
|
+
async putMany(input) {
|
|
1432
|
+
const owner = recordsCallerOf(input);
|
|
1433
|
+
return (await this.fileOf(owner, input.kind)).records("putMany", {
|
|
1434
|
+
...input,
|
|
1435
|
+
owner
|
|
1436
|
+
});
|
|
1437
|
+
}
|
|
1438
|
+
async patch(input) {
|
|
1439
|
+
const owner = recordsCallerOf(input);
|
|
1440
|
+
return (await this.fileOf(owner, input.kind)).records("patch", {
|
|
1441
|
+
...input,
|
|
1442
|
+
owner
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
async delete(input) {
|
|
1446
|
+
const owner = recordsCallerOf(input);
|
|
1447
|
+
return (await this.fileOf(owner, input.kind)).records("delete", {
|
|
1448
|
+
...input,
|
|
1449
|
+
owner
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
async deleteMany(input) {
|
|
1453
|
+
const owner = recordsCallerOf(input);
|
|
1454
|
+
return (await this.fileOf(owner, input.kind)).records("deleteMany", {
|
|
1455
|
+
...input,
|
|
1456
|
+
owner
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
async query(input) {
|
|
1460
|
+
const owner = recordsCallerOf(input);
|
|
1461
|
+
return (await this.fileOf(owner, input.kind)).records("query", {
|
|
1462
|
+
...input,
|
|
1463
|
+
owner
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1466
|
+
async count(input) {
|
|
1467
|
+
const owner = recordsCallerOf(input);
|
|
1468
|
+
return (await this.fileOf(owner, input.kind)).records("count", {
|
|
1469
|
+
...input,
|
|
1470
|
+
owner
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
async histogram(input) {
|
|
1474
|
+
const owner = recordsCallerOf(input);
|
|
1475
|
+
return (await this.fileOf(owner, input.kind)).records("histogram", {
|
|
1476
|
+
...input,
|
|
1477
|
+
owner
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
async aggregate(input) {
|
|
1481
|
+
const owner = recordsCallerOf(input);
|
|
1482
|
+
return (await this.fileOf(owner, input.kind)).records("aggregate", {
|
|
1483
|
+
...input,
|
|
1484
|
+
owner
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1487
|
+
async deleteWhere(input) {
|
|
1488
|
+
const owner = recordsCallerOf(input);
|
|
1489
|
+
return (await this.fileOf(owner, input.kind)).records("deleteWhere", {
|
|
1490
|
+
...input,
|
|
1491
|
+
owner
|
|
1492
|
+
});
|
|
1493
|
+
}
|
|
1494
|
+
async allocateId(input) {
|
|
1495
|
+
const owner = recordsCallerOf(input);
|
|
1496
|
+
return (await this.fileOf(owner, input.kind)).records("allocateId", {
|
|
1497
|
+
...input,
|
|
1498
|
+
owner
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1501
|
+
/** The D865 hook body: every file that holds kinds of this owner. */
|
|
1502
|
+
async deleteDevice(input) {
|
|
1503
|
+
const owner = recordsCallerOf(input);
|
|
1504
|
+
const deleted = {};
|
|
1505
|
+
const secretRefs = [];
|
|
1506
|
+
const databases = new Set([...this.placement.entries()].filter(([key]) => key.startsWith(`${owner}\u0000`)).map(([, database]) => database));
|
|
1507
|
+
for (const database of databases) {
|
|
1508
|
+
const result = await (await this.router.recordsFileFor(database)).records("deleteDevice", {
|
|
1509
|
+
...input,
|
|
1510
|
+
owner
|
|
1511
|
+
});
|
|
1512
|
+
Object.assign(deleted, result.deleted);
|
|
1513
|
+
secretRefs.push(...result.secretRefs);
|
|
1514
|
+
}
|
|
1515
|
+
return {
|
|
1516
|
+
deleted,
|
|
1517
|
+
secretRefs
|
|
1518
|
+
};
|
|
1519
|
+
}
|
|
1520
|
+
async listKinds(input) {
|
|
1521
|
+
const kinds = [];
|
|
1522
|
+
for (const file of this.router.openFiles()) {
|
|
1523
|
+
if (file.databaseId === "history") continue;
|
|
1524
|
+
kinds.push(...await file.records("listKinds", input));
|
|
1525
|
+
}
|
|
1526
|
+
return { kinds };
|
|
1527
|
+
}
|
|
1528
|
+
async readRecords(input) {
|
|
1529
|
+
this.logger.info("records: admin read", { meta: {
|
|
1530
|
+
owner: input.owner,
|
|
1531
|
+
kind: input.kind,
|
|
1532
|
+
limit: input.limit
|
|
1533
|
+
} });
|
|
1534
|
+
return (await this.fileOf(input.owner, input.kind)).records("query", input);
|
|
1535
|
+
}
|
|
1536
|
+
/** True when a declared kind lists `collection` as `adoptsFrom` and adoption finished. */
|
|
1537
|
+
async isAdoptedLegacyTable(collection) {
|
|
1538
|
+
const { kinds } = await this.listKinds({ counts: false });
|
|
1539
|
+
for (const k of kinds) {
|
|
1540
|
+
if (k.state === "dropped") continue;
|
|
1541
|
+
if (k.declaration.adoptsFrom !== collection) continue;
|
|
1542
|
+
const { adoptedAt } = await (await this.fileOf(k.owner, k.kind)).records("adoptionState", {
|
|
1543
|
+
owner: k.owner,
|
|
1544
|
+
kind: k.kind
|
|
1545
|
+
});
|
|
1546
|
+
if (adoptedAt !== null) return true;
|
|
1547
|
+
}
|
|
1548
|
+
return false;
|
|
1549
|
+
}
|
|
1550
|
+
async adoptRecords(input) {
|
|
1551
|
+
const file = await this.fileOf(input.owner, input.kind);
|
|
1552
|
+
if (input.records.length > 0) {
|
|
1553
|
+
const { adoptedAt } = await file.records("adoptionState", {
|
|
1554
|
+
owner: input.owner,
|
|
1555
|
+
kind: input.kind
|
|
1556
|
+
});
|
|
1557
|
+
if (adoptedAt !== null) {
|
|
1558
|
+
if ((await file.records("count", {
|
|
1559
|
+
owner: input.owner,
|
|
1560
|
+
kind: input.kind
|
|
1561
|
+
})).count === 0) await file.records("revokeAdopted", {
|
|
1562
|
+
owner: input.owner,
|
|
1563
|
+
kind: input.kind
|
|
1564
|
+
});
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
const result = await file.records("putMany", input);
|
|
1568
|
+
if (input.complete === true) await file.records("markAdopted", {
|
|
1569
|
+
owner: input.owner,
|
|
1570
|
+
kind: input.kind
|
|
1571
|
+
});
|
|
1572
|
+
this.logger.warn("records: ADOPTED rows as their declared owner", { meta: {
|
|
1573
|
+
owner: input.owner,
|
|
1574
|
+
kind: input.kind,
|
|
1575
|
+
count: result.count,
|
|
1576
|
+
complete: input.complete === true
|
|
1577
|
+
} });
|
|
1578
|
+
return { adopted: result.count };
|
|
1579
|
+
}
|
|
1580
|
+
/** Housekeeping: delete rows past `expires_at` in every file that hosts kinds. */
|
|
1581
|
+
async sweepExpired() {
|
|
1582
|
+
let deleted = 0;
|
|
1583
|
+
for (const file of this.router.openFiles()) {
|
|
1584
|
+
if (file.databaseId === "history") continue;
|
|
1585
|
+
deleted += (await file.records("sweepExpired", {})).deleted;
|
|
1586
|
+
}
|
|
1587
|
+
return deleted;
|
|
1588
|
+
}
|
|
1589
|
+
};
|
|
1590
|
+
//#endregion
|
|
1201
1591
|
//#region src/builtins/sqlite-storage/storage-admin-provider.ts
|
|
1202
1592
|
/**
|
|
1203
1593
|
* The `storage-admin` provider of the SQLite engine (D870): the operator's
|
|
@@ -1211,10 +1601,27 @@ var StorageAdminProvider = class {
|
|
|
1211
1601
|
backend;
|
|
1212
1602
|
logger;
|
|
1213
1603
|
installedOwners;
|
|
1214
|
-
|
|
1604
|
+
records;
|
|
1605
|
+
constructor(backend, logger, installedOwners, records) {
|
|
1215
1606
|
this.backend = backend;
|
|
1216
1607
|
this.logger = logger;
|
|
1217
1608
|
this.installedOwners = installedOwners;
|
|
1609
|
+
this.records = records;
|
|
1610
|
+
}
|
|
1611
|
+
listKinds(input) {
|
|
1612
|
+
return this.records.listKinds(input);
|
|
1613
|
+
}
|
|
1614
|
+
readRecords(input) {
|
|
1615
|
+
return this.records.readRecords(input);
|
|
1616
|
+
}
|
|
1617
|
+
adoptRecords(input) {
|
|
1618
|
+
return this.records.adoptRecords(input);
|
|
1619
|
+
}
|
|
1620
|
+
isAdoptedLegacyTable(input) {
|
|
1621
|
+
return this.records.isAdoptedLegacyTable(input.collection).then((adopted) => ({ adopted }));
|
|
1622
|
+
}
|
|
1623
|
+
readLegacyCollection(input) {
|
|
1624
|
+
return Promise.resolve(this.backend.readLegacyCollection(input));
|
|
1218
1625
|
}
|
|
1219
1626
|
/** May this table be dropped AT ALL? Throws with the reason when not. */
|
|
1220
1627
|
async assertDroppable(collection) {
|
|
@@ -1227,7 +1634,7 @@ var StorageAdminProvider = class {
|
|
|
1227
1634
|
throw new Error(`drop refused: the installed addons could not be read (${err instanceof Error ? err.message : String(err)})`);
|
|
1228
1635
|
});
|
|
1229
1636
|
const owner = collection.slice(0, colon);
|
|
1230
|
-
if (installed.has(owner)) throw new Error(`drop refused: "${collection}" belongs to the installed addon "${owner}"`);
|
|
1637
|
+
if (installed.has(owner) && !await this.records.isAdoptedLegacyTable(collection)) throw new Error(`drop refused: "${collection}" belongs to the installed addon "${owner}"`);
|
|
1231
1638
|
}
|
|
1232
1639
|
async listTables(input) {
|
|
1233
1640
|
const tables = this.backend.listTables(input.ownerPrefix);
|
|
@@ -1240,6 +1647,7 @@ var StorageAdminProvider = class {
|
|
|
1240
1647
|
async dropCollection(input) {
|
|
1241
1648
|
try {
|
|
1242
1649
|
await this.assertDroppable(input.collection);
|
|
1650
|
+
if (await this.records.isAdoptedLegacyTable(input.collection)) this.backend.forgetDeclaredThisBoot(input.collection);
|
|
1243
1651
|
const rows = this.backend.dropTable(input.collection, input.expectRows);
|
|
1244
1652
|
this.logger.warn("storage-admin: DROPPED a table", { meta: {
|
|
1245
1653
|
collection: input.collection,
|
|
@@ -1407,6 +1815,8 @@ var DATABASE_FILE_NAMES = {
|
|
|
1407
1815
|
var SqliteSettingsAddon = class extends BaseAddon {
|
|
1408
1816
|
settingsFile = null;
|
|
1409
1817
|
router = null;
|
|
1818
|
+
sweepTimer = null;
|
|
1819
|
+
sweepStart = null;
|
|
1410
1820
|
constructor() {
|
|
1411
1821
|
super({});
|
|
1412
1822
|
}
|
|
@@ -1463,12 +1873,19 @@ var SqliteSettingsAddon = class extends BaseAddon {
|
|
|
1463
1873
|
this.router = router;
|
|
1464
1874
|
const vectorIndex = settings.getVectorIndex();
|
|
1465
1875
|
if (vectorIndex === null) throw new Error("vector-store: the settings file has no vector index");
|
|
1876
|
+
const records = new RecordsProvider(router, this.ctx.logger.child("Records"));
|
|
1877
|
+
await records.init();
|
|
1878
|
+
this.startRecordsSweep(records);
|
|
1466
1879
|
this.ctx.logger.info("Initialized successfully");
|
|
1467
1880
|
return [
|
|
1468
1881
|
{
|
|
1469
1882
|
capability: dataStoreProviderCapability,
|
|
1470
1883
|
provider: router
|
|
1471
1884
|
},
|
|
1885
|
+
{
|
|
1886
|
+
capability: recordsCapability,
|
|
1887
|
+
provider: records
|
|
1888
|
+
},
|
|
1472
1889
|
{
|
|
1473
1890
|
capability: vectorStoreCapability,
|
|
1474
1891
|
provider: vectorProviderOf(vectorIndex)
|
|
@@ -1479,7 +1896,7 @@ var SqliteSettingsAddon = class extends BaseAddon {
|
|
|
1479
1896
|
},
|
|
1480
1897
|
{
|
|
1481
1898
|
capability: storageAdminCapability,
|
|
1482
|
-
provider: new StorageAdminProvider(settings.backend, this.ctx.logger.child("StorageAdmin"), async () => new Set((await this.ctx.api.addons.list.query()).map((addon) => addon.manifest.id)))
|
|
1899
|
+
provider: new StorageAdminProvider(settings.backend, this.ctx.logger.child("StorageAdmin"), async () => new Set((await this.ctx.api.addons.list.query()).map((addon) => addon.manifest.id)), records)
|
|
1483
1900
|
}
|
|
1484
1901
|
];
|
|
1485
1902
|
}
|
|
@@ -1496,7 +1913,31 @@ var SqliteSettingsAddon = class extends BaseAddon {
|
|
|
1496
1913
|
}
|
|
1497
1914
|
await purgeRetiredCollections(retiredCollectionStoreOfFile(file), this.ctx.logger.child("RetiredCollections").withTags({ database: file.databaseId }));
|
|
1498
1915
|
}
|
|
1916
|
+
/**
|
|
1917
|
+
* The engine's TTL sweep (D881): every 10 minutes, off the boot path (the
|
|
1918
|
+
* first run a minute after boot), batched and yielding. A failed pass is
|
|
1919
|
+
* warned about and the next one retries; it never blocks anything.
|
|
1920
|
+
*/
|
|
1921
|
+
startRecordsSweep(records) {
|
|
1922
|
+
const run = () => {
|
|
1923
|
+
records.sweepExpired().then((deleted) => {
|
|
1924
|
+
if (deleted > 0) this.ctx.logger.info("records: expired rows swept", { meta: { deleted } });
|
|
1925
|
+
}).catch((err) => {
|
|
1926
|
+
this.ctx.logger.warn("records: expiry sweep failed", { meta: { error: errMsg(err) } });
|
|
1927
|
+
});
|
|
1928
|
+
};
|
|
1929
|
+
this.sweepStart = setTimeout(() => {
|
|
1930
|
+
run();
|
|
1931
|
+
this.sweepTimer = setInterval(run, RECORD_SWEEP_INTERVAL_MS);
|
|
1932
|
+
this.sweepTimer.unref();
|
|
1933
|
+
}, 6e4);
|
|
1934
|
+
this.sweepStart.unref();
|
|
1935
|
+
}
|
|
1499
1936
|
async onShutdown() {
|
|
1937
|
+
if (this.sweepStart !== null) clearTimeout(this.sweepStart);
|
|
1938
|
+
if (this.sweepTimer !== null) clearInterval(this.sweepTimer);
|
|
1939
|
+
this.sweepStart = null;
|
|
1940
|
+
this.sweepTimer = null;
|
|
1500
1941
|
const files = this.router?.openFiles() ?? [];
|
|
1501
1942
|
for (const file of files.toReversed()) try {
|
|
1502
1943
|
await file.stop();
|
|
@@ -7,13 +7,27 @@
|
|
|
7
7
|
* capability's method, once the last hub ran `migrate-device-store.ts --drop`.
|
|
8
8
|
*/
|
|
9
9
|
import { type IScopedLogger, type IStorageAdminProvider, type StorageTable } from "@camstack/types";
|
|
10
|
+
import type { RecordsProvider } from "./records/records-provider.js";
|
|
10
11
|
import type { SqliteSettingsBackend } from "./sqlite-settings-backend.js";
|
|
11
12
|
export declare class StorageAdminProvider implements IStorageAdminProvider {
|
|
12
13
|
private readonly backend;
|
|
13
14
|
private readonly logger;
|
|
14
15
|
/** The addon ids installed on this hub; a throw means "cannot tell" and refuses the drop. */
|
|
15
16
|
private readonly installedOwners;
|
|
16
|
-
|
|
17
|
+
/** The records provider the System -> Data and migration methods delegate to (D881). */
|
|
18
|
+
private readonly records;
|
|
19
|
+
constructor(backend: SqliteSettingsBackend, logger: IScopedLogger, installedOwners: () => Promise<ReadonlySet<string>>, records: Pick<RecordsProvider, "listKinds" | "readRecords" | "adoptRecords" | "isAdoptedLegacyTable">);
|
|
20
|
+
listKinds(input: Parameters<IStorageAdminProvider["listKinds"]>[0]): ReturnType<IStorageAdminProvider["listKinds"]>;
|
|
21
|
+
readRecords(input: Parameters<IStorageAdminProvider["readRecords"]>[0]): ReturnType<IStorageAdminProvider["readRecords"]>;
|
|
22
|
+
adoptRecords(input: Parameters<IStorageAdminProvider["adoptRecords"]>[0]): ReturnType<IStorageAdminProvider["adoptRecords"]>;
|
|
23
|
+
isAdoptedLegacyTable(input: {
|
|
24
|
+
collection: string;
|
|
25
|
+
}): ReturnType<IStorageAdminProvider["isAdoptedLegacyTable"]>;
|
|
26
|
+
readLegacyCollection(input: {
|
|
27
|
+
collection: string;
|
|
28
|
+
cursor?: string | undefined;
|
|
29
|
+
limit?: number | undefined;
|
|
30
|
+
}): ReturnType<IStorageAdminProvider["readLegacyCollection"]>;
|
|
17
31
|
/** May this table be dropped AT ALL? Throws with the reason when not. */
|
|
18
32
|
private assertDroppable;
|
|
19
33
|
listTables(input: {
|
|
@@ -8,14 +8,17 @@
|
|
|
8
8
|
* on every sweep, through the same `settings-store` door the location table
|
|
9
9
|
* uses.
|
|
10
10
|
*/
|
|
11
|
-
import type { ISettingsStoreProvider } from "@camstack/types";
|
|
11
|
+
import type { ISettingsStoreProvider, RecordKindHandle, RecordsAccess } from "@camstack/types";
|
|
12
12
|
import type { DrainState } from "./drain-ratchet.js";
|
|
13
|
+
import { type StorageDrainStateBody } from "./record-kinds.js";
|
|
13
14
|
import type { DrainStateStore } from "./storage-pressure-manager.js";
|
|
14
15
|
/** {@link DrainStateStore} on the `settings-store` collection surface. */
|
|
15
16
|
export declare class SqliteDrainStateStore implements DrainStateStore {
|
|
16
17
|
private readonly store;
|
|
17
18
|
private declared;
|
|
18
|
-
|
|
19
|
+
private readonly drainKind;
|
|
20
|
+
constructor(store: ISettingsStoreProvider, drainKind?: RecordKindHandle<StorageDrainStateBody> | null);
|
|
21
|
+
static recordStoresOf(records: Pick<RecordsAccess, "kind">): RecordKindHandle<StorageDrainStateBody>;
|
|
19
22
|
private ensureDeclared;
|
|
20
23
|
load(): Promise<readonly DrainState[]>;
|
|
21
24
|
save(state: DrainState): Promise<void>;
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* tests pass a fake (in-memory `Map`-backed) implementation. Same
|
|
8
8
|
* pattern as `IntegrationRegistry` in `sqlite-storage/`.
|
|
9
9
|
*/
|
|
10
|
-
import type { ISettingsStoreProvider, LegacyStorageLocationDefault, StorageLocation } from "@camstack/types";
|
|
10
|
+
import type { ISettingsStoreProvider, LegacyStorageLocationDefault, RecordKindHandle, RecordsAccess, StorageLocation } from "@camstack/types";
|
|
11
|
+
import { type StorageLocationBody } from "./record-kinds.js";
|
|
11
12
|
/**
|
|
12
13
|
* A location as it comes back OFF DISK: the live record plus the retired
|
|
13
14
|
* `isDefault` column, which exists only so the orchestrator's boot migration
|
|
@@ -47,7 +48,9 @@ export declare const STORAGE_LOCATIONS = "storage_locations";
|
|
|
47
48
|
export declare class SqliteLocationStore implements ILocationStore {
|
|
48
49
|
private readonly store;
|
|
49
50
|
private declared;
|
|
50
|
-
|
|
51
|
+
private readonly locationsKind;
|
|
52
|
+
constructor(store: ISettingsStoreProvider, locationsKind?: RecordKindHandle<StorageLocationBody> | null);
|
|
53
|
+
static recordStoresOf(records: Pick<RecordsAccess, "kind">): RecordKindHandle<StorageLocationBody>;
|
|
51
54
|
/**
|
|
52
55
|
* Lazy `declareCollection` — keeps the constructor cheap and async-free.
|
|
53
56
|
* Called from every mutation/read path; `declareCollection` is idempotent
|
|
@@ -64,3 +67,5 @@ export declare class SqliteLocationStore implements ILocationStore {
|
|
|
64
67
|
upsert(loc: StorageLocation): Promise<void>;
|
|
65
68
|
delete(id: string): Promise<void>;
|
|
66
69
|
}
|
|
70
|
+
export declare function locationToBody(loc: StorageLocation): StorageLocationBody;
|
|
71
|
+
export declare function bodyToPersistedLocation(id: string, body: StorageLocationBody): PersistedStorageLocation | null;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Record kinds owned by storage-orchestrator (phase 4 — hub-main).
|
|
3
|
+
*/
|
|
4
|
+
import { StorageLocationModeSchema, StorageLocationTypeSchema, type DefinedRecordKind } from "@camstack/types";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
export declare const STORAGE_DRAIN_STATE_LEGACY = "storage_drain_state";
|
|
7
|
+
export type StorageLocationBody = {
|
|
8
|
+
readonly type: z.infer<typeof StorageLocationTypeSchema>;
|
|
9
|
+
readonly displayName: string;
|
|
10
|
+
readonly providerId: string;
|
|
11
|
+
readonly config: Record<string, unknown>;
|
|
12
|
+
readonly isSystem: boolean;
|
|
13
|
+
readonly createdAt: number;
|
|
14
|
+
readonly updatedAt: number;
|
|
15
|
+
readonly nodeId?: string;
|
|
16
|
+
readonly enabled?: boolean;
|
|
17
|
+
readonly mode?: z.infer<typeof StorageLocationModeSchema>;
|
|
18
|
+
readonly isDefault?: boolean;
|
|
19
|
+
};
|
|
20
|
+
export declare const StorageLocationBodySchema: z.ZodType<StorageLocationBody>;
|
|
21
|
+
export type StorageDrainStateBody = {
|
|
22
|
+
readonly locationId: string;
|
|
23
|
+
readonly startedAtMs: number;
|
|
24
|
+
readonly startBytes: number;
|
|
25
|
+
readonly capBytes: number;
|
|
26
|
+
readonly lastPeerBytes: number | null;
|
|
27
|
+
readonly lastSweepMs: number;
|
|
28
|
+
readonly observedGrowthBytes: number;
|
|
29
|
+
readonly observedElapsedMs: number;
|
|
30
|
+
};
|
|
31
|
+
export declare const StorageDrainStateBodySchema: z.ZodType<StorageDrainStateBody>;
|
|
32
|
+
export type StorageOrchestratorRecordKindsMap = {
|
|
33
|
+
readonly locations: DefinedRecordKind<z.ZodType<StorageLocationBody>>;
|
|
34
|
+
readonly "drain-state": DefinedRecordKind<z.ZodType<StorageDrainStateBody>>;
|
|
35
|
+
};
|
|
36
|
+
export declare const storageOrchestratorRecordKinds: StorageOrchestratorRecordKindsMap;
|
|
37
|
+
export declare const storageLocationsRecordKind: DefinedRecordKind<z.ZodType<StorageLocationBody>>;
|
|
38
|
+
export declare const storageDrainStateRecordKind: DefinedRecordKind<z.ZodType<StorageDrainStateBody>>;
|
|
@@ -2,6 +2,8 @@ import type { ProviderRegistration } from "@camstack/types";
|
|
|
2
2
|
import { BaseAddon } from "@camstack/types";
|
|
3
3
|
interface StorageOrchestratorConfig extends Record<string, unknown> {}
|
|
4
4
|
export declare class StorageOrchestratorAddon extends BaseAddon<StorageOrchestratorConfig> {
|
|
5
|
+
private locationsKind;
|
|
6
|
+
private drainStateKind;
|
|
5
7
|
private service;
|
|
6
8
|
private pressureManager;
|
|
7
9
|
private readonly locationBandMonitor;
|