@camstack/system 1.2.442 → 1.2.444

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/assets/record-entries/icon.svg +8 -0
  2. package/dist/addon-runner.js +41 -11
  3. package/dist/addon-runner.mjs +42 -12
  4. package/dist/addon-utils.js +1 -1
  5. package/dist/addon-utils.mjs +1 -1
  6. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  7. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  9. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  10. package/dist/builtins/alerts/alerts.addon.d.ts +10 -2
  11. package/dist/builtins/alerts/alerts.addon.js +43 -10
  12. package/dist/builtins/alerts/alerts.addon.mjs +43 -10
  13. package/dist/builtins/autotrack/index.js +1 -1
  14. package/dist/builtins/autotrack/index.mjs +1 -1
  15. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
  16. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
  17. package/dist/builtins/calendars/calendars.addon.js +1 -1
  18. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  19. package/dist/builtins/camera-grid/index.js +1 -1
  20. package/dist/builtins/camera-grid/index.mjs +1 -1
  21. package/dist/builtins/composer/composer.addon.js +2 -2
  22. package/dist/builtins/composer/composer.addon.mjs +2 -2
  23. package/dist/builtins/console-logging/index.js +1 -1
  24. package/dist/builtins/console-logging/index.mjs +1 -1
  25. package/dist/builtins/core-blocks/block-package.d.ts +4 -2
  26. package/dist/builtins/core-blocks/block-settings-store.d.ts +65 -19
  27. package/dist/builtins/core-blocks/core-blocks.addon.js +365 -38
  28. package/dist/builtins/core-blocks/core-blocks.addon.mjs +365 -38
  29. package/dist/builtins/device-manager/device-manager.addon.js +1 -1
  30. package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
  31. package/dist/builtins/hub-forwarder/index.js +1 -1
  32. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  33. package/dist/builtins/keychain/index.js +3 -3
  34. package/dist/builtins/keychain/index.mjs +3 -3
  35. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  36. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  37. package/dist/builtins/local-auth/local-auth.addon.js +2 -2
  38. package/dist/builtins/local-auth/local-auth.addon.mjs +2 -2
  39. package/dist/builtins/local-network/local-network.addon.js +2 -2
  40. package/dist/builtins/local-network/local-network.addon.mjs +2 -2
  41. package/dist/builtins/loki-logging/index.js +1 -1
  42. package/dist/builtins/loki-logging/index.mjs +1 -1
  43. package/dist/builtins/native-metrics/native-metrics.addon.js +2 -2
  44. package/dist/builtins/native-metrics/native-metrics.addon.mjs +2 -2
  45. package/dist/builtins/platform-probe/index.js +2 -2
  46. package/dist/builtins/platform-probe/index.mjs +2 -2
  47. package/dist/builtins/record-entries/entries-service.d.ts +42 -0
  48. package/dist/builtins/record-entries/index.d.ts +1 -0
  49. package/dist/builtins/record-entries/index.js +142 -0
  50. package/dist/builtins/record-entries/index.mjs +136 -0
  51. package/dist/builtins/record-entries/record-entries.addon.d.ts +13 -0
  52. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  53. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  54. package/dist/builtins/snapshot/index.js +1 -1
  55. package/dist/builtins/snapshot/index.mjs +1 -1
  56. package/dist/builtins/sqlite-storage/file-host-client.d.ts +2 -0
  57. package/dist/builtins/sqlite-storage/file-host-handlers.d.ts +4 -0
  58. package/dist/builtins/sqlite-storage/file-host-protocol.d.ts +7 -1
  59. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  60. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  61. package/dist/builtins/sqlite-storage/index.js +1 -1
  62. package/dist/builtins/sqlite-storage/index.mjs +1 -1
  63. package/dist/builtins/sqlite-storage/owned-sqlite-file.d.ts +7 -0
  64. package/dist/builtins/sqlite-storage/placement-router.d.ts +5 -0
  65. package/dist/builtins/sqlite-storage/records/records-catalog.d.ts +29 -0
  66. package/dist/builtins/sqlite-storage/records/records-engine-types.d.ts +46 -0
  67. package/dist/builtins/sqlite-storage/records/records-engine.d.ts +90 -0
  68. package/dist/builtins/sqlite-storage/records/records-explain.d.ts +18 -0
  69. package/dist/builtins/sqlite-storage/records/records-plan.d.ts +90 -0
  70. package/dist/builtins/sqlite-storage/records/records-probe.d.ts +33 -0
  71. package/dist/builtins/sqlite-storage/records/records-provider.d.ts +59 -0
  72. package/dist/builtins/sqlite-storage/records/records-rows.d.ts +46 -0
  73. package/dist/builtins/sqlite-storage/records/records-sql.d.ts +41 -0
  74. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +0 -10
  75. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +8 -0
  76. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +337 -4
  77. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +337 -4
  78. package/dist/builtins/sqlite-storage/storage-admin-provider.d.ts +7 -1
  79. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  80. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  81. package/dist/builtins/system-config/system-config.addon.js +2 -2
  82. package/dist/builtins/system-config/system-config.addon.mjs +2 -2
  83. package/dist/builtins/winston-logging/index.js +1 -1
  84. package/dist/builtins/winston-logging/index.mjs +1 -1
  85. package/dist/{composition-sources-CftPpY4O.mjs → composition-sources-C3rKncIF.mjs} +1 -1
  86. package/dist/{composition-sources-DmSEMtUD.js → composition-sources-NAPZddic.js} +1 -1
  87. package/dist/{constants-2iWQ-Nx-.mjs → constants-BKX2QnIg.mjs} +1 -1
  88. package/dist/{constants-b7kpjuO4.js → constants-BXiNEIeV.js} +1 -1
  89. package/dist/{device-ca-tKY_ZS9H.js → device-ca-DT9X2S6d.js} +1 -1
  90. package/dist/{device-ca-BJpYTAPg.mjs → device-ca-jxjSL8Ov.mjs} +1 -1
  91. package/dist/{dist-CyIHDLCg.js → dist-D1vECb_6.js} +1247 -120
  92. package/dist/{dist-DsrQYcLm.mjs → dist-DERK-gP5.mjs} +1068 -121
  93. package/dist/file-host-worker.js +11 -1
  94. package/dist/file-host-worker.mjs +11 -1
  95. package/dist/{hub-mdns-ciao-BS2akjWx.mjs → hub-mdns-ciao-CRaC97V0.mjs} +1 -1
  96. package/dist/{hub-mdns-ciao-Da-0NEyr.js → hub-mdns-ciao-Cah9GCIg.js} +1 -1
  97. package/dist/index.js +53 -21
  98. package/dist/index.mjs +54 -22
  99. package/dist/kernel/moleculer/records-api-transport.d.ts +9 -0
  100. package/dist/kernel/settings-view-types.d.ts +0 -7
  101. package/dist/{restore-archive-Cdf09dHm.js → restore-archive-Dy-qKTdF.js} +1 -1
  102. package/dist/{restore-archive-RaA3uZ7H.mjs → restore-archive-daKyE24F.mjs} +1 -1
  103. package/dist/{wal-maintenance-C-bmkDhm.js → wal-maintenance-dAv4IdzC.js} +0 -0
  104. package/dist/{wal-maintenance-DE8QrreK.mjs → wal-maintenance-zRc24mOC.mjs} +0 -0
  105. package/package.json +22 -1
  106. package/dist/{custom-action-registry-BKmoaqG0.js → custom-action-registry-COyb49zm.js} +1 -1
  107. package/dist/{custom-action-registry-CyUuhATc.mjs → custom-action-registry-stpC3Zy-.mjs} +1 -1
