@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
@@ -3,9 +3,9 @@ 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_retired_settings_keys = require("../../retired-settings-keys-D_VwZiDt.js");
8
- const require_wal_maintenance = require("../../wal-maintenance-C-bmkDhm.js");
8
+ const require_wal_maintenance = require("../../wal-maintenance-dAv4IdzC.js");
9
9
  const require_sqlite_snapshot_protocol = require("../../sqlite-snapshot-protocol-B9OndqZv.js");
10
10
  const require_wal_checkpoint_policy = require("../../wal-checkpoint-policy-d2z2qPqx.js");
11
11
  let node_fs_promises = require("node:fs/promises");
@@ -107,6 +107,13 @@ var FileHostClient = class {
107
107
  input
108
108
  });
109
109
  }
110
+ records(op, input) {
111
+ return this.request({
112
+ kind: "records",
113
+ op,
114
+ input
115
+ });
116
+ }
110
117
  control(op, input) {
111
118
  return this.request({
112
119
  kind: "control",
@@ -869,6 +876,7 @@ var InlineOwnedFile = class extends OwnedFileBase {
869
876
  vectorIndex = null;
870
877
  vectorProvider = null;
871
878
  maintenance = null;
879
+ recordsEngine = null;
872
880
  constructor(spec, deps) {
873
881
  super(spec, deps);
874
882
  this.backend = new require_wal_maintenance.SqliteSettingsBackend(spec.livePath, deps.runtimeDefaults === void 0 ? {} : { ...deps.runtimeDefaults }, this.log("Query"), {
@@ -886,6 +894,11 @@ var InlineOwnedFile = class extends OwnedFileBase {
886
894
  this.vectorIndex = vectorIndex;
887
895
  this.vectorProvider = require_wal_maintenance.vectorProviderOf(vectorIndex);
888
896
  }
897
+ const handle = this.backend.getDatabase();
898
+ if (handle !== null) this.recordsEngine = new require_wal_maintenance.RecordsEngine(handle, {
899
+ databaseId: this.spec.databaseId,
900
+ logger: this.log("Records")
901
+ });
889
902
  await this.deps.afterOpen?.(this);
890
903
  const db = this.backend.getDatabase();
891
904
  if (db !== null) {
@@ -907,6 +920,10 @@ var InlineOwnedFile = class extends OwnedFileBase {
907
920
  if (op === "declareCollection") this.declared = this.backend.declaredCollectionNames();
908
921
  return result;
909
922
  }
923
+ async records(op, input) {
924
+ if (this.recordsEngine === null) throw new Error(`database "${this.databaseId}" is not open`);
925
+ return require_wal_maintenance.callRecords(this.recordsEngine, op, input);
926
+ }
910
927
  async vector(op, input) {
911
928
  if (this.vectorProvider === null) throw new Error(`database "${this.databaseId}" does not serve vector calls`);
912
929
  return require_wal_maintenance.callVector(this.vectorProvider, op, input);
@@ -962,6 +979,9 @@ var WorkerOwnedFile = class extends OwnedFileBase {
962
979
  vector(op, input) {
963
980
  return this.client.vector(op, input);
964
981
  }
982
+ records(op, input) {
983
+ return this.client.records(op, input);
984
+ }
965
985
  declaredCollections() {
966
986
  return this.client.declaredCollections();
967
987
  }
@@ -1094,6 +1114,14 @@ var PlacementRouter = class {
1094
1114
  databaseOf(table) {
1095
1115
  return this.placement.get(table) ?? "settings";
1096
1116
  }
1117
+ /**
1118
+ * The file that hosts records of `databaseId`, created by the first
1119
+ * declaration that names it (`events`). `history` never hosts records.
1120
+ */
1121
+ async recordsFileFor(databaseId) {
1122
+ if (databaseId === "history") throw new Error("placement: history.db is device-history's and never hosts records");
1123
+ return this.openFile(databaseId);
1124
+ }
1097
1125
  /** The files currently open, settings first. */
1098
1126
  openFiles() {
1099
1127
  return require_dist.DATA_STORE_DATABASES.flatMap((id) => {
@@ -1204,6 +1232,267 @@ var PlacementRouter = class {
1204
1232
  }
1205
1233
  };
1206
1234
  //#endregion
1235
+ //#region src/builtins/sqlite-storage/records/records-provider.ts
1236
+ /**
1237
+ * The `records` capability of the engine (D881): resolves WHO is calling and
1238
+ * WHICH file a kind lives in, then hands the call to that file's records engine.
1239
+ *
1240
+ * - **Owner** = the transport-stamped `callerAddonId` (as device-history's
1241
+ * `not-owner` and the keychain). It is never a field of any input; a call with
1242
+ * no stamp is refused `records/no-caller`.
1243
+ * - **Placement**: a kind's file is its declaration's `database`. The map is
1244
+ * rebuilt from each open file's own `_record_kinds` at boot and updated on
1245
+ * declaration. A kind declared for another file than the one it lives in is
1246
+ * refused (the engine never moves data, D853).
1247
+ * - **The boot guard**: after a declaration, a kind with `adoptsFrom` that is
1248
+ * EMPTY while its legacy table still holds rows is reported `adoptionPending`;
1249
+ * `ctx.records.declare` turns that into a refusal to start.
1250
+ */
1251
+ /** The caller the transport stamped, or a refusal. */
1252
+ function recordsCallerOf(input) {
1253
+ const raw = input !== null && typeof input === "object" ? Reflect.get(input, "callerAddonId") : void 0;
1254
+ if (typeof raw !== "string" || raw.length === 0) throw new require_dist.NoCallerError("the call carries no caller identity; records are reached through ctx.records");
1255
+ return require_dist.normalizeSecretOwner(raw);
1256
+ }
1257
+ function keyOf(owner, kind) {
1258
+ return `${owner}\u0000${kind}`;
1259
+ }
1260
+ var RecordsProvider = class {
1261
+ router;
1262
+ logger;
1263
+ placement = /* @__PURE__ */ new Map();
1264
+ constructor(router, logger) {
1265
+ this.router = router;
1266
+ this.logger = logger;
1267
+ }
1268
+ /** Rebuild the placement map from every open file's catalog. Call once, after the files are open. */
1269
+ async init() {
1270
+ this.placement.clear();
1271
+ for (const file of this.router.openFiles()) {
1272
+ if (file.databaseId === "history") continue;
1273
+ const kinds = await file.records("listKinds", {});
1274
+ for (const k of kinds) {
1275
+ if (k.state === "dropped") continue;
1276
+ const key = keyOf(k.owner, k.kind);
1277
+ const other = this.placement.get(key);
1278
+ if (other !== void 0 && other !== file.databaseId) throw new require_dist.DeclarationRefusedError(`kind "${k.kind}" of "${k.owner}" is in both "${other}" and "${file.databaseId}"; the layout is corrupt and is not served`);
1279
+ this.placement.set(key, file.databaseId);
1280
+ }
1281
+ }
1282
+ this.logger.info("records: catalog loaded", { meta: { kinds: this.placement.size } });
1283
+ }
1284
+ fileOf(owner, kind) {
1285
+ const database = this.placement.get(keyOf(owner, kind));
1286
+ if (database === void 0) return Promise.reject(new require_dist.UnknownRecordKindError(`"${owner}" declared no kind "${kind}"`));
1287
+ return this.router.recordsFileFor(database);
1288
+ }
1289
+ async declareKinds(input) {
1290
+ const owner = recordsCallerOf(input);
1291
+ const byDatabase = /* @__PURE__ */ new Map();
1292
+ for (const [kind, raw] of Object.entries(input.kinds)) {
1293
+ const declaration = require_dist.RecordKindDeclarationSchema.parse(raw);
1294
+ const known = this.placement.get(keyOf(owner, kind));
1295
+ if (known !== void 0 && known !== declaration.database) throw new require_dist.DeclarationRefusedError(`kind "${kind}" of "${owner}" lives in "${known}", declared for "${declaration.database}" - the engine never moves data`);
1296
+ const group = byDatabase.get(declaration.database) ?? {};
1297
+ byDatabase.set(declaration.database, {
1298
+ ...group,
1299
+ [kind]: declaration
1300
+ });
1301
+ }
1302
+ const merged = {};
1303
+ for (const [database, kinds] of byDatabase) {
1304
+ const { kinds: results } = await (await this.router.recordsFileFor(database)).records("declareKinds", {
1305
+ owner,
1306
+ kinds
1307
+ });
1308
+ for (const [kind, result] of Object.entries(results)) {
1309
+ this.placement.set(keyOf(owner, kind), database);
1310
+ merged[kind] = result;
1311
+ }
1312
+ }
1313
+ return { kinds: await this.withAdoption(owner, input.kinds, merged) };
1314
+ }
1315
+ /** The boot guard: empty kind + a legacy table that still has rows = adoption pending. */
1316
+ async withAdoption(owner, declared, results) {
1317
+ const out = { ...results };
1318
+ for (const [kind, raw] of Object.entries(declared)) {
1319
+ const legacy = raw.adoptsFrom;
1320
+ const result = results[kind];
1321
+ if (legacy === void 0 || result === void 0) continue;
1322
+ if ((await (await this.fileOf(owner, kind)).records("adoptionState", {
1323
+ owner,
1324
+ kind
1325
+ })).adoptedAt !== null) continue;
1326
+ const legacyRows = await (await this.router.recordsFileFor("settings")).records("legacyRowCount", { table: legacy });
1327
+ if (legacyRows !== null && legacyRows > 0) out[kind] = {
1328
+ ...result,
1329
+ adoptionPending: {
1330
+ legacyTable: legacy,
1331
+ legacyRows
1332
+ }
1333
+ };
1334
+ }
1335
+ return out;
1336
+ }
1337
+ async get(input) {
1338
+ const owner = recordsCallerOf(input);
1339
+ return (await this.fileOf(owner, input.kind)).records("get", {
1340
+ ...input,
1341
+ owner
1342
+ });
1343
+ }
1344
+ async getMany(input) {
1345
+ const owner = recordsCallerOf(input);
1346
+ return (await this.fileOf(owner, input.kind)).records("getMany", {
1347
+ ...input,
1348
+ owner
1349
+ });
1350
+ }
1351
+ async secretRefs(input) {
1352
+ const owner = recordsCallerOf(input);
1353
+ return (await this.fileOf(owner, input.kind)).records("secretRefs", {
1354
+ ...input,
1355
+ owner
1356
+ });
1357
+ }
1358
+ async put(input) {
1359
+ const owner = recordsCallerOf(input);
1360
+ return (await this.fileOf(owner, input.kind)).records("put", {
1361
+ ...input,
1362
+ owner
1363
+ });
1364
+ }
1365
+ async putMany(input) {
1366
+ const owner = recordsCallerOf(input);
1367
+ return (await this.fileOf(owner, input.kind)).records("putMany", {
1368
+ ...input,
1369
+ owner
1370
+ });
1371
+ }
1372
+ async patch(input) {
1373
+ const owner = recordsCallerOf(input);
1374
+ return (await this.fileOf(owner, input.kind)).records("patch", {
1375
+ ...input,
1376
+ owner
1377
+ });
1378
+ }
1379
+ async delete(input) {
1380
+ const owner = recordsCallerOf(input);
1381
+ return (await this.fileOf(owner, input.kind)).records("delete", {
1382
+ ...input,
1383
+ owner
1384
+ });
1385
+ }
1386
+ async deleteMany(input) {
1387
+ const owner = recordsCallerOf(input);
1388
+ return (await this.fileOf(owner, input.kind)).records("deleteMany", {
1389
+ ...input,
1390
+ owner
1391
+ });
1392
+ }
1393
+ async query(input) {
1394
+ const owner = recordsCallerOf(input);
1395
+ return (await this.fileOf(owner, input.kind)).records("query", {
1396
+ ...input,
1397
+ owner
1398
+ });
1399
+ }
1400
+ async count(input) {
1401
+ const owner = recordsCallerOf(input);
1402
+ return (await this.fileOf(owner, input.kind)).records("count", {
1403
+ ...input,
1404
+ owner
1405
+ });
1406
+ }
1407
+ async histogram(input) {
1408
+ const owner = recordsCallerOf(input);
1409
+ return (await this.fileOf(owner, input.kind)).records("histogram", {
1410
+ ...input,
1411
+ owner
1412
+ });
1413
+ }
1414
+ async aggregate(input) {
1415
+ const owner = recordsCallerOf(input);
1416
+ return (await this.fileOf(owner, input.kind)).records("aggregate", {
1417
+ ...input,
1418
+ owner
1419
+ });
1420
+ }
1421
+ async deleteWhere(input) {
1422
+ const owner = recordsCallerOf(input);
1423
+ return (await this.fileOf(owner, input.kind)).records("deleteWhere", {
1424
+ ...input,
1425
+ owner
1426
+ });
1427
+ }
1428
+ async allocateId(input) {
1429
+ const owner = recordsCallerOf(input);
1430
+ return (await this.fileOf(owner, input.kind)).records("allocateId", {
1431
+ ...input,
1432
+ owner
1433
+ });
1434
+ }
1435
+ /** The D865 hook body: every file that holds kinds of this owner. */
1436
+ async deleteDevice(input) {
1437
+ const owner = recordsCallerOf(input);
1438
+ const deleted = {};
1439
+ const secretRefs = [];
1440
+ const databases = new Set([...this.placement.entries()].filter(([key]) => key.startsWith(`${owner}\u0000`)).map(([, database]) => database));
1441
+ for (const database of databases) {
1442
+ const result = await (await this.router.recordsFileFor(database)).records("deleteDevice", {
1443
+ ...input,
1444
+ owner
1445
+ });
1446
+ Object.assign(deleted, result.deleted);
1447
+ secretRefs.push(...result.secretRefs);
1448
+ }
1449
+ return {
1450
+ deleted,
1451
+ secretRefs
1452
+ };
1453
+ }
1454
+ async listKinds(input) {
1455
+ const kinds = [];
1456
+ for (const file of this.router.openFiles()) {
1457
+ if (file.databaseId === "history") continue;
1458
+ kinds.push(...await file.records("listKinds", input));
1459
+ }
1460
+ return { kinds };
1461
+ }
1462
+ async readRecords(input) {
1463
+ this.logger.info("records: admin read", { meta: {
1464
+ owner: input.owner,
1465
+ kind: input.kind,
1466
+ limit: input.limit
1467
+ } });
1468
+ return (await this.fileOf(input.owner, input.kind)).records("query", input);
1469
+ }
1470
+ async adoptRecords(input) {
1471
+ const file = await this.fileOf(input.owner, input.kind);
1472
+ const result = await file.records("putMany", input);
1473
+ if (input.complete === true) await file.records("markAdopted", {
1474
+ owner: input.owner,
1475
+ kind: input.kind
1476
+ });
1477
+ this.logger.warn("records: ADOPTED rows as their declared owner", { meta: {
1478
+ owner: input.owner,
1479
+ kind: input.kind,
1480
+ count: result.count,
1481
+ complete: input.complete === true
1482
+ } });
1483
+ return { adopted: result.count };
1484
+ }
1485
+ /** Housekeeping: delete rows past `expires_at` in every file that hosts kinds. */
1486
+ async sweepExpired() {
1487
+ let deleted = 0;
1488
+ for (const file of this.router.openFiles()) {
1489
+ if (file.databaseId === "history") continue;
1490
+ deleted += (await file.records("sweepExpired", {})).deleted;
1491
+ }
1492
+ return deleted;
1493
+ }
1494
+ };
1495
+ //#endregion
1207
1496
  //#region src/builtins/sqlite-storage/storage-admin-provider.ts
1208
1497
  /**
1209
1498
  * The `storage-admin` provider of the SQLite engine (D870): the operator's
@@ -1217,10 +1506,21 @@ var StorageAdminProvider = class {
1217
1506
  backend;
1218
1507
  logger;
1219
1508
  installedOwners;
1220
- constructor(backend, logger, installedOwners) {
1509
+ records;
1510
+ constructor(backend, logger, installedOwners, records) {
1221
1511
  this.backend = backend;
1222
1512
  this.logger = logger;
1223
1513
  this.installedOwners = installedOwners;
1514
+ this.records = records;
1515
+ }
1516
+ listKinds(input) {
1517
+ return this.records.listKinds(input);
1518
+ }
1519
+ readRecords(input) {
1520
+ return this.records.readRecords(input);
1521
+ }
1522
+ adoptRecords(input) {
1523
+ return this.records.adoptRecords(input);
1224
1524
  }
1225
1525
  /** May this table be dropped AT ALL? Throws with the reason when not. */
1226
1526
  async assertDroppable(collection) {
@@ -1413,6 +1713,8 @@ var DATABASE_FILE_NAMES = {
1413
1713
  var SqliteSettingsAddon = class extends require_dist.BaseAddon {
1414
1714
  settingsFile = null;
1415
1715
  router = null;
1716
+ sweepTimer = null;
1717
+ sweepStart = null;
1416
1718
  constructor() {
1417
1719
  super({});
1418
1720
  }
@@ -1469,12 +1771,19 @@ var SqliteSettingsAddon = class extends require_dist.BaseAddon {
1469
1771
  this.router = router;
1470
1772
  const vectorIndex = settings.getVectorIndex();
1471
1773
  if (vectorIndex === null) throw new Error("vector-store: the settings file has no vector index");
1774
+ const records = new RecordsProvider(router, this.ctx.logger.child("Records"));
1775
+ await records.init();
1776
+ this.startRecordsSweep(records);
1472
1777
  this.ctx.logger.info("Initialized successfully");
1473
1778
  return [
1474
1779
  {
1475
1780
  capability: require_dist.dataStoreProviderCapability,
1476
1781
  provider: router
1477
1782
  },
1783
+ {
1784
+ capability: require_dist.recordsCapability,
1785
+ provider: records
1786
+ },
1478
1787
  {
1479
1788
  capability: require_dist.vectorStoreCapability,
1480
1789
  provider: require_wal_maintenance.vectorProviderOf(vectorIndex)
@@ -1485,7 +1794,7 @@ var SqliteSettingsAddon = class extends require_dist.BaseAddon {
1485
1794
  },
1486
1795
  {
1487
1796
  capability: require_dist.storageAdminCapability,
1488
- 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)))
1797
+ 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)
1489
1798
  }
1490
1799
  ];
1491
1800
  }
@@ -1502,7 +1811,31 @@ var SqliteSettingsAddon = class extends require_dist.BaseAddon {
1502
1811
  }
1503
1812
  await purgeRetiredCollections(retiredCollectionStoreOfFile(file), this.ctx.logger.child("RetiredCollections").withTags({ database: file.databaseId }));
1504
1813
  }
1814
+ /**
1815
+ * The engine's TTL sweep (D881): every 10 minutes, off the boot path (the
1816
+ * first run a minute after boot), batched and yielding. A failed pass is
1817
+ * warned about and the next one retries; it never blocks anything.
1818
+ */
1819
+ startRecordsSweep(records) {
1820
+ const run = () => {
1821
+ records.sweepExpired().then((deleted) => {
1822
+ if (deleted > 0) this.ctx.logger.info("records: expired rows swept", { meta: { deleted } });
1823
+ }).catch((err) => {
1824
+ this.ctx.logger.warn("records: expiry sweep failed", { meta: { error: require_dist.errMsg(err) } });
1825
+ });
1826
+ };
1827
+ this.sweepStart = setTimeout(() => {
1828
+ run();
1829
+ this.sweepTimer = setInterval(run, require_dist.RECORD_SWEEP_INTERVAL_MS);
1830
+ this.sweepTimer.unref();
1831
+ }, 6e4);
1832
+ this.sweepStart.unref();
1833
+ }
1505
1834
  async onShutdown() {
1835
+ if (this.sweepStart !== null) clearTimeout(this.sweepStart);
1836
+ if (this.sweepTimer !== null) clearInterval(this.sweepTimer);
1837
+ this.sweepStart = null;
1838
+ this.sweepTimer = null;
1506
1839
  const files = this.router?.openFiles() ?? [];
1507
1840
  for (const file of files.toReversed()) try {
1508
1841
  await file.stop();