@camstack/system 1.2.444 → 1.2.446

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 (144) hide show
  1. package/dist/addon-runner.js +40 -31
  2. package/dist/addon-runner.mjs +41 -32
  3. package/dist/{agent-https-DlpTMDqA.js → agent-https-5DYAOJMO.js} +810 -12
  4. package/dist/{agent-https-U0d4uvn2.mjs → agent-https-BWUEf6ev.mjs} +697 -13
  5. package/dist/auth/admin-token-manager.d.ts +9 -3
  6. package/dist/auth/api-key-manager.d.ts +9 -3
  7. package/dist/auth/auth-audit-log.d.ts +9 -3
  8. package/dist/auth/device-credential-manager.d.ts +5 -1
  9. package/dist/auth/external-identity-manager.d.ts +8 -21
  10. package/dist/auth/login-session-manager.d.ts +11 -3
  11. package/dist/auth/scoped-token-manager.d.ts +8 -52
  12. package/dist/auth/totp-manager.d.ts +11 -3
  13. package/dist/auth/user-manager.d.ts +10 -17
  14. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  15. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  16. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  17. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  18. package/dist/builtins/alerts/alert-store.d.ts +32 -0
  19. package/dist/builtins/alerts/alerts.addon.d.ts +9 -2
  20. package/dist/builtins/alerts/alerts.addon.js +373 -154
  21. package/dist/builtins/alerts/alerts.addon.mjs +372 -154
  22. package/dist/builtins/alerts/critical-push.d.ts +4 -0
  23. package/dist/builtins/alerts/emit-alert-policy.d.ts +28 -0
  24. package/dist/builtins/alerts/record-kinds.d.ts +15 -0
  25. package/dist/builtins/autotrack/index.js +1 -1
  26. package/dist/builtins/autotrack/index.mjs +1 -1
  27. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +1 -0
  28. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +134 -193
  29. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +134 -193
  30. package/dist/builtins/backup-orchestrator/destination-policy.d.ts +4 -2
  31. package/dist/builtins/backup-orchestrator/encryption-key-store.d.ts +4 -2
  32. package/dist/builtins/backup-orchestrator/record-kinds.d.ts +58 -0
  33. package/dist/builtins/backup-orchestrator/schedule-store.d.ts +4 -2
  34. package/dist/builtins/backup-orchestrator/seed-marker-store.d.ts +4 -2
  35. package/dist/builtins/calendars/calendar-prefs-store.d.ts +13 -5
  36. package/dist/builtins/calendars/calendars.addon.d.ts +2 -2
  37. package/dist/builtins/calendars/calendars.addon.js +67 -64
  38. package/dist/builtins/calendars/calendars.addon.mjs +59 -64
  39. package/dist/builtins/calendars/record-kinds.d.ts +18 -0
  40. package/dist/builtins/camera-grid/index.js +1 -1
  41. package/dist/builtins/camera-grid/index.mjs +1 -1
  42. package/dist/builtins/cluster-agent/record-kinds.d.ts +36 -0
  43. package/dist/builtins/composer/composer.addon.js +2 -2
  44. package/dist/builtins/composer/composer.addon.mjs +2 -2
  45. package/dist/builtins/console-logging/index.js +1 -1
  46. package/dist/builtins/console-logging/index.mjs +1 -1
  47. package/dist/builtins/core-blocks/block-settings-store.d.ts +8 -4
  48. package/dist/builtins/core-blocks/core-block-store.d.ts +8 -16
  49. package/dist/builtins/core-blocks/core-blocks.addon.js +85 -112
  50. package/dist/builtins/core-blocks/core-blocks.addon.mjs +86 -113
  51. package/dist/builtins/core-blocks/index.mjs +1 -1
  52. package/dist/builtins/core-blocks/record-kinds.d.ts +26 -0
  53. package/dist/builtins/device-manager/device-manager.addon.js +111 -187
  54. package/dist/builtins/device-manager/device-manager.addon.mjs +110 -187
  55. package/dist/builtins/device-manager/device-tombstone-store.d.ts +9 -48
  56. package/dist/builtins/device-manager/record-kinds.d.ts +14 -0
  57. package/dist/builtins/hub-forwarder/index.js +1 -1
  58. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  59. package/dist/builtins/keychain/index.js +152 -22
  60. package/dist/builtins/keychain/index.mjs +152 -22
  61. package/dist/builtins/keychain/keychain-service.d.ts +3 -2
  62. package/dist/builtins/keychain/keychain-store.d.ts +13 -2
  63. package/dist/builtins/keychain/record-kinds.d.ts +16 -0
  64. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  65. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  66. package/dist/builtins/local-auth/auth-schema.d.ts +3 -1
  67. package/dist/builtins/local-auth/local-auth.addon.js +2903 -2123
  68. package/dist/builtins/local-auth/local-auth.addon.mjs +2904 -2124
  69. package/dist/builtins/local-auth/oauth-session-manager.d.ts +8 -48
  70. package/dist/builtins/local-auth/record-kinds.d.ts +141 -0
  71. package/dist/builtins/local-network/local-network.addon.js +2 -2
  72. package/dist/builtins/local-network/local-network.addon.mjs +2 -2
  73. package/dist/builtins/loki-logging/index.js +1 -1
  74. package/dist/builtins/loki-logging/index.mjs +1 -1
  75. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  76. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  77. package/dist/builtins/platform-probe/index.js +1 -1
  78. package/dist/builtins/platform-probe/index.mjs +1 -1
  79. package/dist/builtins/record-entries/index.js +1 -1
  80. package/dist/builtins/record-entries/index.mjs +1 -1
  81. package/dist/builtins/records/legacy-table-row-count.d.ts +5 -0
  82. package/dist/builtins/records/phase6-declare-gate.d.ts +28 -0
  83. package/dist/builtins/records-isolated.d.ts +10 -0
  84. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  85. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  86. package/dist/builtins/snapshot/index.js +1 -1
  87. package/dist/builtins/snapshot/index.mjs +1 -1
  88. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  89. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  90. package/dist/builtins/sqlite-storage/index.js +1 -1
  91. package/dist/builtins/sqlite-storage/index.mjs +1 -1
  92. package/dist/builtins/sqlite-storage/integration-record-kinds.d.ts +30 -0
  93. package/dist/builtins/sqlite-storage/integration-registry.d.ts +10 -16
  94. package/dist/builtins/sqlite-storage/records/count-settings-array-legacy.d.ts +5 -0
  95. package/dist/builtins/sqlite-storage/records/count-settings-brokers-legacy.d.ts +6 -0
  96. package/dist/builtins/sqlite-storage/records/records-engine-types.d.ts +5 -0
  97. package/dist/builtins/sqlite-storage/records/records-engine.d.ts +4 -0
  98. package/dist/builtins/sqlite-storage/records/records-provider.d.ts +5 -1
  99. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +17 -0
  100. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +111 -3
  101. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +111 -3
  102. package/dist/builtins/sqlite-storage/storage-admin-provider.d.ts +9 -1
  103. package/dist/builtins/storage-orchestrator/drain-state-store.d.ts +5 -2
  104. package/dist/builtins/storage-orchestrator/location-store.d.ts +7 -2
  105. package/dist/builtins/storage-orchestrator/record-kinds.d.ts +38 -0
  106. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +2 -0
  107. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +196 -5
  108. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +195 -6
  109. package/dist/builtins/system-config/record-kinds.d.ts +32 -0
  110. package/dist/builtins/system-config/system-config.addon.js +53 -618
  111. package/dist/builtins/system-config/system-config.addon.mjs +29 -577
  112. package/dist/builtins/winston-logging/index.js +1 -1
  113. package/dist/builtins/winston-logging/index.mjs +1 -1
  114. package/dist/{composition-sources-C3rKncIF.mjs → composition-sources-BmC5jAUv.mjs} +1 -1
  115. package/dist/{composition-sources-NAPZddic.js → composition-sources-BwIIltnZ.js} +1 -1
  116. package/dist/{constants-BKX2QnIg.mjs → constants-6XHGmEUF.mjs} +1 -1
  117. package/dist/{constants-BXiNEIeV.js → constants-DA_tjzIk.js} +1 -1
  118. package/dist/{device-ca-jxjSL8Ov.mjs → device-ca-Bh_ClxMO.mjs} +1 -1
  119. package/dist/{device-ca-DT9X2S6d.js → device-ca-CnbrgfmW.js} +1 -1
  120. package/dist/{dist-D1vECb_6.js → dist-BkNfEJKa.js} +521 -64
  121. package/dist/{dist-DERK-gP5.mjs → dist-CkZIrsAP.mjs} +462 -65
  122. package/dist/file-host-worker.js +1 -1
  123. package/dist/file-host-worker.mjs +1 -1
  124. package/dist/{hub-mdns-ciao-CRaC97V0.mjs → hub-mdns-ciao-CoyIUWHC.mjs} +2 -2
  125. package/dist/{hub-mdns-ciao-Cah9GCIg.js → hub-mdns-ciao-m5LIr4oA.js} +2 -2
  126. package/dist/index.d.ts +7 -0
  127. package/dist/index.js +3095 -2821
  128. package/dist/index.mjs +3067 -2810
  129. package/dist/kernel/index.d.ts +2 -0
  130. package/dist/kernel/moleculer/event-bus.d.ts +3 -1
  131. package/dist/kernel/moleculer/mesh-mtls/mesh-certificate-registry.d.ts +5 -1
  132. package/dist/kernel/moleculer/remote-logger.d.ts +2 -2
  133. package/dist/kernel/transport/cap-route-resolver.d.ts +9 -38
  134. package/dist/phase6-declare-gate-BDWZuB2n.mjs +93 -0
  135. package/dist/phase6-declare-gate-Bl7KocEs.js +98 -0
  136. package/dist/read-all-rows-CVoO1ONM.js +29 -0
  137. package/dist/read-all-rows-TaPqdWNF.mjs +25 -0
  138. package/dist/records/read-all-rows.d.ts +6 -0
  139. package/dist/{restore-archive-Dy-qKTdF.js → restore-archive-B57xI5Ue.js} +353 -5
  140. package/dist/{restore-archive-daKyE24F.mjs → restore-archive-CMr4V7Fi.mjs} +339 -9
  141. package/dist/tls/agent-https-names.d.ts +9 -13
  142. package/dist/{wal-maintenance-zRc24mOC.mjs → wal-maintenance-Bqm4zrNA.mjs} +0 -0
  143. package/dist/{wal-maintenance-dAv4IdzC.js → wal-maintenance-CuG1DUca.js} +0 -0
  144. package/package.json +1 -1