@@ -1,6 +1,6 @@
1
- import { Ar as errMsg, At as databaseSnapshotCapability, Ir as RUNTIME_DEFAULTS, J as STORAGE_ADMIN_SCOPED_BASES, S as DATA_STORE_DATABASES, b as DATABASE_SNAPSHOT_SUFFIX, er as storageAdminCapability, jr as BaseAddon, kt as dataStoreProviderCapability, pr as vectorStoreCapability, q as STORAGE_ADMIN_MOVED_COLLECTIONS, ut as bareAddonId, x as DATABASE_SNAPSHOT_TIMEOUT_MS, y as DATABASE_SNAPSHOT_PARTIAL_SUFFIX } from "../../dist-DsrQYcLm.mjs";
1
+ import { At as dataStoreProviderCapability, Br as DeclarationRefusedError, C as DATA_STORE_DATABASES, Fr as BaseAddon, J as STORAGE_ADMIN_MOVED_COLLECTIONS, Li as normalizeSecretOwner, Ln as recordsCapability, Pr as errMsg, Qr as RUNTIME_DEFAULTS, S as DATABASE_SNAPSHOT_TIMEOUT_MS, Wr as NoCallerError, Y as STORAGE_ADMIN_SCOPED_BASES, Yr as RECORD_SWEEP_INTERVAL_MS, b as DATABASE_SNAPSHOT_PARTIAL_SUFFIX, ci as UnknownRecordKindError, dt as bareAddonId, gr as vectorStoreCapability, jt as databaseSnapshotCapability, rr as storageAdminCapability, ti as RecordKindDeclarationSchema, x as DATABASE_SNAPSHOT_SUFFIX } from "../../dist-DERK-gP5.mjs";
2
2
  import { i as retiredKeyStoreOf, n as purgeRetiredSettingsKeys } from "../../retired-settings-keys-Bhwe4ymb.mjs";
