@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
@@ -1,4 +1,5 @@
1
- import { Ar as errMsg, Br as WELL_KNOWN_TAB_MAP, Bt as deviceStatusCapability, C as DAY_NAMES, Ci as toSecretFieldView, Dr as DeviceFeature, Ei as EventCategory, En as normalizeUnit, Gn as runtimeStatePolicyFor, Ht as enumerateItemArrayFields, Kt as expandContainer, Lt as deviceExtensionCapability, N as FieldClaimModeSchema, Nt as defineExtensionSlotProvider, Or as DeviceRole, Ot as createDeviceExtensionProvider, P as FieldClaimSchema, Qt as formatMinutes, Rt as deviceManagerCapability, Ti as userError, Ut as enumerateSchemaFields, V as MINUTES_PER_DAY, Y as STREAM_PROFILE_META, Zn as siteZoneKey, _i as resolveSecretMarkers, ai as isSecretClear, c as CAMERA_SWITCH_ORDER, dn as legacyAutoLinkIds, hn as locationIconKey, ht as buildStreamParamsConfigSchema, ii as isKeychainStoredField, j as DeviceStatusSchema, jr as BaseAddon, kn as parseStreamParamsFormPatch, kr as DeviceType, ni as isDeviceConfigCap, oi as isSecretMarker, qr as collectZodSecretPaths, r as ALL_CAPABILITY_DEFINITIONS, si as isSecretMarkerLike, u as CAP_NAMES_WITH_STATUS, vt as canonicalIconKey, wi as transformSecretWrite, xi as sleep$1, yi as secretTreeFromPaths, zr as SECRET_CLEAR, zt as deviceStateCapability } from "../../dist-Bxt_S-9a.mjs";
1
+ import { $ as STREAM_PROFILE_META, $i as resolveSecretMarkers, C as DAY_NAMES, Ct as canonicalIconKey, Di as defineRecordKinds, F as FieldClaimModeSchema, Fi as isKeychainStoredField, Fr as DeviceRole, G as MINUTES_PER_DAY, Gt as deviceStatusCapability, Ht as deviceExtensionCapability, I as FieldClaimSchema, Ii as isSecretClear, Ir as DeviceType, Jt as enumerateSchemaFields, Li as isSecretMarker, Lr as errMsg, M as DeviceStatusSchema, N as DeviceTombstoneSchema, Ni as isDeviceConfigCap, Nt as createDeviceExtensionProvider, Pn as parseStreamParamsFormPatch, Pr as DeviceFeature, Qn as runtimeStatePolicyFor, Ri as isSecretMarkerLike, Rr as BaseAddon, Rt as defineExtensionSlotProvider, Si as collectZodSecretPaths, Ut as deviceManagerCapability, Wt as deviceStateCapability, Zt as expandContainer, aa as toSecretFieldView, bn as locationIconKey, bt as buildStreamParamsConfigSchema, c as CAMERA_SWITCH_ORDER, gn as legacyAutoLinkIds, ir as siteZoneKey, jn as normalizeUnit, la as EventCategory, oa as transformSecretWrite, pi as WELL_KNOWN_TAB_MAP, qt as enumerateItemArrayFields, r as ALL_CAPABILITY_DEFINITIONS, ra as sleep$1, rn as formatMinutes, sa as userError, ta as secretTreeFromPaths, u as CAP_NAMES_WITH_STATUS, ui as SECRET_CLEAR } from "../../dist-BNunRyXT.mjs";
2
+ import { t as require_read_all_rows } from "../../read-all-rows-TaPqdWNF.mjs";
2
3
  import { t as prefixRange } from "../../prefix-range-Dl0znowN.mjs";
3
4
  import { t as loadPrefixed } from "../../prefix-walk-DAOBSyH1.mjs";
4
5
  import { r as purgeRetiredSettingsRows } from "../../retired-settings-keys-Bhwe4ymb.mjs";
