@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.
Files changed (160) hide show
  1. package/assets/record-entries/icon.svg +8 -0
  2. package/dist/addon-runner.js +81 -42
  3. package/dist/addon-runner.mjs +82 -43
  4. package/dist/{agent-https-DlpTMDqA.js → agent-https-CiOW0-sj.js} +810 -12
  5. package/dist/{agent-https-U0d4uvn2.mjs → agent-https-D4Q8iFNd.mjs} +697 -13
  6. package/dist/auth/admin-token-manager.d.ts +9 -3
  7. package/dist/auth/api-key-manager.d.ts +9 -3
  8. package/dist/auth/auth-audit-log.d.ts +9 -3
  9. package/dist/auth/device-credential-manager.d.ts +5 -1
  10. package/dist/auth/external-identity-manager.d.ts +8 -21
  11. package/dist/auth/login-session-manager.d.ts +11 -3
  12. package/dist/auth/scoped-token-manager.d.ts +8 -52
  13. package/dist/auth/totp-manager.d.ts +11 -3
  14. package/dist/auth/user-manager.d.ts +10 -17
  15. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  16. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  17. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  18. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  19. package/dist/builtins/alerts/alert-store.d.ts +32 -0
  20. package/dist/builtins/alerts/alerts.addon.d.ts +19 -4
  21. package/dist/builtins/alerts/alerts.addon.js +331 -159
  22. package/dist/builtins/alerts/alerts.addon.mjs +330 -159
  23. package/dist/builtins/alerts/record-kinds.d.ts +15 -0
  24. package/dist/builtins/autotrack/index.js +1 -1
  25. package/dist/builtins/autotrack/index.mjs +1 -1
  26. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +1 -0
  27. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +134 -193
  28. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +134 -193
  29. package/dist/builtins/backup-orchestrator/destination-policy.d.ts +4 -2
  30. package/dist/builtins/backup-orchestrator/encryption-key-store.d.ts +4 -2
  31. package/dist/builtins/backup-orchestrator/record-kinds.d.ts +58 -0
  32. package/dist/builtins/backup-orchestrator/schedule-store.d.ts +4 -2
  33. package/dist/builtins/backup-orchestrator/seed-marker-store.d.ts +4 -2
  34. package/dist/builtins/calendars/calendar-prefs-store.d.ts +13 -5
  35. package/dist/builtins/calendars/calendars.addon.d.ts +2 -2
  36. package/dist/builtins/calendars/calendars.addon.js +67 -64
  37. package/dist/builtins/calendars/calendars.addon.mjs +59 -64
  38. package/dist/builtins/calendars/record-kinds.d.ts +18 -0
  39. package/dist/builtins/camera-grid/index.js +1 -1
  40. package/dist/builtins/camera-grid/index.mjs +1 -1
  41. package/dist/builtins/cluster-agent/record-kinds.d.ts +36 -0
  42. package/dist/builtins/composer/composer.addon.js +2 -2
  43. package/dist/builtins/composer/composer.addon.mjs +2 -2
  44. package/dist/builtins/console-logging/index.js +1 -1
  45. package/dist/builtins/console-logging/index.mjs +1 -1
  46. package/dist/builtins/core-blocks/block-settings-store.d.ts +8 -4
  47. package/dist/builtins/core-blocks/core-block-store.d.ts +8 -16
  48. package/dist/builtins/core-blocks/core-blocks.addon.js +85 -112
  49. package/dist/builtins/core-blocks/core-blocks.addon.mjs +86 -113
  50. package/dist/builtins/core-blocks/index.mjs +1 -1
  51. package/dist/builtins/core-blocks/record-kinds.d.ts +26 -0
  52. package/dist/builtins/device-manager/device-manager.addon.js +111 -187
  53. package/dist/builtins/device-manager/device-manager.addon.mjs +110 -187
  54. package/dist/builtins/device-manager/device-tombstone-store.d.ts +9 -48
  55. package/dist/builtins/device-manager/record-kinds.d.ts +14 -0
  56. package/dist/builtins/hub-forwarder/index.js +1 -1
  57. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  58. package/dist/builtins/keychain/index.js +152 -22
  59. package/dist/builtins/keychain/index.mjs +152 -22
  60. package/dist/builtins/keychain/keychain-service.d.ts +3 -2
  61. package/dist/builtins/keychain/keychain-store.d.ts +13 -2
  62. package/dist/builtins/keychain/record-kinds.d.ts +16 -0
  63. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  64. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  65. package/dist/builtins/local-auth/auth-schema.d.ts +3 -1
  66. package/dist/builtins/local-auth/local-auth.addon.js +2903 -2123
  67. package/dist/builtins/local-auth/local-auth.addon.mjs +2904 -2124
  68. package/dist/builtins/local-auth/oauth-session-manager.d.ts +8 -48
  69. package/dist/builtins/local-auth/record-kinds.d.ts +141 -0
  70. package/dist/builtins/local-network/local-network.addon.js +2 -2
  71. package/dist/builtins/local-network/local-network.addon.mjs +2 -2
  72. package/dist/builtins/loki-logging/index.js +1 -1
  73. package/dist/builtins/loki-logging/index.mjs +1 -1
  74. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  75. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  76. package/dist/builtins/platform-probe/index.js +1 -1
  77. package/dist/builtins/platform-probe/index.mjs +1 -1
  78. package/dist/builtins/record-entries/entries-service.d.ts +42 -0
  79. package/dist/builtins/record-entries/index.d.ts +1 -0
  80. package/dist/builtins/record-entries/index.js +142 -0
  81. package/dist/builtins/record-entries/index.mjs +136 -0
  82. package/dist/builtins/record-entries/record-entries.addon.d.ts +13 -0
  83. package/dist/builtins/records/legacy-table-row-count.d.ts +5 -0
  84. package/dist/builtins/records/phase6-declare-gate.d.ts +28 -0
  85. package/dist/builtins/records-isolated.d.ts +10 -0
  86. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  87. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  88. package/dist/builtins/snapshot/index.js +1 -1
  89. package/dist/builtins/snapshot/index.mjs +1 -1
  90. package/dist/builtins/sqlite-storage/file-host-client.d.ts +2 -0
  91. package/dist/builtins/sqlite-storage/file-host-handlers.d.ts +4 -0
  92. package/dist/builtins/sqlite-storage/file-host-protocol.d.ts +7 -1
  93. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  94. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  95. package/dist/builtins/sqlite-storage/index.js +1 -1
  96. package/dist/builtins/sqlite-storage/index.mjs +1 -1
  97. package/dist/builtins/sqlite-storage/integration-record-kinds.d.ts +30 -0
  98. package/dist/builtins/sqlite-storage/integration-registry.d.ts +10 -16
  99. package/dist/builtins/sqlite-storage/owned-sqlite-file.d.ts +7 -0
  100. package/dist/builtins/sqlite-storage/placement-router.d.ts +5 -0
  101. package/dist/builtins/sqlite-storage/records/count-settings-array-legacy.d.ts +5 -0
  102. package/dist/builtins/sqlite-storage/records/count-settings-brokers-legacy.d.ts +6 -0
  103. package/dist/builtins/sqlite-storage/records/records-catalog.d.ts +29 -0
  104. package/dist/builtins/sqlite-storage/records/records-engine-types.d.ts +51 -0
  105. package/dist/builtins/sqlite-storage/records/records-engine.d.ts +94 -0
  106. package/dist/builtins/sqlite-storage/records/records-explain.d.ts +18 -0
  107. package/dist/builtins/sqlite-storage/records/records-plan.d.ts +90 -0
  108. package/dist/builtins/sqlite-storage/records/records-probe.d.ts +33 -0
  109. package/dist/builtins/sqlite-storage/records/records-provider.d.ts +63 -0
  110. package/dist/builtins/sqlite-storage/records/records-rows.d.ts +46 -0
  111. package/dist/builtins/sqlite-storage/records/records-sql.d.ts +41 -0
  112. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +17 -10
  113. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +8 -0
  114. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +446 -5
  115. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +446 -5
  116. package/dist/builtins/sqlite-storage/storage-admin-provider.d.ts +15 -1
  117. package/dist/builtins/storage-orchestrator/drain-state-store.d.ts +5 -2
  118. package/dist/builtins/storage-orchestrator/location-store.d.ts +7 -2
  119. package/dist/builtins/storage-orchestrator/record-kinds.d.ts +38 -0
  120. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +2 -0
  121. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +196 -5
  122. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +195 -6
  123. package/dist/builtins/system-config/record-kinds.d.ts +32 -0
  124. package/dist/builtins/system-config/system-config.addon.js +53 -618
  125. package/dist/builtins/system-config/system-config.addon.mjs +29 -577
  126. package/dist/builtins/winston-logging/index.js +1 -1
  127. package/dist/builtins/winston-logging/index.mjs +1 -1
  128. package/dist/{composition-sources-C8tUG2uL.mjs → composition-sources-BMt5cFYb.mjs} +1 -1
  129. package/dist/{composition-sources-BUXX1e8j.js → composition-sources-D3fi9Xns.js} +1 -1
  130. package/dist/{constants-CGwVaAV3.mjs → constants-BMHCxRzb.mjs} +1 -1
  131. package/dist/{constants-DWmm7_of.js → constants-Br879Axi.js} +1 -1
  132. package/dist/{device-ca-DGayRmC0.js → device-ca-CnJ_va7i.js} +1 -1
  133. package/dist/{device-ca-DBfiJ_SB.mjs → device-ca-T8osSMos.mjs} +1 -1
  134. package/dist/{dist-Bxt_S-9a.mjs → dist-BNunRyXT.mjs} +1133 -93
  135. package/dist/{dist-D9qT3jHr.js → dist-DgOG8flk.js} +1354 -92
  136. package/dist/file-host-worker.js +11 -1
  137. package/dist/file-host-worker.mjs +11 -1
  138. package/dist/{hub-mdns-ciao-B-wk9nzx.js → hub-mdns-ciao-BIkTHq-n.js} +2 -2
  139. package/dist/{hub-mdns-ciao-DpPcQDg-.mjs → hub-mdns-ciao-D16oRQ9K.mjs} +2 -2
  140. package/dist/index.d.ts +7 -0
  141. package/dist/index.js +3111 -2806
  142. package/dist/index.mjs +3083 -2795
  143. package/dist/kernel/index.d.ts +2 -0
  144. package/dist/kernel/moleculer/event-bus.d.ts +3 -1
  145. package/dist/kernel/moleculer/mesh-mtls/mesh-certificate-registry.d.ts +5 -1
  146. package/dist/kernel/moleculer/records-api-transport.d.ts +9 -0
  147. package/dist/kernel/moleculer/remote-logger.d.ts +2 -2
  148. package/dist/kernel/settings-view-types.d.ts +0 -7
  149. package/dist/kernel/transport/cap-route-resolver.d.ts +9 -38
  150. package/dist/phase6-declare-gate-Ci1-8uUn.js +98 -0
  151. package/dist/phase6-declare-gate-tkKOEitw.mjs +93 -0
  152. package/dist/read-all-rows-CVoO1ONM.js +29 -0
  153. package/dist/read-all-rows-TaPqdWNF.mjs +25 -0
  154. package/dist/records/read-all-rows.d.ts +6 -0
  155. package/dist/{restore-archive-9CGgeBzD.mjs → restore-archive-DR9MtO7J.mjs} +339 -9
  156. package/dist/{restore-archive-BMNXwWWD.js → restore-archive-DjJnCgap.js} +353 -5
  157. package/dist/tls/agent-https-names.d.ts +9 -13
  158. package/dist/{wal-maintenance-cRHR4rUY.js → wal-maintenance-CODGqhKY.js} +0 -0
  159. package/dist/{wal-maintenance-sIB32ONp.mjs → wal-maintenance-CfvgtQ7C.mjs} +0 -0
  160. package/package.json +22 -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-D9qT3jHr.js");