3
- import { C as callData, S as callControl, T as controlTargetOf, _ 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 callVector, x as trustResult } from "../../wal-maintenance-DE8QrreK.mjs";
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-zRc24mOC.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,267 @@ var PlacementRouter = class {
1198
1226
  }
1199
1227
  };
1200
1228
  //#endregion
1229
+ //#region src/builtins/sqlite-storage/records/records-provider.ts
1230
+ /**
1231
+ * The `records` capability of the engine (D881): resolves WHO is calling and
1232
+ * WHICH file a kind lives in, then hands the call to that file's records engine.
1233
+ *
1234
+ * - **Owner** = the transport-stamped `callerAddonId` (as device-history's
1235
+ * `not-owner` and the keychain). It is never a field of any input; a call with
1236
+ * no stamp is refused `records/no-caller`.
1237
+ * - **Placement**: a kind's file is its declaration's `database`. The map is
1238
+ * rebuilt from each open file's own `_record_kinds` at boot and updated on
1239
+ * declaration. A kind declared for another file than the one it lives in is
1240
+ * refused (the engine never moves data, D853).
1241
+ * - **The boot guard**: after a declaration, a kind with `adoptsFrom` that is
1242
+ * EMPTY while its legacy table still holds rows is reported `adoptionPending`;
1243
+ * `ctx.records.declare` turns that into a refusal to start.
1244
+ */
1245
+ /** The caller the transport stamped, or a refusal. */
1246
+ function recordsCallerOf(input) {
1247
+ const raw = input !== null && typeof input === "object" ? Reflect.get(input, "callerAddonId") : void 0;
1248
+ if (typeof raw !== "string" || raw.length === 0) throw new NoCallerError("the call carries no caller identity; records are reached through ctx.records");
1249
+ return normalizeSecretOwner(raw);
1250
+ }
1251
+ function keyOf(owner, kind) {
1252
+ return `${owner}\u0000${kind}`;
1253
+ }
1254
+ var RecordsProvider = class {
1255
+ router;
1256
+ logger;
1257
+ placement = /* @__PURE__ */ new Map();
1258
+ constructor(router, logger) {
1259
+ this.router = router;
1260
+ this.logger = logger;
1261
+ }
1262
+ /** Rebuild the placement map from every open file's catalog. Call once, after the files are open. */
1263
+ async init() {
1264
+ this.placement.clear();
1265
+ for (const file of this.router.openFiles()) {
1266
+ if (file.databaseId === "history") continue;
1267
+ const kinds = await file.records("listKinds", {});
1268
+ for (const k of kinds) {
1269
+ if (k.state === "dropped") continue;
1270
+ const key = keyOf(k.owner, k.kind);
1271
+ const other = this.placement.get(key);
1272
+ 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`);
1273
+ this.placement.set(key, file.databaseId);
1274
+ }
1275
+ }
1276
+ this.logger.info("records: catalog loaded", { meta: { kinds: this.placement.size } });
1277
+ }
1278
+ fileOf(owner, kind) {
1279
+ const database = this.placement.get(keyOf(owner, kind));
1280
+ if (database === void 0) return Promise.reject(new UnknownRecordKindError(`"${owner}" declared no kind "${kind}"`));
1281
+ return this.router.recordsFileFor(database);
1282
+ }
1283
+ async declareKinds(input) {
1284
+ const owner = recordsCallerOf(input);
1285
+ const byDatabase = /* @__PURE__ */ new Map();
1286
+ for (const [kind, raw] of Object.entries(input.kinds)) {
1287
+ const declaration = RecordKindDeclarationSchema.parse(raw);
1288
+ const known = this.placement.get(keyOf(owner, kind));
1289
+ 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`);
1290
+ const group = byDatabase.get(declaration.database) ?? {};
1291
+ byDatabase.set(declaration.database, {
1292
+ ...group,
1293
+ [kind]: declaration
1294
+ });
1295
+ }
1296
+ const merged = {};
1297
+ for (const [database, kinds] of byDatabase) {
1298
+ const { kinds: results } = await (await this.router.recordsFileFor(database)).records("declareKinds", {
1299
+ owner,
1300
+ kinds
1301
+ });
1302
+ for (const [kind, result] of Object.entries(results)) {
1303
+ this.placement.set(keyOf(owner, kind), database);
1304
+ merged[kind] = result;
1305
+ }
1306
+ }
1307
+ return { kinds: await this.withAdoption(owner, input.kinds, merged) };
1308
+ }
1309
+ /** The boot guard: empty kind + a legacy table that still has rows = adoption pending. */
1310
+ async withAdoption(owner, declared, results) {
1311
+ const out = { ...results };
1312
+ for (const [kind, raw] of Object.entries(declared)) {
1313
+ const legacy = raw.adoptsFrom;
1314
+ const result = results[kind];
1315
+ if (legacy === void 0 || result === void 0) continue;
1316
+ if ((await (await this.fileOf(owner, kind)).records("adoptionState", {
1317
+ owner,
1318
+ kind
1319
+ })).adoptedAt !== null) continue;
1320
+ const legacyRows = await (await this.router.recordsFileFor("settings")).records("legacyRowCount", { table: legacy });
1321
+ if (legacyRows !== null && legacyRows > 0) out[kind] = {
1322
+ ...result,
1323
+ adoptionPending: {
1324
+ legacyTable: legacy,
1325
+ legacyRows
1326
+ }
1327
+ };
1328
+ }
1329
+ return out;
1330
+ }
1331
+ async get(input) {
1332
+ const owner = recordsCallerOf(input);
1333
+ return (await this.fileOf(owner, input.kind)).records("get", {
1334
+ ...input,
1335
+ owner
1336
+ });
1337
+ }
1338
+ async getMany(input) {
1339
+ const owner = recordsCallerOf(input);
1340
+ return (await this.fileOf(owner, input.kind)).records("getMany", {
1341
+ ...input,
1342
+ owner
1343
+ });
1344
+ }
1345
+ async secretRefs(input) {
1346
+ const owner = recordsCallerOf(input);
1347
+ return (await this.fileOf(owner, input.kind)).records("secretRefs", {
1348
+ ...input,
1349
+ owner
1350
+ });
1351
+ }
1352
+ async put(input) {
1353
+ const owner = recordsCallerOf(input);
1354
+ return (await this.fileOf(owner, input.kind)).records("put", {
1355
+ ...input,
1356
+ owner
1357
+ });
1358
+ }
1359
+ async putMany(input) {
1360
+ const owner = recordsCallerOf(input);
1361
+ return (await this.fileOf(owner, input.kind)).records("putMany", {
1362
+ ...input,
1363
+ owner
1364
+ });
1365
+ }
1366
+ async patch(input) {
1367
+ const owner = recordsCallerOf(input);
1368
+ return (await this.fileOf(owner, input.kind)).records("patch", {
1369
+ ...input,
1370
+ owner
1371
+ });
1372
+ }
1373
+ async delete(input) {
1374
+ const owner = recordsCallerOf(input);
1375
+ return (await this.fileOf(owner, input.kind)).records("delete", {
1376
+ ...input,
1377
+ owner
1378
+ });
1379
+ }
1380
+ async deleteMany(input) {
1381
+ const owner = recordsCallerOf(input);
1382
+ return (await this.fileOf(owner, input.kind)).records("deleteMany", {
1383
+ ...input,
1384
+ owner
1385
+ });
1386
+ }
1387
+ async query(input) {
1388
+ const owner = recordsCallerOf(input);
1389
+ return (await this.fileOf(owner, input.kind)).records("query", {
1390
+ ...input,
1391
+ owner
1392
+ });
1393
+ }
1394
+ async count(input) {
1395
+ const owner = recordsCallerOf(input);
1396
+ return (await this.fileOf(owner, input.kind)).records("count", {
1397
+ ...input,
1398
+ owner
1399
+ });
1400
+ }
1401
+ async histogram(input) {
1402
+ const owner = recordsCallerOf(input);
1403
+ return (await this.fileOf(owner, input.kind)).records("histogram", {
1404
+ ...input,
1405
+ owner
1406
+ });
1407
+ }
1408
+ async aggregate(input) {
1409
+ const owner = recordsCallerOf(input);
1410
+ return (await this.fileOf(owner, input.kind)).records("aggregate", {
1411
+ ...input,
1412
+ owner
1413
+ });
1414
+ }
1415
+ async deleteWhere(input) {
1416
+ const owner = recordsCallerOf(input);
1417
+ return (await this.fileOf(owner, input.kind)).records("deleteWhere", {
1418
+ ...input,
1419
+ owner
1420
+ });
1421
+ }
1422
+ async allocateId(input) {
1423
+ const owner = recordsCallerOf(input);
1424
+ return (await this.fileOf(owner, input.kind)).records("allocateId", {
1425
+ ...input,
1426
+ owner
1427
+ });
1428
+ }
1429
+ /** The D865 hook body: every file that holds kinds of this owner. */
1430
+ async deleteDevice(input) {
1431
+ const owner = recordsCallerOf(input);
1432
+ const deleted = {};
1433
+ const secretRefs = [];
1434
+ const databases = new Set([...this.placement.entries()].filter(([key]) => key.startsWith(`${owner}\u0000`)).map(([, database]) => database));
1435
+ for (const database of databases) {
1436
+ const result = await (await this.router.recordsFileFor(database)).records("deleteDevice", {
1437
+ ...input,
1438
+ owner
1439
+ });
1440
+ Object.assign(deleted, result.deleted);
1441
+ secretRefs.push(...result.secretRefs);
1442
+ }
1443
+ return {
1444
+ deleted,
1445
+ secretRefs
1446
+ };
1447
+ }
1448
+ async listKinds(input) {
1449
+ const kinds = [];
1450
+ for (const file of this.router.openFiles()) {
1451
+ if (file.databaseId === "history") continue;
1452
+ kinds.push(...await file.records("listKinds", input));
1453
+ }
1454
+ return { kinds };
1455
+ }
1456
+ async readRecords(input) {
1457
+ this.logger.info("records: admin read", { meta: {
1458
+ owner: input.owner,
1459
+ kind: input.kind,
1460
+ limit: input.limit
1461
+ } });
1462
+ return (await this.fileOf(input.owner, input.kind)).records("query", input);
1463
+ }
1464
+ async adoptRecords(input) {
1465
+ const file = await this.fileOf(input.owner, input.kind);
1466
+ const result = await file.records("putMany", input);
1467
+ if (input.complete === true) await file.records("markAdopted", {
1468
+ owner: input.owner,
1469
+ kind: input.kind
1470
+ });
1471
+ this.logger.warn("records: ADOPTED rows as their declared owner", { meta: {
1472
+ owner: input.owner,
1473
+ kind: input.kind,
1474
+ count: result.count,
1475
+ complete: input.complete === true
1476
+ } });
1477
+ return { adopted: result.count };
1478
+ }
1479
+ /** Housekeeping: delete rows past `expires_at` in every file that hosts kinds. */
1480
+ async sweepExpired() {
1481
+ let deleted = 0;
1482
+ for (const file of this.router.openFiles()) {
1483
+ if (file.databaseId === "history") continue;
1484
+ deleted += (await file.records("sweepExpired", {})).deleted;
1485
+ }
1486
+ return deleted;
1487
+ }
1488
+ };
1489
+ //#endregion
1201
1490
  //#region src/builtins/sqlite-storage/storage-admin-provider.ts