@@ -3,9 +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-D1vECb_6.js");
7
- const require_device_ca = require("../../device-ca-DT9X2S6d.js");
8
- const require_constants = require("../../constants-BXiNEIeV.js");
6
+ const require_dist = require("../../dist-BkNfEJKa.js");
7
+ const require_read_all_rows$1 = require("../../read-all-rows-CVoO1ONM.js");
8
+ const require_device_ca = require("../../device-ca-CnbrgfmW.js");
9
+ const require_phase6_declare_gate = require("../../phase6-declare-gate-Bl7KocEs.js");
10
+ const require_constants = require("../../constants-DA_tjzIk.js");
9
11
  const require_platform_key_source = require("../../platform-key-source-Di7HrlGR.js");
10
12
  let node_crypto = require("node:crypto");
11
13
  let _camstack_types_node = require("@camstack/types/node");
@@ -388,8 +390,11 @@ var NOT_INITIALIZED = {
388
390
  state: "locked",
389
391
  reason: "not-initialized"
390
392
  };
391
- /** The only refs `importSecret` accepts: a camera's restream tokens (D870 migration). */
392
- var IMPORTABLE_REF = /^secret:\/\/stream-broker\/device\/[0-9]+\/rtspTokens$/;
393
+ /**
394
+ * Refs `importSecret` accepts for operator migration (D870): restream tokens and
395
+ * record-row secret refs (`recordSecretRef` — collection `records%3A<kind>`).
396
+ */
397
+ var IMPORTABLE_REF = /^(?:secret:\/\/stream-broker\/device\/[0-9]+\/rtspTokens|secret:\/\/[^/]+\/row\/records%3A[^/]+\/[^/]+\/.+)$/;
393
398
  var KeychainService = class {
394
399
  deps;
395
400
  unlock = NOT_INITIALIZED;
@@ -785,11 +790,12 @@ var KeychainService = class {
785
790
  return this.put(require_device_ca.SYSTEM_SECRET_OWNER, ref, value, `user:${userId}`);
786
791
  }
787
792
  /**
788
- * An operator tool stores a carried-over value at an addon's own ref (D870).
789
- * Stored under the ref's owner, audited as the operator.
793
+ * An operator tool stores a carried-over value at a migration ref (D870):
794
+ * restream tokens or a `recordSecretRef` row field. Stored under the ref's
795
+ * owner, audited as the operator; never overwrites an existing value.
790
796
  */
791
797
  async importSecret(userId, ref, value) {
792
- if (!IMPORTABLE_REF.test(ref)) throw new Error(`keychain: "${ref}" is not an importable ref (restream tokens only)`);
798
+ if (!IMPORTABLE_REF.test(ref)) throw new Error(`keychain: "${ref}" is not an importable ref (restream tokens or record row secrets)`);
793
799
  if ((await this.deps.repo.getSecrets([ref])).has(ref)) throw new Error(`keychain: a value is already stored at ${ref} - import refuses to overwrite`);
794
800
  const parts = require_dist.parseSecretRef(ref);
795
801
  if (parts === null) throw new Error(`keychain: "${ref}" is not a secret ref`);
@@ -1068,6 +1074,7 @@ function errMsg(err) {
1068
1074
  require_dist.EventCategory.KeychainChanged;
1069
1075
  //#endregion
1070
1076
  //#region src/builtins/keychain/keychain-store.ts
1077
+ var import_read_all_rows = require_read_all_rows$1.require_read_all_rows();
1071
1078
  /**
1072
1079
  * @durable class=config owner=keychain
1073
1080
  * write="`keychain.put` upserts one row per ref; `delete` removes it"
@@ -1373,8 +1380,16 @@ function toResetRecord(id, data) {
1373
1380
  var PAGE = 1e3;
1374
1381
  var KeychainRepository = class {
1375
1382
  door;
1376
- constructor(door) {
1383
+ records;
1384
+ constructor(door, records) {
1377
1385
  this.door = door;
1386
+ this.records = records;
1387
+ }
1388
+ static recordStoresOf(records) {
1389
+ return {
1390
+ audit: records.kind(keychainRecordKinds.audit),
1391
+ resets: records.kind(keychainRecordKinds.resets)
1392
+ };
1378
1393
  }
1379
1394
  async init() {
1380
1395
  await this.door.declareCollection({
@@ -1389,18 +1404,20 @@ var KeychainRepository = class {
1389
1404
  collection: KEYCHAIN_KEYS_COLLECTION,
1390
1405
  columns: KEY_COLUMNS
1391
1406
  });
1392
- await this.door.declareCollection({
1393
- collection: KEYCHAIN_RESETS_COLLECTION,
1394
- columns: RESET_COLUMNS
1395
- });
1396
- await this.door.declareCollection({
1397
- collection: KEYCHAIN_AUDIT_COLLECTION,
1398
- columns: AUDIT_COLUMNS,
1399
- indexes: [{
1400
- name: "idx_keychain_audit_at",
1401
- columns: ["at"]
1402
- }]
1403
- });
1407
+ if (this.records === void 0) {
1408
+ await this.door.declareCollection({
1409
+ collection: KEYCHAIN_RESETS_COLLECTION,
1410
+ columns: RESET_COLUMNS
1411
+ });
1412
+ await this.door.declareCollection({
1413
+ collection: KEYCHAIN_AUDIT_COLLECTION,
1414
+ columns: AUDIT_COLUMNS,
1415
+ indexes: [{
1416
+ name: "idx_keychain_audit_at",
1417
+ columns: ["at"]
1418
+ }]
1419
+ });
1420
+ }
1404
1421
  }
1405
1422
  async getSecrets(refs) {
1406
1423
  const out = /* @__PURE__ */ new Map();
@@ -1477,6 +1494,21 @@ var KeychainRepository = class {
1477
1494
  });
1478
1495
  }
1479
1496
  async appendAudit(row) {
1497
+ const kind = this.records?.audit;
1498
+ if (kind !== void 0) {
1499
+ const { id, at, action, actor, ref, detail } = row;
1500
+ await kind.put({
1501
+ id,
1502
+ at,
1503
+ data: {
1504
+ action,
1505
+ actor,
1506
+ ref,
1507
+ detail
1508
+ }
1509
+ });
1510
+ return;
1511
+ }
1480
1512
  await this.door.set({
1481
1513
  collection: KEYCHAIN_AUDIT_COLLECTION,
1482
1514
  key: row.id,
@@ -1484,6 +1516,20 @@ var KeychainRepository = class {
1484
1516
  });
1485
1517
  }
1486
1518
  async listAudit(limit) {
1519
+ const kind = this.records?.audit;
1520
+ if (kind !== void 0) {
1521
+ const rows = await (0, import_read_all_rows.readAllRows)(kind);
1522
+ rows.sort((a, b) => (b.at ?? 0) - (a.at ?? 0));
1523
+ const out = [];
1524
+ for (const row of rows.slice(0, limit)) {
1525
+ const parsed = toAuditRow(row.id, {
1526
+ ...row.data,
1527
+ at: row.at ?? 0
1528
+ });
1529
+ if (parsed !== null) out.push(parsed);
1530
+ }
1531
+ return out;
1532
+ }
1487
1533
  const rows = await this.door.query({
1488
1534
  collection: KEYCHAIN_AUDIT_COLLECTION,
1489
1535
  filter: {
@@ -1503,6 +1549,22 @@ var KeychainRepository = class {
1503
1549
  }
1504
1550
  /** Drop audit rows older than the retention window, then beyond the row bound. */
1505
1551
  async pruneAudit(nowMs) {
1552
+ const kind = this.records?.audit;
1553
+ if (kind !== void 0) {
1554
+ const ageCutoff = nowMs - AUDIT_RETENTION_MS;
1555
+ let deleted = 0;
1556
+ for (const row of await (0, import_read_all_rows.readAllRows)(kind)) if ((row.at ?? 0) <= ageCutoff) {
1557
+ await kind.delete(row.id);
1558
+ deleted += 1;
1559
+ }
1560
+ const remaining = await (0, import_read_all_rows.readAllRows)(kind);
1561
+ remaining.sort((a, b) => (b.at ?? 0) - (a.at ?? 0));
1562
+ for (const row of remaining.slice(AUDIT_MAX_ROWS)) {
1563
+ await kind.delete(row.id);
1564
+ deleted += 1;
1565
+ }
1566
+ return deleted;
1567
+ }
1506
1568
  const aged = await this.door.deleteWhere({
1507
1569
  collection: KEYCHAIN_AUDIT_COLLECTION,
1508
1570
  filter: { whereBetween: { at: [0, nowMs - AUDIT_RETENTION_MS] } }
@@ -1604,6 +1666,24 @@ var KeychainRepository = class {
1604
1666
  return cleared;
1605
1667
  }
1606
1668
  async putReset(record) {
1669
+ const kind = this.records?.resets;
1670
+ if (kind !== void 0) {
1671
+ const { id, at, actor, lockedReason, archived, archivedCollection, archivedKeysCollection, clearedSettingsKeys, acknowledgedAt } = record;
1672
+ await kind.put({
1673
+ id,
1674
+ at,
1675
+ data: {
1676
+ actor,
1677
+ lockedReason,
1678
+ archived,
1679
+ archivedCollection,
1680
+ archivedKeysCollection,
1681
+ clearedSettingsKeys: [...clearedSettingsKeys],
1682
+ acknowledgedAt
1683
+ }
1684
+ });
1685
+ return;
1686
+ }
1607
1687
  await this.door.set({
1608
1688
  collection: KEYCHAIN_RESETS_COLLECTION,
1609
1689
  key: record.id,
@@ -1614,6 +1694,17 @@ var KeychainRepository = class {
1614
1694
  });
1615
1695
  }
1616
1696
  async latestReset() {
1697
+ const kind = this.records?.resets;
1698
+ if (kind !== void 0) {
1699
+ const rows = await (0, import_read_all_rows.readAllRows)(kind);
1700
+ rows.sort((a, b) => (b.at ?? 0) - (a.at ?? 0));
1701
+ const row = rows[0];
1702
+ if (row === void 0) return null;
1703
+ return toResetRecord(row.id, {
1704
+ ...row.data,
1705
+ at: row.at ?? 0
1706
+ });
1707
+ }
1617
1708
  const row = (await this.door.query({
1618
1709
  collection: KEYCHAIN_RESETS_COLLECTION,
1619
1710
  filter: {
@@ -1627,6 +1718,44 @@ var KeychainRepository = class {
1627
1718
  return row === void 0 ? null : toResetRecord(row.id, row.data);
1628
1719
  }
1629
1720
  };
1721
+ var KeychainAuditBodySchema = require_dist.KeychainAuditEntrySchema.omit({
1722
+ id: true,
1723
+ at: true
1724
+ });
1725
+ var KeychainResetBodySchema = require_dist.KeychainResetRecordSchema.omit({
1726
+ id: true,
1727
+ at: true
1728
+ });
1729
+ var _keychainRecordKinds = require_dist.defineRecordKinds({
1730
+ audit: {
1731
+ schema: KeychainAuditBodySchema,
1732
+ class: "audit",
1733
+ writeTrigger: "one row per write / delete / rotation / reveal / recovery download",
1734
+ device: "none",
1735
+ at: "required",
1736
+ indexes: [{
1737
+ name: "audit_at",
1738
+ fields: ["at"]
1739
+ }],
1740
+ retention: {
1741
+ owner: "keychain",
1742
+ reason: "90 days and at most 20_000 rows, pruned at boot and daily"
1743
+ },
1744
+ adoptsFrom: KEYCHAIN_AUDIT_COLLECTION
1745
+ },
1746
+ resets: {
1747
+ schema: KeychainResetBodySchema,
1748
+ class: "config",
1749
+ writeTrigger: "one row per keychain reset (System → Secrets, or the RESET_KEYCHAIN trigger file); acknowledgeReset stamps acknowledgedAt",
1750
+ device: "none",
1751
+ at: "required",
1752
+ retention: { none: "a handful of rows over a hub life; they name archive tables a reset left behind" },
1753
+ adoptsFrom: KEYCHAIN_RESETS_COLLECTION
1754
+ }
1755
+ });
1756
+ var keychainRecordKinds = _keychainRecordKinds;
1757
+ _keychainRecordKinds.audit;
1758
+ _keychainRecordKinds.resets;
1630
1759
  //#endregion
1631
1760
  //#region src/builtins/keychain/keychain-usage.ts
1632
1761
  /**
@@ -1823,8 +1952,9 @@ var KeychainAddon = class extends require_dist.BaseAddon {
1823
1952
  warn: (message, meta) => ctx.logger.warn(message, meta ? { meta } : void 0),
1824
1953
  error: (message, meta) => ctx.logger.error(message, meta ? { meta } : void 0)
1825
1954
  };
1955
+ const records = ctx.records;
1826
1956
  const service = new KeychainService({
1827
- repo: new KeychainRepository(door),
1957
+ repo: new KeychainRepository(door, records !== void 0 && await require_phase6_declare_gate.resolvePhase6UseRecordsPathForHub(ctx, "keychain", keychainRecordKinds, ["keychain:audit", "keychain:resets"]) && records !== void 0 ? KeychainRepository.recordStoresOf(records) : void 0),
1828
1958
  candidates: async () => {
1829
1959
  return buildKeySourceCandidates({
1830
1960
  config: readKeyConfig(await ctx.settings?.getSection("keychain") ?? {}),
@@ -1,6 +1,8 @@
1
- import { $i as EventCategory, Bi as parseSecretRef, Fr as BaseAddon, Li as normalizeSecretOwner, R as KEYCHAIN_RESET_TRIGGER_ACTOR, Ti as formatSecretScope, dn as keychainCapability, un as keychainAdminCapability } from "../../dist-DERK-gP5.mjs";
2
- import { d as JWT_SIGNING_KEY_REF, n as DEVICE_CA_KEY_REF, p as SYSTEM_SECRET_OWNER } from "../../device-ca-jxjSL8Ov.mjs";
3
- import { a as MESH_CA_KEY_REF } from "../../constants-BKX2QnIg.mjs";
1
+ import { B as KeychainAuditEntrySchema, Di as defineRecordKinds, Rr as BaseAddon, V as KeychainResetRecordSchema, Wi as normalizeSecretOwner, hn as keychainCapability, ji as formatSecretScope, la as EventCategory, mn as keychainAdminCapability, qi as parseSecretRef, z as KEYCHAIN_RESET_TRIGGER_ACTOR } from "../../dist-CkZIrsAP.mjs";
2
+ import { t as require_read_all_rows } from "../../read-all-rows-TaPqdWNF.mjs";
3
+ import { d as JWT_SIGNING_KEY_REF, n as DEVICE_CA_KEY_REF, p as SYSTEM_SECRET_OWNER } from "../../device-ca-Bh_ClxMO.mjs";
4
+ import { t as resolvePhase6UseRecordsPathForHub } from "../../phase6-declare-gate-BDWZuB2n.mjs";
5
+ import { a as MESH_CA_KEY_REF } from "../../constants-6XHGmEUF.mjs";
4
6
  import { n as getPlatformKeychainKey } from "../../platform-key-source-BWlq0jjn.mjs";
5
7
  import { createCipheriv, createDecipheriv, createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
6
8
  import { restrictDirToOwnerSync, restrictFileToOwnerSync, writeOwnerOnlyFileSync } from "@camstack/types/node";
@@ -382,8 +384,11 @@ var NOT_INITIALIZED = {
382
384
  state: "locked",
383
385
  reason: "not-initialized"
384
386
  };
385
- /** The only refs `importSecret` accepts: a camera's restream tokens (D870 migration). */
386
- var IMPORTABLE_REF = /^secret:\/\/stream-broker\/device\/[0-9]+\/rtspTokens$/;
387
+ /**
388
+ * Refs `importSecret` accepts for operator migration (D870): restream tokens and
389
+ * record-row secret refs (`recordSecretRef` — collection `records%3A<kind>`).
390
+ */
391
+ var IMPORTABLE_REF = /^(?:secret:\/\/stream-broker\/device\/[0-9]+\/rtspTokens|secret:\/\/[^/]+\/row\/records%3A[^/]+\/[^/]+\/.+)$/;
387
392
  var KeychainService = class {
388
393
  deps;
389
394
  unlock = NOT_INITIALIZED;
@@ -779,11 +784,12 @@ var KeychainService = class {
779
784
  return this.put(SYSTEM_SECRET_OWNER, ref, value, `user:${userId}`);
780
785
  }
781
786
  /**
782
- * An operator tool stores a carried-over value at an addon's own ref (D870).
783
- * Stored under the ref's owner, audited as the operator.
787
+ * An operator tool stores a carried-over value at a migration ref (D870):
788
+ * restream tokens or a `recordSecretRef` row field. Stored under the ref's
789
+ * owner, audited as the operator; never overwrites an existing value.
784
790
  */
785
791
  async importSecret(userId, ref, value) {
786
- if (!IMPORTABLE_REF.test(ref)) throw new Error(`keychain: "${ref}" is not an importable ref (restream tokens only)`);
792
+ if (!IMPORTABLE_REF.test(ref)) throw new Error(`keychain: "${ref}" is not an importable ref (restream tokens or record row secrets)`);
787
793
  if ((await this.deps.repo.getSecrets([ref])).has(ref)) throw new Error(`keychain: a value is already stored at ${ref} - import refuses to overwrite`);
788
794
  const parts = parseSecretRef(ref);
789
795
  if (parts === null) throw new Error(`keychain: "${ref}" is not a secret ref`);
@@ -1062,6 +1068,7 @@ function errMsg(err) {
1062
1068
  EventCategory.KeychainChanged;
1063
1069
  //#endregion
1064
1070
  //#region src/builtins/keychain/keychain-store.ts
1071
+ var import_read_all_rows = require_read_all_rows();
1065
1072
  /**
1066
1073
  * @durable class=config owner=keychain
1067
1074
  * write="`keychain.put` upserts one row per ref; `delete` removes it"
@@ -1367,8 +1374,16 @@ function toResetRecord(id, data) {
1367
1374
  var PAGE = 1e3;
1368
1375
  var KeychainRepository = class {
1369
1376
  door;
1370
- constructor(door) {
1377
+ records;
1378
+ constructor(door, records) {
1371
1379
  this.door = door;
1380
+ this.records = records;
1381
+ }
1382
+ static recordStoresOf(records) {
1383
+ return {
1384
+ audit: records.kind(keychainRecordKinds.audit),
1385
+ resets: records.kind(keychainRecordKinds.resets)
1386
+ };
1372
1387
  }
1373
1388
  async init() {
1374
1389
  await this.door.declareCollection({
@@ -1383,18 +1398,20 @@ var KeychainRepository = class {
1383
1398
  collection: KEYCHAIN_KEYS_COLLECTION,
1384
1399
  columns: KEY_COLUMNS
1385
1400
  });
1386
- await this.door.declareCollection({
1387
- collection: KEYCHAIN_RESETS_COLLECTION,
1388
- columns: RESET_COLUMNS
1389
- });
1390
- await this.door.declareCollection({
1391
- collection: KEYCHAIN_AUDIT_COLLECTION,
1392
- columns: AUDIT_COLUMNS,
1393
- indexes: [{
1394
- name: "idx_keychain_audit_at",
1395
- columns: ["at"]
1396
- }]
1397
- });
1401
+ if (this.records === void 0) {
1402
+ await this.door.declareCollection({
1403
+ collection: KEYCHAIN_RESETS_COLLECTION,
1404
+ columns: RESET_COLUMNS
1405
+ });
1406
+ await this.door.declareCollection({
1407
+ collection: KEYCHAIN_AUDIT_COLLECTION,
1408
+ columns: AUDIT_COLUMNS,
1409
+ indexes: [{
1410
+ name: "idx_keychain_audit_at",
1411
+ columns: ["at"]
1412
+ }]
1413
+ });
1414
+ }
1398
1415
  }
1399
1416
  async getSecrets(refs) {
1400
1417
  const out = /* @__PURE__ */ new Map();
@@ -1471,6 +1488,21 @@ var KeychainRepository = class {
1471
1488
  });
1472
1489
  }
1473
1490
  async appendAudit(row) {
1491
+ const kind = this.records?.audit;
1492
+ if (kind !== void 0) {
1493
+ const { id, at, action, actor, ref, detail } = row;
1494
+ await kind.put({
1495
+ id,
1496
+ at,
1497
+ data: {
1498
+ action,
1499
+ actor,
1500
+ ref,
1501
+ detail
1502
+ }
1503
+ });
1504
+ return;
1505
+ }
1474
1506
  await this.door.set({
1475
1507
  collection: KEYCHAIN_AUDIT_COLLECTION,
1476
1508
  key: row.id,
@@ -1478,6 +1510,20 @@ var KeychainRepository = class {
1478
1510
  });
1479
1511
  }
1480
1512
  async listAudit(limit) {
1513
+ const kind = this.records?.audit;
1514
+ if (kind !== void 0) {
1515
+ const rows = await (0, import_read_all_rows.readAllRows)(kind);
1516
+ rows.sort((a, b) => (b.at ?? 0) - (a.at ?? 0));
1517
+ const out = [];
1518
+ for (const row of rows.slice(0, limit)) {
1519
+ const parsed = toAuditRow(row.id, {
1520
+ ...row.data,
1521
+ at: row.at ?? 0
1522
+ });
1523
+ if (parsed !== null) out.push(parsed);
1524
+ }
1525
+ return out;
1526
+ }
1481
1527
  const rows = await this.door.query({
1482
1528
  collection: KEYCHAIN_AUDIT_COLLECTION,
1483
1529
  filter: {
@@ -1497,6 +1543,22 @@ var KeychainRepository = class {
1497
1543
  }
1498
1544
  /** Drop audit rows older than the retention window, then beyond the row bound. */
1499
1545
  async pruneAudit(nowMs) {
1546
+ const kind = this.records?.audit;
1547
+ if (kind !== void 0) {
1548
+ const ageCutoff = nowMs - AUDIT_RETENTION_MS;
1549
+ let deleted = 0;
1550
+ for (const row of await (0, import_read_all_rows.readAllRows)(kind)) if ((row.at ?? 0) <= ageCutoff) {
1551
+ await kind.delete(row.id);
1552
+ deleted += 1;
1553
+ }
1554
+ const remaining = await (0, import_read_all_rows.readAllRows)(kind);
1555
+ remaining.sort((a, b) => (b.at ?? 0) - (a.at ?? 0));
1556
+ for (const row of remaining.slice(AUDIT_MAX_ROWS)) {
1557
+ await kind.delete(row.id);
1558
+ deleted += 1;
1559
+ }
1560
+ return deleted;
1561
+ }
1500
1562
  const aged = await this.door.deleteWhere({
1501
1563
  collection: KEYCHAIN_AUDIT_COLLECTION,
1502
1564
  filter: { whereBetween: { at: [0, nowMs - AUDIT_RETENTION_MS] } }
@@ -1598,6 +1660,24 @@ var KeychainRepository = class {
1598
1660
  return cleared;
1599
1661
  }
1600
1662
  async putReset(record) {
1663
+ const kind = this.records?.resets;
1664
+ if (kind !== void 0) {
1665
+ const { id, at, actor, lockedReason, archived, archivedCollection, archivedKeysCollection, clearedSettingsKeys, acknowledgedAt } = record;
1666
+ await kind.put({
1667
+ id,
1668
+ at,
1669
+ data: {
1670
+ actor,
1671
+ lockedReason,
1672
+ archived,
1673
+ archivedCollection,
1674
+ archivedKeysCollection,
1675
+ clearedSettingsKeys: [...clearedSettingsKeys],
1676
+ acknowledgedAt
1677
+ }
1678
+ });
1679
+ return;
1680
+ }
1601
1681
  await this.door.set({
1602
1682
  collection: KEYCHAIN_RESETS_COLLECTION,
1603
1683
  key: record.id,
@@ -1608,6 +1688,17 @@ var KeychainRepository = class {
1608
1688
  });
1609
1689
  }
1610
1690
  async latestReset() {
1691
+ const kind = this.records?.resets;
1692
+ if (kind !== void 0) {
1693
+ const rows = await (0, import_read_all_rows.readAllRows)(kind);
1694
+ rows.sort((a, b) => (b.at ?? 0) - (a.at ?? 0));
1695
+ const row = rows[0];
1696
+ if (row === void 0) return null;
1697
+ return toResetRecord(row.id, {
1698
+ ...row.data,
1699
+ at: row.at ?? 0
1700
+ });
1701
+ }
1611
1702
  const row = (await this.door.query({
1612
1703
  collection: KEYCHAIN_RESETS_COLLECTION,
1613
1704
  filter: {
@@ -1621,6 +1712,44 @@ var KeychainRepository = class {
1621
1712
  return row === void 0 ? null : toResetRecord(row.id, row.data);
1622
1713
  }
1623
1714
  };
1715
+ var KeychainAuditBodySchema = KeychainAuditEntrySchema.omit({
1716
+ id: true,
1717
+ at: true
1718
+ });
1719
+ var KeychainResetBodySchema = KeychainResetRecordSchema.omit({
1720
+ id: true,
1721
+ at: true
1722
+ });
1723
+ var _keychainRecordKinds = defineRecordKinds({
1724
+ audit: {
1725
+ schema: KeychainAuditBodySchema,
1726
+ class: "audit",
1727
+ writeTrigger: "one row per write / delete / rotation / reveal / recovery download",
1728
+ device: "none",
1729
+ at: "required",
1730
+ indexes: [{
1731
+ name: "audit_at",
1732
+ fields: ["at"]
1733
+ }],
1734
+ retention: {
1735
+ owner: "keychain",
1736
+ reason: "90 days and at most 20_000 rows, pruned at boot and daily"
1737
+ },
1738
+ adoptsFrom: KEYCHAIN_AUDIT_COLLECTION
1739
+ },
1740
+ resets: {
1741
+ schema: KeychainResetBodySchema,
1742
+ class: "config",
1743
+ writeTrigger: "one row per keychain reset (System → Secrets, or the RESET_KEYCHAIN trigger file); acknowledgeReset stamps acknowledgedAt",
1744
+ device: "none",
1745
+ at: "required",
1746
+ retention: { none: "a handful of rows over a hub life; they name archive tables a reset left behind" },
1747
+ adoptsFrom: KEYCHAIN_RESETS_COLLECTION
1748
+ }
1749
+ });
1750
+ var keychainRecordKinds = _keychainRecordKinds;
1751
+ _keychainRecordKinds.audit;
1752
+ _keychainRecordKinds.resets;
1624
1753
  //#endregion
1625
1754
  //#region src/builtins/keychain/keychain-usage.ts
1626
1755
  /**
@@ -1817,8 +1946,9 @@ var KeychainAddon = class extends BaseAddon {
1817
1946
  warn: (message, meta) => ctx.logger.warn(message, meta ? { meta } : void 0),
1818
1947
  error: (message, meta) => ctx.logger.error(message, meta ? { meta } : void 0)
1819
1948
  };
1949
+ const records = ctx.records;
1820
1950
  const service = new KeychainService({
1821
- repo: new KeychainRepository(door),
1951
+ repo: new KeychainRepository(door, records !== void 0 && await resolvePhase6UseRecordsPathForHub(ctx, "keychain", keychainRecordKinds, ["keychain:audit", "keychain:resets"]) && records !== void 0 ? KeychainRepository.recordStoresOf(records) : void 0),
1822
1952
  candidates: async () => {
1823
1953
  return buildKeySourceCandidates({
1824
1954
  config: readKeyConfig(await ctx.settings?.getSection("keychain") ?? {}),
@@ -97,8 +97,9 @@ export declare class KeychainService {
97
97
  version: number;
98
98
  }>;
99
99
  /**
100
- * An operator tool stores a carried-over value at an addon's own ref (D870).
101
- * Stored under the ref's owner, audited as the operator.
100
+ * An operator tool stores a carried-over value at a migration ref (D870):
101
+ * restream tokens or a `recordSecretRef` row field. Stored under the ref's
102
+ * owner, audited as the operator; never overwrites an existing value.
102
103
  */
103
104
  importSecret(userId: string, ref: string, value: string): Promise<{
104
105
  ref: string;
@@ -7,7 +7,9 @@
7
7
  * The repository takes a narrow door port rather than the whole tRPC client so
8
8
  * the service can be exercised against an in-memory door in tests.
9
9
  */
10
- import type { ISettingsStoreProvider, KeychainAuditAction, KeychainResetRecord } from "@camstack/types";
10
+ import type { ISettingsStoreProvider, KeychainAuditAction, KeychainResetRecord, RecordKindHandle, RecordsAccess } from "@camstack/types";
11
+ import { type KeychainAuditBodySchema, type KeychainResetBodySchema } from "./record-kinds.js";
12
+ import type { z } from "zod";
11
13
  /**
12
14
  * @durable class=config owner=keychain
13
15
  * write="`keychain.put` upserts one row per ref; `delete` removes it"
@@ -74,9 +76,17 @@ export interface KeychainAuditRow {
74
76
  }
75
77
  /** The subset of the settings door the repository uses. */
76
78
  export type KeychainDoor = Pick<ISettingsStoreProvider, "declareCollection" | "get" | "set" | "query" | "delete" | "deleteWhere">;
79
+ type KeychainAuditBody = z.infer<typeof KeychainAuditBodySchema>;
80
+ type KeychainResetBody = z.infer<typeof KeychainResetBodySchema>;
81
+ export interface KeychainRecordStores {
82
+ readonly audit: RecordKindHandle<KeychainAuditBody>;
83
+ readonly resets: RecordKindHandle<KeychainResetBody>;
84
+ }
77
85
  export declare class KeychainRepository {
78
86
  private readonly door;
79
- constructor(door: KeychainDoor);
87
+ private readonly records?;
88
+ constructor(door: KeychainDoor, records?: KeychainRecordStores);
89
+ static recordStoresOf(records: Pick<RecordsAccess, "kind">): KeychainRecordStores;
80
90
  init(): Promise<void>;
81
91
  getSecrets(refs: readonly string[]): Promise<ReadonlyMap<string, KeychainSecretRow>>;
82
92
  /** Every row, paged by primary key. */
@@ -112,3 +122,4 @@ export declare class KeychainRepository {
112
122
  putReset(record: KeychainResetRecord): Promise<void>;
113
123
  latestReset(): Promise<KeychainResetRecord | null>;
114
124
  }
125
+ export {};
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Record kinds owned by keychain (phase 4 — audit and resets only).
3
+ */
4
+ import { KeychainAuditEntrySchema, KeychainResetRecordSchema, type DefinedRecordKind } from "@camstack/types";
5
+ import { z } from "zod";
6
+ export type KeychainAuditBody = Omit<z.infer<typeof KeychainAuditEntrySchema>, "id" | "at">;
7
+ export declare const KeychainAuditBodySchema: z.ZodType<KeychainAuditBody>;
8
+ export type KeychainResetBody = Omit<z.infer<typeof KeychainResetRecordSchema>, "id" | "at">;
9
+ export declare const KeychainResetBodySchema: z.ZodType<KeychainResetBody>;
10
+ export type KeychainRecordKindsMap = {
11
+ readonly audit: DefinedRecordKind<z.ZodType<KeychainAuditBody>>;
12
+ readonly resets: DefinedRecordKind<z.ZodType<KeychainResetBody>>;
13
+ };
14
+ export declare const keychainRecordKinds: KeychainRecordKindsMap;
15
+ export declare const keychainAuditRecordKind: DefinedRecordKind<z.ZodType<KeychainAuditBody>>;
16
+ export declare const keychainResetsRecordKind: DefinedRecordKind<z.ZodType<KeychainResetBody>>;
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../../chunk-Cek0wNdY.js");
3
- const require_dist = require("../../dist-D1vECb_6.js");
3
+ const require_dist = require("../../dist-BkNfEJKa.js");
4
4
  //#region src/builtins/liveness-monitor/liveness-checks.ts
5
5
  var NO_DEVICES = "liveness:no-devices";
6
6
  var ALL_OFFLINE = "liveness:all-devices-offline";
@@ -1,4 +1,4 @@
1
- import { $i as EventCategory, Fr as BaseAddon, G as RECORDING_SOURCE_CAMSTACK_ADDON, K as RecordingStatusSchema, Pr as errMsg, yi as createEvent } from "../../dist-DERK-gP5.mjs";
1
+ import { Ci as createEvent, J as RECORDING_SOURCE_CAMSTACK_ADDON, Lr as errMsg, Rr as BaseAddon, Y as RecordingStatusSchema, la as EventCategory } from "../../dist-CkZIrsAP.mjs";
2
2
  //#region src/builtins/liveness-monitor/liveness-checks.ts
3
3
  var NO_DEVICES = "liveness:no-devices";
4
4
  var ALL_OFFLINE = "liveness:all-devices-offline";
@@ -103,4 +103,6 @@ export declare const USER_EXTERNAL_IDENTITIES_COLLECTION = "user_external_identi
103
103
  * managers. Idempotent — `declareCollection` is a no-op when the
104
104
  * collection has already been declared (same shape).
105
105
  */
106
- export declare function declareAuthSchema(store: SettingsStoreClient): Promise<void>;
106
+ export declare function declareAuthSchema(store: SettingsStoreClient, options?: {
107
+ readonly skipCollections?: readonly string[];
108
+ }): Promise<void>;