6
+ const require_dist = require("../../dist-DgOG8flk.js");
7
7
  const require_retired_settings_keys = require("../../retired-settings-keys-D_VwZiDt.js");
8
- const require_wal_maintenance = require("../../wal-maintenance-cRHR4rUY.js");
8
+ const require_wal_maintenance = require("../../wal-maintenance-CODGqhKY.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,368 @@ var PlacementRouter = class {
1204
1232
  }
1205
1233
  };
1206
1234
  //#endregion
1235
+ //#region src/builtins/sqlite-storage/records/count-settings-array-legacy.ts
1236
+ function isRecord$1(value) {
1237
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1238
+ }
1239
+ function unwrapValue$1(raw) {
1240
+ if (isRecord$1(raw) && "value" in raw) return raw["value"];
1241
+ return raw;
1242
+ }
1243
+ function legacyRowId(item) {
1244
+ const id = item["id"];
1245
+ if (typeof id === "string" && id.length > 0) return id;
1246
+ const username = item["username"];
1247
+ if (typeof username === "string" && username.length > 0) return username;
1248
+ return null;
1249
+ }
1250
+ async function countSettingsArrayLegacy(router, addonId, settingsKey) {
1251
+ const list = unwrapValue$1(await router.get({
1252
+ collection: "addon-settings",
1253
+ key: `${addonId}.${settingsKey}`
1254
+ }));
1255
+ if (!Array.isArray(list)) return 0;
1256
+ let n = 0;
1257
+ for (const item of list) {
1258
+ if (!isRecord$1(item)) continue;
1259
+ if (legacyRowId(item) !== null) n += 1;
1260
+ }
1261
+ return n;
1262
+ }
1263
+ //#endregion
1264
+ //#region src/builtins/sqlite-storage/records/count-settings-brokers-legacy.ts
1265
+ function isRecord(value) {
1266
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1267
+ }
1268
+ function unwrapValue(raw) {
1269
+ if (isRecord(raw) && "value" in raw) return raw["value"];
1270
+ return raw;
1271
+ }
1272
+ async function countSettingsBrokersLegacy(router, addonId) {
1273
+ const list = unwrapValue(await router.get({
1274
+ collection: "addon-settings",
1275
+ key: `${addonId}.brokers`
1276
+ }));
1277
+ if (!Array.isArray(list)) return 0;
1278
+ let n = 0;
1279
+ for (const item of list) if (isRecord(item) && typeof item["id"] === "string") n += 1;
1280
+ return n;
1281
+ }
1282
+ //#endregion
1283
+ //#region src/builtins/sqlite-storage/records/records-provider.ts
1284
+ /**
1285
+ * The `records` capability of the engine (D881): resolves WHO is calling and
1286
+ * WHICH file a kind lives in, then hands the call to that file's records engine.
1287
+ *
1288
+ * - **Owner** = the transport-stamped `callerAddonId` (as device-history's
1289
+ * `not-owner` and the keychain). It is never a field of any input; a call with
1290
+ * no stamp is refused `records/no-caller`.
1291
+ * - **Placement**: a kind's file is its declaration's `database`. The map is
1292
+ * rebuilt from each open file's own `_record_kinds` at boot and updated on
1293
+ * declaration. A kind declared for another file than the one it lives in is
1294
+ * refused (the engine never moves data, D853).
1295
+ * - **The boot guard**: after a declaration, a kind with `adoptsFrom` that is
1296
+ * EMPTY while its legacy table still holds rows is reported `adoptionPending`;
1297
+ * `ctx.records.declare` turns that into a refusal to start.
1298
+ */
1299
+ /** The caller the transport stamped, or a refusal. */
1300
+ function recordsCallerOf(input) {
1301
+ const raw = input !== null && typeof input === "object" ? Reflect.get(input, "callerAddonId") : void 0;
1302
+ if (typeof raw !== "string" || raw.length === 0) throw new require_dist.NoCallerError("the call carries no caller identity; records are reached through ctx.records");
1303
+ return require_dist.normalizeSecretOwner(raw);
1304
+ }
1305
+ function keyOf(owner, kind) {
1306
+ return `${owner}\u0000${kind}`;
1307
+ }
1308
+ var RecordsProvider = class {
1309
+ router;
1310
+ logger;
1311
+ placement = /* @__PURE__ */ new Map();
1312
+ constructor(router, logger) {
1313
+ this.router = router;
1314
+ this.logger = logger;
1315
+ }
1316
+ /** Rebuild the placement map from every open file's catalog. Call once, after the files are open. */
1317
+ async init() {
1318
+ this.placement.clear();
1319
+ for (const file of this.router.openFiles()) {
1320
+ if (file.databaseId === "history") continue;
1321
+ const kinds = await file.records("listKinds", {});
1322
+ for (const k of kinds) {
1323
+ if (k.state === "dropped") continue;
1324
+ const key = keyOf(k.owner, k.kind);
1325
+ const other = this.placement.get(key);
1326
+ 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`);
1327
+ this.placement.set(key, file.databaseId);
1328
+ }
1329
+ }
1330
+ this.logger.info("records: catalog loaded", { meta: { kinds: this.placement.size } });
1331
+ }
1332
+ fileOf(owner, kind) {
1333
+ const database = this.placement.get(keyOf(owner, kind));
1334
+ if (database === void 0) return Promise.reject(new require_dist.UnknownRecordKindError(`"${owner}" declared no kind "${kind}"`));
1335
+ return this.router.recordsFileFor(database);
1336
+ }
1337
+ async declareKinds(input) {
1338
+ const owner = recordsCallerOf(input);
1339
+ const byDatabase = /* @__PURE__ */ new Map();
1340
+ for (const [kind, raw] of Object.entries(input.kinds)) {
1341
+ const declaration = require_dist.RecordKindDeclarationSchema.parse(raw);
1342
+ const known = this.placement.get(keyOf(owner, kind));
1343
+ 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`);
1344
+ const group = byDatabase.get(declaration.database) ?? {};
1345
+ byDatabase.set(declaration.database, {
1346
+ ...group,
1347
+ [kind]: declaration
1348
+ });
1349
+ }
1350
+ const merged = {};
1351
+ for (const [database, kinds] of byDatabase) {
1352
+ const { kinds: results } = await (await this.router.recordsFileFor(database)).records("declareKinds", {
1353
+ owner,
1354
+ kinds
1355
+ });
1356
+ for (const [kind, result] of Object.entries(results)) {
1357
+ this.placement.set(keyOf(owner, kind), database);
1358
+ merged[kind] = result;
1359
+ }
1360
+ }
1361
+ return { kinds: await this.withAdoption(owner, input.kinds, merged) };
1362
+ }
1363
+ /** The boot guard: empty kind + a legacy table that still has rows = adoption pending. */
1364
+ async withAdoption(owner, declared, results) {
1365
+ const out = { ...results };
1366
+ for (const [kind, raw] of Object.entries(declared)) {
1367
+ const legacy = raw.adoptsFrom;
1368
+ const result = results[kind];
1369
+ if (legacy === void 0 || result === void 0) continue;
1370
+ if ((await (await this.fileOf(owner, kind)).records("adoptionState", {
1371
+ owner,
1372
+ kind
1373
+ })).adoptedAt !== null) continue;
1374
+ const settingsBrokersAddon = require_dist.parseSettingsBrokersAdoptsFrom(legacy);
1375
+ if (settingsBrokersAddon !== null) {
1376
+ const legacyRows = await countSettingsBrokersLegacy(this.router, settingsBrokersAddon);
1377
+ if (legacyRows > 0) out[kind] = {
1378
+ ...result,
1379
+ adoptionPending: {
1380
+ legacyTable: legacy,
1381
+ legacyRows
1382
+ }
1383
+ };
1384
+ continue;
1385
+ }
1386
+ const settingsArray = require_dist.parseSettingsArrayAdoptsFrom(legacy);
1387
+ if (settingsArray !== null) {
1388
+ const legacyRows = await countSettingsArrayLegacy(this.router, settingsArray.addonId, settingsArray.settingsKey);
1389
+ if (legacyRows > 0) out[kind] = {
1390
+ ...result,
1391
+ adoptionPending: {
1392
+ legacyTable: legacy,
1393
+ legacyRows
1394
+ }
1395
+ };
1396
+ continue;
1397
+ }
1398
+ const legacyRows = await (await this.router.recordsFileFor("settings")).records("legacyRowCount", { table: legacy });
1399
+ if (legacyRows !== null && legacyRows > 0) out[kind] = {
1400
+ ...result,
1401
+ adoptionPending: {
1402
+ legacyTable: legacy,
1403
+ legacyRows
1404
+ }
1405
+ };
1406
+ }
1407
+ return out;
1408
+ }
1409
+ async get(input) {
1410
+ const owner = recordsCallerOf(input);
1411
+ return (await this.fileOf(owner, input.kind)).records("get", {
1412
+ ...input,
1413
+ owner
1414
+ });
1415
+ }
1416
+ async getMany(input) {
1417
+ const owner = recordsCallerOf(input);
1418
+ return (await this.fileOf(owner, input.kind)).records("getMany", {
1419
+ ...input,
1420
+ owner
1421
+ });
1422
+ }
1423
+ async secretRefs(input) {
1424
+ const owner = recordsCallerOf(input);
1425
+ return (await this.fileOf(owner, input.kind)).records("secretRefs", {
1426
+ ...input,
1427
+ owner
1428
+ });
1429
+ }
1430
+ async put(input) {
1431
+ const owner = recordsCallerOf(input);
1432
+ return (await this.fileOf(owner, input.kind)).records("put", {
1433
+ ...input,
1434
+ owner
1435
+ });
1436
+ }
1437
+ async putMany(input) {
1438
+ const owner = recordsCallerOf(input);
1439
+ return (await this.fileOf(owner, input.kind)).records("putMany", {
1440
+ ...input,
1441
+ owner
1442
+ });
1443
+ }
1444
+ async patch(input) {
1445
+ const owner = recordsCallerOf(input);
1446
+ return (await this.fileOf(owner, input.kind)).records("patch", {
1447
+ ...input,
1448
+ owner
1449
+ });
1450
+ }
1451
+ async delete(input) {
1452
+ const owner = recordsCallerOf(input);
1453
+ return (await this.fileOf(owner, input.kind)).records("delete", {
1454
+ ...input,
1455
+ owner
1456
+ });
1457
+ }
1458
+ async deleteMany(input) {
1459
+ const owner = recordsCallerOf(input);
1460
+ return (await this.fileOf(owner, input.kind)).records("deleteMany", {
1461
+ ...input,
1462
+ owner
1463
+ });
1464
+ }
1465
+ async query(input) {
1466
+ const owner = recordsCallerOf(input);
1467
+ return (await this.fileOf(owner, input.kind)).records("query", {
1468
+ ...input,
1469
+ owner
1470
+ });
1471
+ }
1472
+ async count(input) {
1473
+ const owner = recordsCallerOf(input);
1474
+ return (await this.fileOf(owner, input.kind)).records("count", {
1475
+ ...input,
1476
+ owner
1477
+ });
1478
+ }
1479
+ async histogram(input) {
1480
+ const owner = recordsCallerOf(input);
1481
+ return (await this.fileOf(owner, input.kind)).records("histogram", {
1482
+ ...input,
1483
+ owner
1484
+ });
1485
+ }
1486
+ async aggregate(input) {
1487
+ const owner = recordsCallerOf(input);
1488
+ return (await this.fileOf(owner, input.kind)).records("aggregate", {
1489
+ ...input,
1490
+ owner
1491
+ });
1492
+ }
1493
+ async deleteWhere(input) {
1494
+ const owner = recordsCallerOf(input);
1495
+ return (await this.fileOf(owner, input.kind)).records("deleteWhere", {
1496
+ ...input,
1497
+ owner
1498
+ });
1499
+ }
1500
+ async allocateId(input) {
1501
+ const owner = recordsCallerOf(input);
1502
+ return (await this.fileOf(owner, input.kind)).records("allocateId", {
1503
+ ...input,
1504
+ owner
1505
+ });
1506
+ }
1507
+ /** The D865 hook body: every file that holds kinds of this owner. */
1508
+ async deleteDevice(input) {
1509
+ const owner = recordsCallerOf(input);
1510
+ const deleted = {};
1511
+ const secretRefs = [];
1512
+ const databases = new Set([...this.placement.entries()].filter(([key]) => key.startsWith(`${owner}\u0000`)).map(([, database]) => database));
1513
+ for (const database of databases) {
1514
+ const result = await (await this.router.recordsFileFor(database)).records("deleteDevice", {
1515
+ ...input,
1516
+ owner
1517
+ });
1518
+ Object.assign(deleted, result.deleted);
1519
+ secretRefs.push(...result.secretRefs);
1520
+ }
1521
+ return {
1522
+ deleted,
1523
+ secretRefs
1524
+ };
1525
+ }
1526
+ async listKinds(input) {
1527
+ const kinds = [];
1528
+ for (const file of this.router.openFiles()) {
1529
+ if (file.databaseId === "history") continue;
1530
+ kinds.push(...await file.records("listKinds", input));
1531
+ }
1532
+ return { kinds };
1533
+ }
1534
+ async readRecords(input) {
1535
+ this.logger.info("records: admin read", { meta: {
1536
+ owner: input.owner,
1537
+ kind: input.kind,
1538
+ limit: input.limit
1539
+ } });
1540
+ return (await this.fileOf(input.owner, input.kind)).records("query", input);
1541
+ }
1542
+ /** True when a declared kind lists `collection` as `adoptsFrom` and adoption finished. */
1543
+ async isAdoptedLegacyTable(collection) {
1544
+ const { kinds } = await this.listKinds({ counts: false });
1545
+ for (const k of kinds) {
1546
+ if (k.state === "dropped") continue;
1547
+ if (k.declaration.adoptsFrom !== collection) continue;
1548
+ const { adoptedAt } = await (await this.fileOf(k.owner, k.kind)).records("adoptionState", {
1549
+ owner: k.owner,
1550
+ kind: k.kind
1551
+ });
1552
+ if (adoptedAt !== null) return true;
1553
+ }
1554
+ return false;
1555
+ }
1556
+ async adoptRecords(input) {
1557
+ const file = await this.fileOf(input.owner, input.kind);
1558
+ if (input.records.length > 0) {
1559
+ const { adoptedAt } = await file.records("adoptionState", {
1560
+ owner: input.owner,
1561
+ kind: input.kind
1562
+ });
1563
+ if (adoptedAt !== null) {
1564
+ if ((await file.records("count", {
1565
+ owner: input.owner,
1566
+ kind: input.kind
1567
+ })).count === 0) await file.records("revokeAdopted", {
1568
+ owner: input.owner,
1569
+ kind: input.kind
1570
+ });
1571
+ }
1572
+ }
1573
+ const result = await file.records("putMany", input);
1574
+ if (input.complete === true) await file.records("markAdopted", {
1575
+ owner: input.owner,
1576
+ kind: input.kind
1577
+ });
1578
+ this.logger.warn("records: ADOPTED rows as their declared owner", { meta: {
1579
+ owner: input.owner,
1580
+ kind: input.kind,
1581
+ count: result.count,
1582
+ complete: input.complete === true
1583
+ } });
1584
+ return { adopted: result.count };
1585
+ }
1586
+ /** Housekeeping: delete rows past `expires_at` in every file that hosts kinds. */
1587
+ async sweepExpired() {
1588
+ let deleted = 0;
1589
+ for (const file of this.router.openFiles()) {
1590
+ if (file.databaseId === "history") continue;
1591
+ deleted += (await file.records("sweepExpired", {})).deleted;
1592
+ }
1593
+ return deleted;
1594
+ }
1595
+ };
1596
+ //#endregion
1207
1597
  //#region src/builtins/sqlite-storage/storage-admin-provider.ts