1202
1491
  /**
1203
1492
  * The `storage-admin` provider of the SQLite engine (D870): the operator's
@@ -1211,10 +1500,21 @@ var StorageAdminProvider = class {
1211
1500
  backend;
1212
1501
  logger;
1213
1502
  installedOwners;
1214
- constructor(backend, logger, installedOwners) {
1503
+ records;
1504
+ constructor(backend, logger, installedOwners, records) {
1215
1505
  this.backend = backend;
1216
1506
  this.logger = logger;
1217
1507
  this.installedOwners = installedOwners;
1508
+ this.records = records;
1509
+ }
1510
+ listKinds(input) {
1511
+ return this.records.listKinds(input);
1512
+ }
1513
+ readRecords(input) {
1514
+ return this.records.readRecords(input);
1515
+ }
1516
+ adoptRecords(input) {
1517
+ return this.records.adoptRecords(input);
1218
1518
  }
1219
1519
  /** May this table be dropped AT ALL? Throws with the reason when not. */
1220
1520
  async assertDroppable(collection) {
@@ -1407,6 +1707,8 @@ var DATABASE_FILE_NAMES = {
1407
1707
  var SqliteSettingsAddon = class extends BaseAddon {
1408
1708
  settingsFile = null;
1409
1709
  router = null;
1710
+ sweepTimer = null;
1711
+ sweepStart = null;
1410
1712
  constructor() {
1411
1713
  super({});
1412
1714
  }
@@ -1463,12 +1765,19 @@ var SqliteSettingsAddon = class extends BaseAddon {
1463
1765
  this.router = router;
1464
1766
  const vectorIndex = settings.getVectorIndex();
1465
1767
  if (vectorIndex === null) throw new Error("vector-store: the settings file has no vector index");
1768
+ const records = new RecordsProvider(router, this.ctx.logger.child("Records"));
1769
+ await records.init();
1770
+ this.startRecordsSweep(records);
1466
1771
  this.ctx.logger.info("Initialized successfully");
1467
1772
  return [
1468
1773
  {
1469
1774
  capability: dataStoreProviderCapability,
1470
1775
  provider: router
1471
1776
  },
1777
+ {
1778
+ capability: recordsCapability,
1779
+ provider: records
1780
+ },
1472
1781
  {
1473
1782
  capability: vectorStoreCapability,
1474
1783
  provider: vectorProviderOf(vectorIndex)
@@ -1479,7 +1788,7 @@ var SqliteSettingsAddon = class extends BaseAddon {
1479
1788
  },
1480
1789
  {
1481
1790
  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)))
1791
+ 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
1792
  }
1484
1793
  ];
1485
1794
  }
@@ -1496,7 +1805,31 @@ var SqliteSettingsAddon = class extends BaseAddon {
1496
1805
  }
1497
1806
  await purgeRetiredCollections(retiredCollectionStoreOfFile(file), this.ctx.logger.child("RetiredCollections").withTags({ database: file.databaseId }));
1498
1807
  }