@@ -1095,6 +1096,10 @@ function mergeAggregates(parts) {
1095
1096
  function isRecord$2(value) {
1096
1097
  return typeof value === "object" && value !== null && !Array.isArray(value);
1097
1098
  }
1099
+ function isConfigFieldWithValue(field) {
1100
+ if (!isRecord$2(field)) return false;
1101
+ return typeof field.type === "string" && typeof field.key === "string" && "value" in field;
1102
+ }
1098
1103
  /** The declared paths that name a top-level config key. */
1099
1104
  function topLevelKeys(paths) {
1100
1105
  return new Set(paths.filter((p) => p.length > 0 && !p.includes(".") && !p.includes("[")));
@@ -1114,8 +1119,8 @@ function viewField(field, stored, declared) {
1114
1119
  fields: tab["fields"].map((f) => viewField(f, stored, declared))
1115
1120
  } : tab)
1116
1121
  };
1117
- const key = field["key"];
1118
- if (typeof key !== "string" || !("value" in field)) return field;
1122
+ if (!isConfigFieldWithValue(field)) return field;
1123
+ const key = field.key;
1119
1124
  const marker = stored[key];
1120
1125
  if (!isSecretMarker(marker)) return field;
1121
1126
  const secretByType = isKeychainStoredField(field);
@@ -7868,6 +7873,104 @@ var DeviceMetaStore = class {
7868
7873
  });
7869
7874
  };
7870
7875
  //#endregion
7876
+ //#region src/builtins/device-manager/record-kinds.ts
7877
+ var import_read_all_rows = require_read_all_rows();
7878
+ var _deviceManagerRecordKinds = defineRecordKinds({ tombstones: {
7879
+ schema: DeviceTombstoneSchema.omit({ deviceId: true }),
7880
+ class: "ledger",
7881
+ writeTrigger: "`removeDevice` records one row per deleted device after the device row is gone; re-record keeps the earlier `deletedAt`",
7882
+ device: "none",
7883
+ at: "required",
7884
+ indexes: [{
7885
+ name: "deleted_at",
7886
+ fields: ["deletedAt"]
7887
+ }],
7888
+ retention: {
7889
+ owner: "device-manager",
7890
+ reason: "90 days (`DEVICE_TOMBSTONE_RETENTION_MS`), pruned whenever a tombstone is written or the list is read"
7891
+ },
7892
+ adoptsFrom: DEVICE_TOMBSTONES_COLLECTION
7893
+ } });
7894
+ var deviceManagerRecordKinds = _deviceManagerRecordKinds;
7895
+ _deviceManagerRecordKinds.tombstones;
7896
+ //#endregion
7897
+ //#region src/builtins/device-manager/device-tombstone-store.ts
7898
+ /**
7899
+ * The tombstones of deleted devices (D865) — `tombstones` record kind (phase 4).
7900
+ */
7901
+ var DEVICE_TOMBSTONES_COLLECTION = "device-manager:tombstones";
7902
+ /** More than the engine's default row cap, so a read is never silently truncated. */
7903
+ var TOMBSTONE_READ_LIMIT = 2e4;
7904
+ function rowToTombstone(id, body) {
7905
+ const deviceId = Number(id);
7906
+ if (!Number.isInteger(deviceId) || deviceId <= 0) return null;
7907
+ return {
7908
+ deviceId,
7909
+ deletedAt: body.deletedAt,
7910
+ providerAddonId: body.providerAddonId
7911
+ };
7912
+ }
7913
+ var DeviceTombstoneStore = class DeviceTombstoneStore {
7914
+ kind;
7915
+ logger;
7916
+ now;
7917
+ retentionMs;
7918
+ constructor(opts) {
7919
+ this.kind = opts.kind;
7920
+ this.logger = opts.logger;
7921
+ this.now = opts.now ?? (() => Date.now());
7922
+ this.retentionMs = opts.retentionMs ?? 7776e6;
7923
+ }
7924
+ static of(records, logger) {
7925
+ return new DeviceTombstoneStore({
7926
+ kind: records.kind(deviceManagerRecordKinds.tombstones),
7927
+ logger
7928
+ });
7929
+ }
7930
+ /** Record a deletion. Re-recording the same id keeps the EARLIER `deletedAt`. */
7931
+ async record(tombstone) {
7932
+ const key = String(tombstone.deviceId);
7933
+ const existing = await this.kind.get(key);
7934
+ if ((existing !== null ? rowToTombstone(existing.id, existing.data)?.deletedAt : void 0) === void 0) await this.kind.put({
7935
+ id: key,
7936
+ at: tombstone.deletedAt,
7937
+ data: {
7938
+ deletedAt: tombstone.deletedAt,
7939
+ providerAddonId: tombstone.providerAddonId
7940
+ }
7941
+ });
7942
+ await this.pruneExpired();
7943
+ }
7944
+ /** Tombstones with `deletedAt >= sinceMs`, oldest first. Expired ones are pruned first. */
7945
+ async listSince(sinceMs) {
7946
+ await this.pruneExpired();
7947
+ const floor = Math.max(sinceMs, this.now() - this.retentionMs);
7948
+ const rows = await (0, import_read_all_rows.readAllRows)(this.kind, {
7949
+ atFrom: floor,
7950
+ order: "at"
7951
+ });
7952
+ const out = [];
7953
+ for (const row of rows) {
7954
+ if (out.length >= TOMBSTONE_READ_LIMIT) break;
7955
+ const decoded = rowToTombstone(row.id, row.data);
7956
+ if (decoded !== null && decoded.deletedAt >= floor) out.push(decoded);
7957
+ }
7958
+ return out;
7959
+ }
7960
+ /** Delete tombstones older than the retention window. Best-effort: a failure is logged. */
7961
+ async pruneExpired() {
7962
+ try {
7963
+ const cutoff = this.now() - this.retentionMs;
7964
+ const rows = await (0, import_read_all_rows.readAllRows)(this.kind, { atTo: cutoff - 1 });
7965
+ for (const row of rows) await this.kind.delete(row.id);
7966
+ return rows.length;
7967
+ } catch (err) {
7968
+ this.logger.warn("device tombstone prune failed — retried on the next write", { meta: { error: errMsg(err) } });
7969
+ return 0;
7970
+ }
7971
+ }
7972
+ };
7973
+ //#endregion
7871
7974
  //#region src/builtins/device-manager/fleet-read-census.ts
