@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.
- package/dist/addon-runner.js +40 -31
- package/dist/addon-runner.mjs +41 -32
- package/dist/{agent-https-DlpTMDqA.js → agent-https-5DYAOJMO.js} +810 -12
- package/dist/{agent-https-U0d4uvn2.mjs → agent-https-BWUEf6ev.mjs} +697 -13
- package/dist/auth/admin-token-manager.d.ts +9 -3
- package/dist/auth/api-key-manager.d.ts +9 -3
- package/dist/auth/auth-audit-log.d.ts +9 -3
- package/dist/auth/device-credential-manager.d.ts +5 -1
- package/dist/auth/external-identity-manager.d.ts +8 -21
- package/dist/auth/login-session-manager.d.ts +11 -3
- package/dist/auth/scoped-token-manager.d.ts +8 -52
- package/dist/auth/totp-manager.d.ts +11 -3
- package/dist/auth/user-manager.d.ts +10 -17
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alert-store.d.ts +32 -0
- package/dist/builtins/alerts/alerts.addon.d.ts +9 -2
- package/dist/builtins/alerts/alerts.addon.js +373 -154
- package/dist/builtins/alerts/alerts.addon.mjs +372 -154
- package/dist/builtins/alerts/critical-push.d.ts +4 -0
- package/dist/builtins/alerts/emit-alert-policy.d.ts +28 -0
- package/dist/builtins/alerts/record-kinds.d.ts +15 -0
- package/dist/builtins/autotrack/index.js +1 -1
- package/dist/builtins/autotrack/index.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +1 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +134 -193
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +134 -193
- package/dist/builtins/backup-orchestrator/destination-policy.d.ts +4 -2
- package/dist/builtins/backup-orchestrator/encryption-key-store.d.ts +4 -2
- package/dist/builtins/backup-orchestrator/record-kinds.d.ts +58 -0
- package/dist/builtins/backup-orchestrator/schedule-store.d.ts +4 -2
- package/dist/builtins/backup-orchestrator/seed-marker-store.d.ts +4 -2
- package/dist/builtins/calendars/calendar-prefs-store.d.ts +13 -5
- package/dist/builtins/calendars/calendars.addon.d.ts +2 -2
- package/dist/builtins/calendars/calendars.addon.js +67 -64
- package/dist/builtins/calendars/calendars.addon.mjs +59 -64
- package/dist/builtins/calendars/record-kinds.d.ts +18 -0
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/cluster-agent/record-kinds.d.ts +36 -0
- package/dist/builtins/composer/composer.addon.js +2 -2
- package/dist/builtins/composer/composer.addon.mjs +2 -2
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/block-settings-store.d.ts +8 -4
- package/dist/builtins/core-blocks/core-block-store.d.ts +8 -16
- package/dist/builtins/core-blocks/core-blocks.addon.js +85 -112
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +86 -113
- package/dist/builtins/core-blocks/index.mjs +1 -1
- package/dist/builtins/core-blocks/record-kinds.d.ts +26 -0
- package/dist/builtins/device-manager/device-manager.addon.js +111 -187
- package/dist/builtins/device-manager/device-manager.addon.mjs +110 -187
- package/dist/builtins/device-manager/device-tombstone-store.d.ts +9 -48
- package/dist/builtins/device-manager/record-kinds.d.ts +14 -0
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/keychain/index.js +152 -22
- package/dist/builtins/keychain/index.mjs +152 -22
- package/dist/builtins/keychain/keychain-service.d.ts +3 -2
- package/dist/builtins/keychain/keychain-store.d.ts +13 -2
- package/dist/builtins/keychain/record-kinds.d.ts +16 -0
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/auth-schema.d.ts +3 -1
- package/dist/builtins/local-auth/local-auth.addon.js +2903 -2123
- package/dist/builtins/local-auth/local-auth.addon.mjs +2904 -2124
- package/dist/builtins/local-auth/oauth-session-manager.d.ts +8 -48
- package/dist/builtins/local-auth/record-kinds.d.ts +141 -0
- package/dist/builtins/local-network/local-network.addon.js +2 -2
- package/dist/builtins/local-network/local-network.addon.mjs +2 -2
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/record-entries/index.js +1 -1
- package/dist/builtins/record-entries/index.mjs +1 -1
- package/dist/builtins/records/legacy-table-row-count.d.ts +5 -0
- package/dist/builtins/records/phase6-declare-gate.d.ts +28 -0
- package/dist/builtins/records-isolated.d.ts +10 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/index.js +1 -1
- package/dist/builtins/sqlite-storage/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/integration-record-kinds.d.ts +30 -0
- package/dist/builtins/sqlite-storage/integration-registry.d.ts +10 -16
- package/dist/builtins/sqlite-storage/records/count-settings-array-legacy.d.ts +5 -0
- package/dist/builtins/sqlite-storage/records/count-settings-brokers-legacy.d.ts +6 -0
- package/dist/builtins/sqlite-storage/records/records-engine-types.d.ts +5 -0
- package/dist/builtins/sqlite-storage/records/records-engine.d.ts +4 -0
- package/dist/builtins/sqlite-storage/records/records-provider.d.ts +5 -1
- package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +17 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +111 -3
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +111 -3
- package/dist/builtins/sqlite-storage/storage-admin-provider.d.ts +9 -1
- package/dist/builtins/storage-orchestrator/drain-state-store.d.ts +5 -2
- package/dist/builtins/storage-orchestrator/location-store.d.ts +7 -2
- package/dist/builtins/storage-orchestrator/record-kinds.d.ts +38 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +2 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +196 -5
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +195 -6
- package/dist/builtins/system-config/record-kinds.d.ts +32 -0
- package/dist/builtins/system-config/system-config.addon.js +53 -618
- package/dist/builtins/system-config/system-config.addon.mjs +29 -577
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{composition-sources-C3rKncIF.mjs → composition-sources-BmC5jAUv.mjs} +1 -1
- package/dist/{composition-sources-NAPZddic.js → composition-sources-BwIIltnZ.js} +1 -1
- package/dist/{constants-BKX2QnIg.mjs → constants-6XHGmEUF.mjs} +1 -1
- package/dist/{constants-BXiNEIeV.js → constants-DA_tjzIk.js} +1 -1
- package/dist/{device-ca-jxjSL8Ov.mjs → device-ca-Bh_ClxMO.mjs} +1 -1
- package/dist/{device-ca-DT9X2S6d.js → device-ca-CnbrgfmW.js} +1 -1
- package/dist/{dist-D1vECb_6.js → dist-BkNfEJKa.js} +521 -64
- package/dist/{dist-DERK-gP5.mjs → dist-CkZIrsAP.mjs} +462 -65
- package/dist/file-host-worker.js +1 -1
- package/dist/file-host-worker.mjs +1 -1
- package/dist/{hub-mdns-ciao-CRaC97V0.mjs → hub-mdns-ciao-CoyIUWHC.mjs} +2 -2
- package/dist/{hub-mdns-ciao-Cah9GCIg.js → hub-mdns-ciao-m5LIr4oA.js} +2 -2
- package/dist/index.d.ts +7 -0
- package/dist/index.js +3095 -2821
- package/dist/index.mjs +3067 -2810
- package/dist/kernel/index.d.ts +2 -0
- package/dist/kernel/moleculer/event-bus.d.ts +3 -1
- package/dist/kernel/moleculer/mesh-mtls/mesh-certificate-registry.d.ts +5 -1
- package/dist/kernel/moleculer/remote-logger.d.ts +2 -2
- package/dist/kernel/transport/cap-route-resolver.d.ts +9 -38
- package/dist/phase6-declare-gate-BDWZuB2n.mjs +93 -0
- package/dist/phase6-declare-gate-Bl7KocEs.js +98 -0
- package/dist/read-all-rows-CVoO1ONM.js +29 -0
- package/dist/read-all-rows-TaPqdWNF.mjs +25 -0
- package/dist/records/read-all-rows.d.ts +6 -0
- package/dist/{restore-archive-Dy-qKTdF.js → restore-archive-B57xI5Ue.js} +353 -5
- package/dist/{restore-archive-daKyE24F.mjs → restore-archive-CMr4V7Fi.mjs} +339 -9
- package/dist/tls/agent-https-names.d.ts +9 -13
- package/dist/{wal-maintenance-zRc24mOC.mjs → wal-maintenance-Bqm4zrNA.mjs} +0 -0
- package/dist/{wal-maintenance-dAv4IdzC.js → wal-maintenance-CuG1DUca.js} +0 -0
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { $
|
|
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-CkZIrsAP.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
|
-
|
|
1118
|
-
|
|
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
|
|
10863
|
-
|
|
10864
|
-
|
|
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
|
-
|
|
36
|
-
export declare const DEVICE_TOMBSTONE_INDEXES: readonly CollectionIndex[];
|
|
8
|
+
type TombstoneBody = z.infer<typeof DeviceTombstoneBodySchema>;
|
|
37
9
|
export interface DeviceTombstoneStoreOptions {
|
|
38
|
-
readonly
|
|
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
|
|
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-
|
|
6
|
+
const require_dist = require("../../dist-BkNfEJKa.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 {
|
|
1
|
+
import { Rr as BaseAddon, xn as logDestinationCapability } from "../../dist-CkZIrsAP.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;
|