1808
+ /**
1809
+ * The engine's TTL sweep (D881): every 10 minutes, off the boot path (the
1810
+ * first run a minute after boot), batched and yielding. A failed pass is
1811
+ * warned about and the next one retries; it never blocks anything.
1812
+ */
1813
+ startRecordsSweep(records) {
1814
+ const run = () => {
1815
+ records.sweepExpired().then((deleted) => {
1816
+ if (deleted > 0) this.ctx.logger.info("records: expired rows swept", { meta: { deleted } });
1817
+ }).catch((err) => {
1818
+ this.ctx.logger.warn("records: expiry sweep failed", { meta: { error: errMsg(err) } });
1819
+ });
1820
+ };
1821
+ this.sweepStart = setTimeout(() => {
1822
+ run();
1823
+ this.sweepTimer = setInterval(run, RECORD_SWEEP_INTERVAL_MS);
1824
+ this.sweepTimer.unref();
1825
+ }, 6e4);
1826
+ this.sweepStart.unref();
1827
+ }
1499
1828
  async onShutdown() {
1829
+ if (this.sweepStart !== null) clearTimeout(this.sweepStart);
1830
+ if (this.sweepTimer !== null) clearInterval(this.sweepTimer);
1831
+ this.sweepStart = null;
1832
+ this.sweepTimer = null;
1500
1833
  const files = this.router?.openFiles() ?? [];
1501
1834
  for (const file of files.toReversed()) try {
1502
1835
  await file.stop();
@@ -7,13 +7,19 @@
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
- constructor(backend: SqliteSettingsBackend, logger: IScopedLogger, installedOwners: () => Promise<ReadonlySet<string>>);
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">);
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"]>;
17
23
  /** May this table be dropped AT ALL? Throws with the reason when not. */
18
24
  private assertDroppable;
19
25
  listTables(input: {
@@ -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-CyIHDLCg.js");
6
+ const require_dist = require("../../dist-D1vECb_6.js");
7
7
  let zod = require("zod");
8
8
  let node_crypto = require("node:crypto");
9
9
  let _camstack_types_node = require("@camstack/types/node");
@@ -1,4 +1,4 @@
1
- import { $ as StorageCleanupJobSchema, $t as gbToBytes, Ci as EventCategory, Cn as modeMayWrite, Fr as REDACTED_SECRET, Gr as collectSecretConfigKeys, Gt as evictionPolicyOfLocation, Hn as resolveLocationMode, Yn as settingsStoreCapability, _i as secretTreeFromPaths, ai as isSecretMarker, an as isLocationEnabled, bn as mayWriteToLocation, et as StorageLocationModeSchema, fn as legacyModeOf, hi as resolveSecretMarkers, jr as BaseAddon, mr as withLocationMode, nr as storageMigrationCapability, nt as StorageMigrationJobSchema, tr as storageCapability, tt as StorageLocationTypeSchema, ui as parseJsonObject, xi as transformSecretWrite, yn as mayReadLocation, z as LegacyStorageLocationDefaultSchema } from "../../dist-DsrQYcLm.mjs";
1
+ import { $i as EventCategory, B as LegacyStorageLocationDefaultSchema, Fr as BaseAddon, Gn as resolveLocationMode, Ki as secretTreeFromPaths, Kt as evictionPolicyOfLocation, Qn as settingsStoreCapability, Ri as parseJsonObject, Wi as resolveSecretMarkers, Xr as REDACTED_SECRET, Zi as transformSecretWrite, _r as withLocationMode, ar as storageMigrationCapability, bn as mayReadLocation, en as gbToBytes, et as StorageCleanupJobSchema, hi as collectSecretConfigKeys, ir as storageCapability, ji as isSecretMarker, nt as StorageLocationTypeSchema, on as isLocationEnabled, pn as legacyModeOf, rt as StorageMigrationJobSchema, tt as StorageLocationModeSchema, wn as modeMayWrite, xn as mayWriteToLocation } from "../../dist-DERK-gP5.mjs";
2
2
  import { z } from "zod";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { containsOrEquals, physicalRootOf } from "@camstack/types/node";
@@ -3,11 +3,11 @@ 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-CyIHDLCg.js");
6
+ const require_dist = require("../../dist-D1vECb_6.js");
7
7
  const require_safe_buffer$1 = require("../../safe-buffer-D3aoa-7X.js");
8
8
  const require_x509_es = require("../../x509.es-C4cOo48M.js");
9
9
  const require_agent_https = require("../../agent-https-DlpTMDqA.js");
10
- const require_constants$8 = require("../../constants-b7kpjuO4.js");
10
+ const require_constants$8 = require("../../constants-BXiNEIeV.js");
11
11
  const require_src$1 = require("../../src-CnAqG6EF.js");
12
12
  let zod = require("zod");
13
13
  let node_crypto = require("node:crypto");
@@ -1,9 +1,9 @@
1
1
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "../../chunk-CNf5ZN-e.mjs";
2
- import { Ar as errMsg, Jr as customAction, Xn as shortHostname, Yr as defineCustomActions, Z as ServerNameSchema, ei as hydrateSchema, jr as BaseAddon } from "../../dist-DsrQYcLm.mjs";
2
+ import { $n as shortHostname, Ei as hydrateSchema, Fr as BaseAddon, Pr as errMsg, Q as ServerNameSchema, bi as customAction, xi as defineCustomActions } from "../../dist-DERK-gP5.mjs";
3
3
  import { t as require_safe_buffer } from "../../safe-buffer-B1OjL1I9.mjs";
4
4
  import { S as backdatedNotBefore, a as KeyUsageFlags, c as Pkcs10CertificateRequest, d as SubjectKeyIdentifierExtension, f as X509Certificate$1, l as Pkcs10CertificateRequestGenerator, m as cryptoProvider, n as BasicConstraintsExtension, o as KeyUsagesExtension, p as X509CertificateGenerator, r as ExtendedKeyUsageExtension, s as PemConverter, t as AuthorityKeyIdentifierExtension } from "../../x509.es-DK__ETIe.mjs";
5
5
  import { F as AGENT_HTTPS_NAMES_COLLECTION, I as AGENT_HTTPS_NAMES_COLUMNS, L as AgentHttpsNames, R as getProcessAgentHttpsNames, j as isLocalOnlyHostname, u as isPrivateAddress, z as setProcessAgentHttpsNames } from "../../agent-https-U0d4uvn2.mjs";
6
- import { a as MESH_CA_KEY_REF, c as SERVER_AUTH_OID, i as MESH_CA_FIELD, n as DEFAULT_HUB_TLS_TCP_PORT, o as MESH_CA_SETTINGS_KEY, r as MESH_CA_COMMON_NAME, s as MESH_CA_VALIDITY_DAYS, t as CLIENT_AUTH_OID } from "../../constants-2iWQ-Nx-.mjs";
6
+ import { a as MESH_CA_KEY_REF, c as SERVER_AUTH_OID, i as MESH_CA_FIELD, n as DEFAULT_HUB_TLS_TCP_PORT, o as MESH_CA_SETTINGS_KEY, r as MESH_CA_COMMON_NAME, s as MESH_CA_VALIDITY_DAYS, t as CLIENT_AUTH_OID } from "../../constants-BKX2QnIg.mjs";
7
7
  import { t as require_src } from "../../src-hG4grMU4.mjs";
8
8
  import { z } from "zod";
9
9
  import { X509Certificate, createHash, createPrivateKey, randomBytes, randomInt, sign, timingSafeEqual, verify, webcrypto } 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-CyIHDLCg.js");
6
+ const require_dist = require("../../dist-D1vECb_6.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 { gn as logDestinationCapability, jr as BaseAddon } from "../../dist-DsrQYcLm.mjs";
1
+ import { Fr as BaseAddon, _n as logDestinationCapability } from "../../dist-DERK-gP5.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 { Ar as errMsg, Cr as compositionSourceKey } from "./dist-DsrQYcLm.mjs";
1
+ import { Dr as compositionSourceKey, Pr as errMsg } from "./dist-DERK-gP5.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
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-CyIHDLCg.js");
1
+ const require_dist = require("./dist-D1vECb_6.js");
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
@@ -1,4 +1,4 @@
1
- import { Wr as buildSecretRef } from "./dist-DsrQYcLm.mjs";
1
+ import { mi as buildSecretRef } from "./dist-DERK-gP5.mjs";
2
2
  /** `secret://system/global/meshCaKey` — EC P-256 PKCS#8 PEM of the hub mesh CA. */
3
3
  var MESH_CA_KEY_REF = buildSecretRef({
4
4
  owner: "system",
@@ -1,5 +1,5 @@
1
1
  /** `secret://system/global/meshCaKey` — EC P-256 PKCS#8 PEM of the hub mesh CA. */
2
- var MESH_CA_KEY_REF = require("./dist-CyIHDLCg.js").buildSecretRef({
2
+ var MESH_CA_KEY_REF = require("./dist-D1vECb_6.js").buildSecretRef({
3
3
  owner: "system",
4
4
  scope: { kind: "global" },
5
5
  fieldPath: "meshCaKey"
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-CyIHDLCg.js");
1
+ const require_dist = require("./dist-D1vECb_6.js");
2
2
  const require_x509_es = require("./x509.es-C4cOo48M.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  //#region src/auth/jwt-signing-key.ts
@@ -1,4 +1,4 @@
1
- import { D as DEVICE_SAN_CREDENTIAL_PREFIX, O as DEVICE_SAN_USER_PREFIX, Wr as buildSecretRef } from "./dist-DsrQYcLm.mjs";
1
+ import { O as DEVICE_SAN_CREDENTIAL_PREFIX, k as DEVICE_SAN_USER_PREFIX, mi as buildSecretRef } from "./dist-DERK-gP5.mjs";
2
2
  import { S as backdatedNotBefore, a as KeyUsageFlags, d as SubjectKeyIdentifierExtension, f as X509Certificate$1, m as cryptoProvider, n as BasicConstraintsExtension, o as KeyUsagesExtension, p as X509CertificateGenerator, r as ExtendedKeyUsageExtension, s as PemConverter, t as AuthorityKeyIdentifierExtension, u as SubjectAlternativeNameExtension } from "./x509.es-DK__ETIe.mjs";
3
3
  import { X509Certificate, createPublicKey, randomBytes, verify, webcrypto } from "node:crypto";
4
4
  //#region src/auth/jwt-signing-key.ts