7872
7975
  /** How many stack frames identify a call site. One frame is a method; three are
7873
7976
  * a cause — `listFleet < listAll < onDeviceRegistered` is the answer, `listAll`
@@ -8769,181 +8872,6 @@ var DeviceRowStore = class {
8769
8872
  }
8770
8873
  };
8771
8874
  //#endregion
8772
- //#region src/builtins/device-manager/device-tombstone-store.ts
8773
- /**
8774
- * The tombstones of deleted devices (D865).
8775
- *
8776
- * A device DELETE is a fact other addons must be able to learn reliably, long
8777
- * after the `DeviceUnregistered` event (telemetry, droppable — D8/D11) is gone.
8778
- * device-manager is the only authority on whether a device exists, so the record
8779
- * of a deletion lives here, in its own collection, beside the device ledger.
8780
- *
8781
- * ## What a tombstone is NOT
8782
- *
8783
- * It is not "the device is unregistered / offline / its provider is restarting".
8784
- * Those are states of a device that still exists; only {@link record}'s one
8785
- * caller — `removeDevice`, the single door every delete converges on — writes a
8786
- * tombstone. Anything that reconciles from tombstones therefore can never
8787
- * destroy data of a device that merely went quiet.
8788
- *
8789
- * ## Expiry
8790
- *
8791
- * {@link DEVICE_TOMBSTONE_RETENTION_MS} (90 days). A tombstone older than that
8792
- * is deleted the next time one is written or read. Ninety days is generous on
8793
- * purpose: an addon that stayed disabled for a quarter still learns of the
8794
- * deletions on its return. Data of a device deleted longer ago than that is
8795
- * reachable only by the admin "clean data of deleted devices" action.
8796
- */
8797
- /**
8798
- * @durable class=ledger owner=device-manager
8799
- * write="`removeDevice` records one row per deleted device (key = device id) after the
8800
- * device row is gone"
8801
- * retention="90 days (`DEVICE_TOMBSTONE_RETENTION_MS`), pruned whenever a tombstone is
8802
- * written or the list is read. Bounded by the deletions an operator makes in a quarter."
8803
- */
8804
- var DEVICE_TOMBSTONES_COLLECTION = "device-manager:tombstones";
8805
- var DEVICE_TOMBSTONE_COLUMNS = [
8806
- {
8807
- name: "id",
8808
- type: "TEXT",
8809
- primaryKey: true,
8810
- notNull: true
8811
- },
8812
- {
8813
- name: "deviceId",
8814
- type: "INTEGER",
8815
- notNull: true
8816
- },
8817
- {
8818
- name: "deletedAt",
8819
- type: "INTEGER",
8820
- notNull: true
8821
- },
8822
- {
8823
- name: "providerAddonId",
8824
- type: "TEXT",
8825
- notNull: true
8826
- }
8827
- ];
8828
- var DEVICE_TOMBSTONE_INDEXES = [{
8829
- name: "idx_dm_tombstones_deleted_at",
8830
- columns: ["deletedAt"]
8831
- }];
8832
- /** More than the engine's default row cap, so a read is never silently truncated. */
8833
- var TOMBSTONE_READ_LIMIT = 2e4;
8834
- function decodeTombstone(raw) {
8835
- const deviceId = raw["deviceId"];
8836
- const deletedAt = raw["deletedAt"];
8837
- const providerAddonId = raw["providerAddonId"];
8838
- if (typeof deviceId !== "number" || !Number.isInteger(deviceId) || deviceId <= 0) return null;
8839
- if (typeof deletedAt !== "number" || typeof providerAddonId !== "string") return null;
8840
- return {
8841
- deviceId,
8842
- deletedAt,
8843
- providerAddonId
8844
- };
8845
- }
8846
- var DeviceTombstoneStore = class {
8847
- backend;
8848
- logger;
8849
- now;
8850
- retentionMs;
8851
- declared = null;
8852
- constructor(opts) {
8853
- this.backend = opts.backend;
8854
- this.logger = opts.logger;
8855
- this.now = opts.now ?? (() => Date.now());
8856
- this.retentionMs = opts.retentionMs ?? 7776e6;
8857
- }
8858
- /**
8859
- * Declare the collection now. Idempotent; a rejection is not latched.
8860
- *
8861
- * Called at device-manager init (D871) so the table exists on a hub that has
8862
- * not deleted a device yet. It used to be declared only by the first
8863
- * `record` / `listSince`, i.e. by the first delete or by an implementer's
8864
- * reconcile — so a hub whose implementers had not been redeployed, and where
8865
- * nothing was deleted, never had the table, and the census read that as
8866
- * "D865 is not running". A DECLARATION only: nothing is read, written or
8867
- * purged here.
8868
- */
8869
- declare() {
8870
- if (this.declared !== null) return this.declared;
8871
- const run = this.backend.declareCollection({
8872
- collection: DEVICE_TOMBSTONES_COLLECTION,
8873
- columns: DEVICE_TOMBSTONE_COLUMNS,
8874
- indexes: DEVICE_TOMBSTONE_INDEXES
8875
- }).catch((err) => {
8876
- this.declared = null;
8877
- throw err;
8878
- });
8879
- this.declared = run;
8880
- return run;
8881
- }
8882
- /** Record a deletion. Re-recording the same id keeps the EARLIER `deletedAt`. */
8883
- async record(tombstone) {
8884
- await this.declare();
8885
- const key = String(tombstone.deviceId);
8886
- const existing = await this.backend.get({
8887
- collection: DEVICE_TOMBSTONES_COLLECTION,
8888
- key
8889
- });
8890
- if ((isPlainObject(existing) ? decodeTombstone(existing) : null) === null) await this.backend.set({
8891
- collection: DEVICE_TOMBSTONES_COLLECTION,
8892
- key,
8893
- value: {
8894
- deviceId: tombstone.deviceId,
8895
- deletedAt: tombstone.deletedAt,
8896
- providerAddonId: tombstone.providerAddonId
8897
- }
8898
- });
8899
- await this.pruneExpired();
8900
- }
8901
- /** Tombstones with `deletedAt >= sinceMs`, oldest first. Expired ones are pruned first. */
8902
- async listSince(sinceMs) {
8903
- await this.declare();
8904
- await this.pruneExpired();
8905
- const floor = Math.max(sinceMs, this.now() - this.retentionMs);
8906
- const rows = await this.backend.query({
8907
- collection: DEVICE_TOMBSTONES_COLLECTION,
8908
- filter: {
8909
- whereBetween: { deletedAt: [floor, Number.MAX_SAFE_INTEGER] },
8910
- orderBy: {
8911
- field: "deletedAt",
8912
- direction: "asc"
8913
- },
8914
- limit: TOMBSTONE_READ_LIMIT
8915
- }
8916
- });
8917
- const out = [];
8918
- for (const row of rows) {
8919
- const decoded = decodeTombstone(row.data);
8920
- if (decoded !== null) out.push(decoded);
8921
- }
8922
- return out;
8923
- }
8924
- /** Delete tombstones older than the retention window. Best-effort: a failure is logged. */
8925
- async pruneExpired() {
8926
- try {
8927
- const cutoff = this.now() - this.retentionMs;
8928
- const stale = await this.backend.query({
8929
- collection: DEVICE_TOMBSTONES_COLLECTION,
8930
- filter: {
8931
- whereBetween: { deletedAt: [0, cutoff - 1] },
8932
- limit: TOMBSTONE_READ_LIMIT
8933
- }
8934
- });
8935
- for (const row of stale) await this.backend.delete({
8936
- collection: DEVICE_TOMBSTONES_COLLECTION,
8937
- key: row.id
8938
- });
8939
- return stale.length;
8940
- } catch (err) {
8941
- this.logger.warn("device tombstone prune failed — retried on the next write", { meta: { error: errMsg(err) } });
8942
- return 0;
8943
- }
8944
- }
8945
- };
8946
- //#endregion
8947
8875
  //#region src/builtins/device-manager/device-state-claims.ts