1208
1598
  /**
1209
1599
  * The `storage-admin` provider of the SQLite engine (D870): the operator's
@@ -1217,10 +1607,27 @@ var StorageAdminProvider = class {
1217
1607
  backend;
1218
1608
  logger;
1219
1609
  installedOwners;
1220
- constructor(backend, logger, installedOwners) {
1610
+ records;
1611
+ constructor(backend, logger, installedOwners, records) {
1221
1612
  this.backend = backend;
1222
1613
  this.logger = logger;
1223
1614
  this.installedOwners = installedOwners;
1615
+ this.records = records;
1616
+ }
1617
+ listKinds(input) {
1618
+ return this.records.listKinds(input);
1619
+ }
1620
+ readRecords(input) {
1621
+ return this.records.readRecords(input);
1622
+ }
1623
+ adoptRecords(input) {
1624
+ return this.records.adoptRecords(input);
1625
+ }
1626
+ isAdoptedLegacyTable(input) {
1627
+ return this.records.isAdoptedLegacyTable(input.collection).then((adopted) => ({ adopted }));
1628
+ }
1629
+ readLegacyCollection(input) {
1630
+ return Promise.resolve(this.backend.readLegacyCollection(input));
1224
1631
  }
1225
1632
  /** May this table be dropped AT ALL? Throws with the reason when not. */
1226
1633
  async assertDroppable(collection) {
@@ -1233,7 +1640,7 @@ var StorageAdminProvider = class {
1233
1640
  throw new Error(`drop refused: the installed addons could not be read (${err instanceof Error ? err.message : String(err)})`);
1234
1641
  });
1235
1642
  const owner = collection.slice(0, colon);
1236
- if (installed.has(owner)) throw new Error(`drop refused: "${collection}" belongs to the installed addon "${owner}"`);
1643
+ if (installed.has(owner) && !await this.records.isAdoptedLegacyTable(collection)) throw new Error(`drop refused: "${collection}" belongs to the installed addon "${owner}"`);
1237
1644
  }
1238
1645
  async listTables(input) {
1239
1646
  const tables = this.backend.listTables(input.ownerPrefix);
@@ -1246,6 +1653,7 @@ var StorageAdminProvider = class {
1246
1653
  async dropCollection(input) {
1247
1654
  try {
1248
1655
  await this.assertDroppable(input.collection);
1656
+ if (await this.records.isAdoptedLegacyTable(input.collection)) this.backend.forgetDeclaredThisBoot(input.collection);
1249
1657
  const rows = this.backend.dropTable(input.collection, input.expectRows);
1250
1658
  this.logger.warn("storage-admin: DROPPED a table", { meta: {
1251
1659
  collection: input.collection,
@@ -1413,6 +1821,8 @@ var DATABASE_FILE_NAMES = {
1413
1821
  var SqliteSettingsAddon = class extends require_dist.BaseAddon {
1414
1822
  settingsFile = null;
1415
1823
  router = null;
1824
+ sweepTimer = null;
1825
+ sweepStart = null;
1416
1826
  constructor() {
1417
1827
  super({});
1418
1828
  }
@@ -1469,12 +1879,19 @@ var SqliteSettingsAddon = class extends require_dist.BaseAddon {
1469
1879
  this.router = router;
1470
1880
  const vectorIndex = settings.getVectorIndex();
1471
1881
  if (vectorIndex === null) throw new Error("vector-store: the settings file has no vector index");
1882
+ const records = new RecordsProvider(router, this.ctx.logger.child("Records"));
1883
+ await records.init();
1884
+ this.startRecordsSweep(records);
1472
1885
  this.ctx.logger.info("Initialized successfully");
1473
1886
  return [
1474
1887
  {
1475
1888
  capability: require_dist.dataStoreProviderCapability,
1476
1889
  provider: router
1477
1890
  },
1891
+ {
1892
+ capability: require_dist.recordsCapability,
1893
+ provider: records
1894
+ },
1478
1895
  {
1479
1896
  capability: require_dist.vectorStoreCapability,
1480
1897
  provider: require_wal_maintenance.vectorProviderOf(vectorIndex)
@@ -1485,7 +1902,7 @@ var SqliteSettingsAddon = class extends require_dist.BaseAddon {
1485
1902
  },
1486
1903
  {
1487
1904
  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)))
1905
+ 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
1906
  }
1490
1907
  ];
1491
1908
  }
@@ -1502,7 +1919,31 @@ var SqliteSettingsAddon = class extends require_dist.BaseAddon {
1502
1919
  }
1503
1920
  await purgeRetiredCollections(retiredCollectionStoreOfFile(file), this.ctx.logger.child("RetiredCollections").withTags({ database: file.databaseId }));
1504
1921
  }
1922
+ /**
1923
+ * The engine's TTL sweep (D881): every 10 minutes, off the boot path (the
1924
+ * first run a minute after boot), batched and yielding. A failed pass is
1925
+ * warned about and the next one retries; it never blocks anything.
1926
+ */
1927
+ startRecordsSweep(records) {
1928
+ const run = () => {
1929
+ records.sweepExpired().then((deleted) => {
1930
+ if (deleted > 0) this.ctx.logger.info("records: expired rows swept", { meta: { deleted } });
1931
+ }).catch((err) => {
1932
+ this.ctx.logger.warn("records: expiry sweep failed", { meta: { error: require_dist.errMsg(err) } });
1933
+ });
1934
+ };
1935
+ this.sweepStart = setTimeout(() => {
1936
+ run();
1937
+ this.sweepTimer = setInterval(run, require_dist.RECORD_SWEEP_INTERVAL_MS);
1938
+ this.sweepTimer.unref();
1939
+ }, 6e4);
1940
+ this.sweepStart.unref();
1941
+ }
1505
1942
  async onShutdown() {
1943
+ if (this.sweepStart !== null) clearTimeout(this.sweepStart);
1944
+ if (this.sweepTimer !== null) clearInterval(this.sweepTimer);
1945
+ this.sweepStart = null;
1946
+ this.sweepTimer = null;
1506
1947
  const files = this.router?.openFiles() ?? [];
1507
1948
  for (const file of files.toReversed()) try {
1508
1949
  await file.stop();