8948
8876
  function createDeviceStateClaimMethods(deps) {
8949
8877
  const { mirror, index, settings, logger } = deps;
@@ -10859,15 +10787,10 @@ var DeviceManagerAddon = class extends BaseAddon {
10859
10787
  const deviceRows = new DeviceRowStore(deviceRowBackendOf(settingsStoreApi), this.ctx.logger.child("rows"));
10860
10788
  await deviceRows.declare();
10861
10789
  this.deviceRows = deviceRows;
10862
- const tombstones = new DeviceTombstoneStore({
10863
- backend: deviceRowBackendOf(settingsStoreApi),
10864
- logger: this.ctx.logger.child("tombstones")
10865
- });
10866
- try {
10867
- await tombstones.declare();
10868
- } catch (err) {
10869
- this.ctx.logger.warn("device tombstones collection not declared at init — retried on first use", { meta: { error: err instanceof Error ? err.message : String(err) } });
10870
- }
10790
+ const records = this.ctx.records;
10791
+ if (records === void 0) throw new Error("[device-manager] ctx.records is required on the hub");
10792
+ await records.declare(deviceManagerRecordKinds);
10793
+ const tombstones = DeviceTombstoneStore.of(records, this.ctx.logger.child("tombstones"));
10871
10794
  this.staleWrapperActivations.checkOnce(() => readBindingsStore(this.bindingsDeps));
10872
10795
  try {
10873
10796
  await purgeRetiredSettingsRows(deviceRows.retiredRowStore(), this.ctx.logger.child("RetiredRows"));
@@ -1,64 +1,24 @@
1
1
  /**
2
- * The tombstones of deleted devices (D865).
3
- *
4
- * A device DELETE is a fact other addons must be able to learn reliably, long
5
- * after the `DeviceUnregistered` event (telemetry, droppable — D8/D11) is gone.
6
- * device-manager is the only authority on whether a device exists, so the record
7
- * of a deletion lives here, in its own collection, beside the device ledger.
8
- *
9
- * ## What a tombstone is NOT
10
- *
11
- * It is not "the device is unregistered / offline / its provider is restarting".
12
- * Those are states of a device that still exists; only {@link record}'s one
13
- * caller — `removeDevice`, the single door every delete converges on — writes a
14
- * tombstone. Anything that reconciles from tombstones therefore can never
15
- * destroy data of a device that merely went quiet.
16
- *
17
- * ## Expiry
18
- *
19
- * {@link DEVICE_TOMBSTONE_RETENTION_MS} (90 days). A tombstone older than that
20
- * is deleted the next time one is written or read. Ninety days is generous on
21
- * purpose: an addon that stayed disabled for a quarter still learns of the
22
- * deletions on its return. Data of a device deleted longer ago than that is
23
- * reachable only by the admin "clean data of deleted devices" action.
24
- */
25
- import { type CollectionColumn, type CollectionIndex, type DeviceTombstone, type IScopedLogger } from "@camstack/types";
26
- import { type DeviceRowBackend } from "./device-row-store.js";
27
- /**
28
- * @durable class=ledger owner=device-manager
29
- * write="`removeDevice` records one row per deleted device (key = device id) after the
30
- * device row is gone"
31
- * retention="90 days (`DEVICE_TOMBSTONE_RETENTION_MS`), pruned whenever a tombstone is
32
- * written or the list is read. Bounded by the deletions an operator makes in a quarter."
2
+ * The tombstones of deleted devices (D865) — `tombstones` record kind (phase 4).
33
3
  */
4
+ import { type DeviceTombstone, type IScopedLogger, type RecordKindHandle, type RecordsAccess } from "@camstack/types";
5
+ import { DeviceTombstoneBodySchema } from "./record-kinds.js";
6
+ import type { z } from "zod";
34
7
  export declare const DEVICE_TOMBSTONES_COLLECTION = "device-manager:tombstones";
35
- export declare const DEVICE_TOMBSTONE_COLUMNS: readonly CollectionColumn[];
36
- export declare const DEVICE_TOMBSTONE_INDEXES: readonly CollectionIndex[];
8
+ type TombstoneBody = z.infer<typeof DeviceTombstoneBodySchema>;
37
9
  export interface DeviceTombstoneStoreOptions {
38
- readonly backend: DeviceRowBackend;
10
+ readonly kind: RecordKindHandle<TombstoneBody>;
39
11
  readonly logger: IScopedLogger;
40
12
  readonly now?: () => number;
41
13
  readonly retentionMs?: number;
42
14
  }
43
15
  export declare class DeviceTombstoneStore {
44
- private readonly backend;
16
+ private readonly kind;
45
17
  private readonly logger;
46
18
  private readonly now;
47
19
  private readonly retentionMs;
48
- private declared;
49
20
  constructor(opts: DeviceTombstoneStoreOptions);
50
- /**
51
- * Declare the collection now. Idempotent; a rejection is not latched.
52
- *
53
- * Called at device-manager init (D871) so the table exists on a hub that has
54
- * not deleted a device yet. It used to be declared only by the first
55
- * `record` / `listSince`, i.e. by the first delete or by an implementer's
56
- * reconcile — so a hub whose implementers had not been redeployed, and where
57
- * nothing was deleted, never had the table, and the census read that as
58
- * "D865 is not running". A DECLARATION only: nothing is read, written or
59
- * purged here.
60
- */
61
- declare(): Promise<void>;
21
+ static of(records: Pick<RecordsAccess, "kind">, logger: IScopedLogger): DeviceTombstoneStore;
62
22
  /** Record a deletion. Re-recording the same id keeps the EARLIER `deletedAt`. */
63
23
  record(tombstone: DeviceTombstone): Promise<void>;
64
24
  /** Tombstones with `deletedAt >= sinceMs`, oldest first. Expired ones are pruned first. */
@@ -66,3 +26,4 @@ export declare class DeviceTombstoneStore {
66
26
  /** Delete tombstones older than the retention window. Best-effort: a failure is logged. */
67
27
  pruneExpired(): Promise<number>;
68
28
  }
29
+ export {};
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Record kinds owned by device-manager (records plan phase 4).
3
+ */
4
+ import { z } from "zod";
5
+ import { DeviceTombstoneSchema, type DefinedRecordKind } from "@camstack/types";
6
+ /** Body excludes `deviceId` — the record id is `String(deviceId)`. */
7
+ export type DeviceTombstoneBody = Omit<z.infer<typeof DeviceTombstoneSchema>, "deviceId">;
8
+ export declare const DeviceTombstoneBodySchema: z.ZodType<DeviceTombstoneBody>;
9
+ export type DeviceManagerRecordKindsMap = {
10
+ readonly tombstones: DefinedRecordKind<z.ZodType<DeviceTombstoneBody>>;
11
+ };
12
+ export declare const deviceManagerRecordKinds: DeviceManagerRecordKindsMap;
13
+ /** Narrow kind for `records.kind()`. */
14
+ export declare const deviceTombstonesRecordKind: DefinedRecordKind<z.ZodType<DeviceTombstoneBody>>;
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-D9qT3jHr.js");
6
+ const require_dist = require("../../dist-DgOG8flk.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  //#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
9
9
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
@@ -1,4 +1,4 @@
1
- import { gn as logDestinationCapability, jr as BaseAddon } from "../../dist-Bxt_S-9a.mjs";
1
+ import { Rr as BaseAddon, xn as logDestinationCapability } from "../../dist-BNunRyXT.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  //#region src/builtins/hub-forwarder/hub-forwarder-destination.ts
4
4
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;