@camstack/types 1.2.373 → 1.2.374

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 (38) hide show
  1. package/dist/addon.d.ts +2 -0
  2. package/dist/addon.js +6 -3
  3. package/dist/addon.mjs +5 -4
  4. package/dist/capabilities/addon-settings.cap.d.ts +10 -0
  5. package/dist/capabilities/core-blocks.cap.d.ts +2 -0
  6. package/dist/capabilities/device-manager.cap.d.ts +78 -0
  7. package/dist/capabilities/device-removal-hook.cap.d.ts +93 -0
  8. package/dist/capabilities/index.d.ts +6 -3
  9. package/dist/capabilities/keychain.cap.d.ts +11 -0
  10. package/dist/client.js +2 -0
  11. package/dist/client.mjs +2 -0
  12. package/dist/{composition-DCYnv4I6.js → composition-DIp0uE_b.js} +1 -1
  13. package/dist/{composition-C-WpVYTX.mjs → composition-EQ9Ok0Ee.mjs} +1 -1
  14. package/dist/device/device-removal-reconcile.d.ts +49 -0
  15. package/dist/device/device-type.d.ts +16 -0
  16. package/dist/{err-msg-DX6i_MY4.mjs → err-msg-DLerKiVO.mjs} +16 -0
  17. package/dist/{err-msg-Dx2Kor0g.js → err-msg-Ls8Q6dHO.js} +16 -0
  18. package/dist/generated/addon-api.d.ts +44 -0
  19. package/dist/generated/capability-router-map.d.ts +5 -2
  20. package/dist/generated/collection-array-methods.d.ts +1 -1
  21. package/dist/generated/method-access-map.d.ts +1 -1
  22. package/dist/generated/method-device-selectors.d.ts +2 -2
  23. package/dist/generated/system-proxy.d.ts +1 -1
  24. package/dist/i18n/camstack-error.d.ts +31 -0
  25. package/dist/i18n/translation.d.ts +39 -0
  26. package/dist/index.d.ts +6 -0
  27. package/dist/index.js +456 -16
  28. package/dist/index.mjs +428 -17
  29. package/dist/interfaces/addon.d.ts +11 -0
  30. package/dist/interfaces/config-ui.d.ts +20 -0
  31. package/dist/keychain/secrets-access.d.ts +12 -0
  32. package/dist/node.js +2 -2
  33. package/dist/node.mjs +2 -2
  34. package/dist/pipeline/face-rescore-schedule.d.ts +35 -0
  35. package/dist/{sleep-DAX0-2v9.mjs → sleep-DRqxtc0C.mjs} +62 -1
  36. package/dist/{sleep-DnQ5WsMI.js → sleep-rqlHXgwb.js} +91 -0
  37. package/dist/system/server-name.d.ts +7 -1
  38. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-DnQ5WsMI.js");
2
+ const require_sleep = require("./sleep-rqlHXgwb.js");
3
3
  const require_event_category = require("./event-category-T43rdQWR.js");
4
- const require_composition = require("./composition-DCYnv4I6.js");
4
+ const require_composition = require("./composition-DIp0uE_b.js");
5
5
  const require_node_color = require("./node-color.js");
6
- const require_err_msg = require("./err-msg-Dx2Kor0g.js");
6
+ const require_err_msg = require("./err-msg-Ls8Q6dHO.js");
7
7
  const require_enums = require("./enums.js");
8
8
  let zod = require("zod");
9
9
  //#region src/media/media-owner-key.ts
@@ -2601,12 +2601,12 @@ function toStreamSourceEntry(stream) {
2601
2601
  function isString(v) {
2602
2602
  return typeof v === "string";
2603
2603
  }
2604
- function isRecord$2(v) {
2604
+ function isRecord$3(v) {
2605
2605
  return typeof v === "object" && v !== null && !Array.isArray(v);
2606
2606
  }
2607
2607
  function parseStreamEntry(v) {
2608
2608
  if (isString(v) && v.trim()) return { url: v };
2609
- if (isRecord$2(v) && isString(v["url"]) && v["url"].trim()) return {
2609
+ if (isRecord$3(v) && isString(v["url"]) && v["url"].trim()) return {
2610
2610
  url: v["url"],
2611
2611
  label: isString(v["label"]) ? v["label"] : void 0
2612
2612
  };
@@ -3247,20 +3247,20 @@ var SURVIVING_TRIGGER_KEYS = [
3247
3247
  "objectClasses",
3248
3248
  "sensorDeviceIds"
3249
3249
  ];
3250
- function isRecord$1(value) {
3250
+ function isRecord$2(value) {
3251
3251
  return typeof value === "object" && value !== null && !Array.isArray(value);
3252
3252
  }
3253
3253
  function listensToLegacySignal(band) {
3254
- return isRecord$1(band) && isRecord$1(band.triggers) && band.triggers.deviceSignal === true;
3254
+ return isRecord$2(band) && isRecord$2(band.triggers) && band.triggers.deviceSignal === true;
3255
3255
  }
3256
3256
  function hasSurvivingTrigger(band) {
3257
3257
  const triggers = band.triggers;
3258
- if (!isRecord$1(triggers)) return false;
3258
+ if (!isRecord$2(triggers)) return false;
3259
3259
  return SURVIVING_TRIGGER_KEYS.some((key) => triggers[key] !== void 0);
3260
3260
  }
3261
3261
  function withoutLegacySignal(band) {
3262
3262
  const triggers = band.triggers;
3263
- if (!isRecord$1(triggers)) return band;
3263
+ if (!isRecord$2(triggers)) return band;
3264
3264
  const { deviceSignal: _retired, ...rest } = triggers;
3265
3265
  return {
3266
3266
  ...band,
@@ -3290,11 +3290,11 @@ function migrateLegacyDeviceSignalConfig(raw) {
3290
3290
  migrated: false,
3291
3291
  strippedOnly: false
3292
3292
  };
3293
- if (!isRecord$1(raw) || !Array.isArray(raw.bands)) return unchanged;
3293
+ if (!isRecord$2(raw) || !Array.isArray(raw.bands)) return unchanged;
3294
3294
  if (!raw.bands.some(listensToLegacySignal)) return unchanged;
3295
3295
  const kept = [];
3296
3296
  for (const band of raw.bands) {
3297
- if (!listensToLegacySignal(band) || !isRecord$1(band)) {
3297
+ if (!listensToLegacySignal(band) || !isRecord$2(band)) {
3298
3298
  kept.push(band);
3299
3299
  continue;
3300
3300
  }
@@ -8000,7 +8000,9 @@ var ConfigTabDeclarationSchema = zod.z.object({
8000
8000
  var ConfigSectionWithValuesSchema = zod.z.object({
8001
8001
  id: zod.z.string(),
8002
8002
  title: zod.z.string(),
8003
+ titleKey: zod.z.string().optional(),
8003
8004
  description: zod.z.string().optional(),
8005
+ descriptionKey: zod.z.string().optional(),
8004
8006
  style: zod.z.enum(["card", "accordion"]).optional(),
8005
8007
  defaultCollapsed: zod.z.boolean().optional(),
8006
8008
  columns: zod.z.union([
@@ -13996,6 +13998,16 @@ var keychainCapability = {
13996
13998
  kind: "mutation",
13997
13999
  auth: "admin"
13998
14000
  }),
14001
+ /**
14002
+ * Delete every value scoped `device/<deviceId>`, whatever its owner (D864).
14003
+ * Reserved to `device-manager`, on the device-removed path: a driver's
14004
+ * device-scoped secret is not anybody's once the device is gone. Answers the
14005
+ * refs removed (never values).
14006
+ */
14007
+ deleteDeviceScope: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int() }), zod.z.object({ refs: zod.z.array(zod.z.string()).readonly() }), {
14008
+ kind: "mutation",
14009
+ auth: "admin"
14010
+ }),
13999
14011
  /** The caller's own refs, metadata only. */
14000
14012
  listMeta: require_sleep.method(zod.z.object({}), zod.z.array(KeychainSecretMetaSchema).readonly(), { auth: "admin" }),
14001
14013
  /** Whether values can be served — the save path refuses a write while locked. */
@@ -36374,6 +36386,42 @@ var DeviceRegisterPayloadSchema = zod.z.object({
36374
36386
  * omits it and the keyword backstop applies. */
36375
36387
  secretConfigPaths: zod.z.array(zod.z.string()).optional()
36376
36388
  });
36389
+ /** One deleted device, kept by device-manager so an addon that missed the
36390
+ * deletion can still learn of it (D865). Written by the delete path ONLY. */
36391
+ var DeviceTombstoneSchema = zod.z.object({
36392
+ deviceId: zod.z.number().int().positive(),
36393
+ /** Epoch ms the device was deleted. */
36394
+ deletedAt: zod.z.number(),
36395
+ /** The addon that owned the device when it was deleted. */
36396
+ providerAddonId: zod.z.string()
36397
+ });
36398
+ /** How long a tombstone stays readable. Past it, a device that was deleted
36399
+ * and never cleaned is only reachable by the admin "clean data of deleted
36400
+ * devices" action. */
36401
+ var DEVICE_TOMBSTONE_RETENTION_MS = 2160 * 60 * 60 * 1e3;
36402
+ /** Data held for one device that device-manager no longer knows. */
36403
+ var OrphanDeviceDataSchema = zod.z.object({
36404
+ deviceId: zod.z.number().int().positive(),
36405
+ /** Rows/files per store (`<addonId>:<store>`). */
36406
+ stores: zod.z.record(zod.z.string(), zod.z.number().int().nonnegative())
36407
+ });
36408
+ var CleanupDeletedDevicesResultSchema = zod.z.object({
36409
+ /**
36410
+ * `skipped` — the absence check could not be trusted (a device-list read
36411
+ * failed or the two reads disagreed); nothing was listed or deleted.
36412
+ * `dry-run` — `devices` is what a confirmed run would delete.
36413
+ * `cleaned` — `devices` is what was deleted.
36414
+ */
36415
+ status: zod.z.enum([
36416
+ "skipped",
36417
+ "dry-run",
36418
+ "cleaned"
36419
+ ]),
36420
+ reason: zod.z.string().nullable(),
36421
+ devices: zod.z.array(OrphanDeviceDataSchema),
36422
+ /** Implementers that could not be asked (their stores are not in `devices`). */
36423
+ unreachable: zod.z.array(zod.z.string())
36424
+ });
36377
36425
  var DeviceRemovePayloadSchema = zod.z.object({ deviceId: zod.z.number() });
36378
36426
  var DevicePersistConfigPayloadSchema = zod.z.object({
36379
36427
  deviceId: zod.z.number(),
@@ -36970,6 +37018,27 @@ var deviceManagerCapability = {
36970
37018
  kind: "mutation",
36971
37019
  auth: "admin"
36972
37020
  }),
37021
+ /**
37022
+ * The tombstones of devices deleted at or after `sinceMs` (D865). The
37023
+ * reconcile feed of every `device-removal-hook` implementer: an addon that
37024
+ * was down when a device was deleted asks here at start and periodically.
37025
+ * A tombstone exists only for a DELETE — never for a device that is merely
37026
+ * unregistered, offline or whose provider is restarting. Tombstones older
37027
+ * than `DEVICE_TOMBSTONE_RETENTION_MS` are gone.
37028
+ */
37029
+ listDeletedSince: require_sleep.method(zod.z.object({ sinceMs: zod.z.number() }), zod.z.array(DeviceTombstoneSchema).readonly(), { auth: "admin" }),
37030
+ /**
37031
+ * Admin-triggered clean-up of data that belongs to devices deleted BEFORE
37032
+ * tombstones existed (D865). Asks every `device-removal-hook` implementer
37033
+ * which device ids it holds data for, keeps those absent from the device
37034
+ * list — confirmed by TWO reads of the list, skipped if either fails — and
37035
+ * with `confirm: false` only reports the counts per store. `confirm: true`
37036
+ * deletes. Never runs on its own.
37037
+ */
37038
+ cleanupDeletedDevicesData: require_sleep.method(zod.z.object({ confirm: zod.z.boolean() }), CleanupDeletedDevicesResultSchema, {
37039
+ kind: "mutation",
37040
+ auth: "admin"
37041
+ }),
36973
37042
  /** Cascade-delete every top-level device whose `integrationId` matches.
36974
37043
  * Children cascade automatically via the per-parent remove path.
36975
37044
  * Idempotent: a device whose `integrationId` was never set never matches.
@@ -37997,6 +38066,87 @@ var embeddingEncoderCapability = {
37997
38066
  }
37998
38067
  };
37999
38068
  //#endregion
38069
+ //#region src/capabilities/device-removal-hook.cap.ts
38070
+ /**
38071
+ * `device-removal-hook` — the reliable way an addon learns a device was DELETED,
38072
+ * so it can delete what it keeps for that device (D865).
38073
+ *
38074
+ * ## Why an event was not enough
38075
+ *
38076
+ * `DeviceUnregistered` is telemetry and may be dropped (D8, D11). An addon that
38077
+ * hung its per-device clean-up on it left durable garbage whenever the event was
38078
+ * lost, the addon was down, or it was restarting at that moment — footage,
38079
+ * analytics rows and settings of device 4483 outlived the device. Loss of this
38080
+ * signal corrupts durable state, so it travels by RPC with a recorded fact
38081
+ * behind it (D8: "if loss would corrupt durable state, use RPC plus a reconcile").
38082
+ *
38083
+ * ## The three pieces
38084
+ *
38085
+ * 1. device-manager records a TOMBSTONE per deleted device
38086
+ * (`deviceManager.listDeletedSince`). The tombstone is written by the delete
38087
+ * path only — a device that is unregistered, offline or whose provider is
38088
+ * restarting is NOT deleted and gets none.
38089
+ * 2. After a delete, device-manager calls `onDeviceRemoved` on EVERY provider of
38090
+ * this collection, one by one, with bounded retries, logged.
38091
+ * 3. An implementer that was down asks `deviceManager.listDeletedSince` at start
38092
+ * (and periodically) and runs its own `onDeviceRemoved` for each tombstone it
38093
+ * may have missed. Reconcile is driven by tombstones, never by "the device is
38094
+ * not in the current list": a failed or partial list read must not destroy data.
38095
+ *
38096
+ * ## Contract for an implementer
38097
+ *
38098
+ * - **Idempotent.** It is called again by a retry, by a reconcile and by the
38099
+ * admin cleanup of data that predates tombstones. A device with nothing left
38100
+ * answers zero counts.
38101
+ * - **One key per store** in `counts`, deleted rows/files per store, so the log
38102
+ * line and the admin dry run can say where the data was.
38103
+ * - **Training datasets are NOT device data** and are never deleted by a hook.
38104
+ * - **Per-device SETTINGS are not hooked.** Configuration lives in the standard
38105
+ * per-device store (`ctx.settings.*DeviceStore`), which device-manager clears
38106
+ * for every addon centrally at delete time. This hook is for device DATA
38107
+ * that is not settings: footage, event media, analytics rows, history.
38108
+ * - A provider that cannot tell is allowed to throw; the caller retries it.
38109
+ *
38110
+ * `listDeviceData` is the read side of the admin "Clean data of deleted devices"
38111
+ * action: which device ids this addon holds data for, and how much per store. It
38112
+ * never deletes. device-manager decides which of those ids are absent from the
38113
+ * fleet, from TWO consistent reads of the device list (D49).
38114
+ */
38115
+ /** What a hook is told about the deletion. */
38116
+ var DeviceRemovedInputSchema = zod.z.object({
38117
+ deviceId: zod.z.number().int().positive(),
38118
+ /** Epoch ms the device was deleted (the tombstone's `deletedAt`). */
38119
+ deletedAt: zod.z.number(),
38120
+ /** The addon that owned the device, as device-manager last knew it. */
38121
+ providerAddonId: zod.z.string()
38122
+ });
38123
+ /** Rows/files/refs deleted, per store this implementer owns. */
38124
+ var DeviceRemovedResultSchema = zod.z.object({ counts: zod.z.record(zod.z.string(), zod.z.number().int().nonnegative()) });
38125
+ /** One (store, device) pair an implementer holds data for. */
38126
+ var DeviceDataEntrySchema = zod.z.object({
38127
+ store: zod.z.string(),
38128
+ deviceId: zod.z.number().int().positive(),
38129
+ /** Rows (or files) held for the device in the store. */
38130
+ count: zod.z.number().int().nonnegative()
38131
+ });
38132
+ var deviceRemovalHookCapability = {
38133
+ name: "device-removal-hook",
38134
+ scope: "system",
38135
+ mode: "collection",
38136
+ internal: true,
38137
+ methods: {
38138
+ /** Delete everything this addon keeps for the deleted device. Idempotent. */
38139
+ onDeviceRemoved: require_sleep.method(DeviceRemovedInputSchema, DeviceRemovedResultSchema, {
38140
+ kind: "mutation",
38141
+ auth: "admin"
38142
+ }),
38143
+ /** Which devices this addon holds data for, per store. Reads only. */
38144
+ listDeviceData: require_sleep.method(zod.z.void(), zod.z.array(DeviceDataEntrySchema).readonly(), { auth: "admin" })
38145
+ },
38146
+ /** In-process only — enumerated through `addons.listCapabilityProviders`. */
38147
+ mount: { kind: "skip" }
38148
+ };
38149
+ //#endregion
38000
38150
  //#region src/capabilities/failure-contribution.cap.ts
38001
38151
  /**
38002
38152
  * `failure-contribution` — the capability an addon reports its OWN losses
@@ -70244,10 +70394,20 @@ var ServerNameInfoSchema = zod.z.object({
70244
70394
  /** `true` when nobody named the hub: `name` is the machine hostname. */
70245
70395
  isDefault: zod.z.boolean()
70246
70396
  });
70247
- /** The hostname without its domain (`nas.lan.example` becomes `nas`). */
70397
+ /** What an unset name shows when the hostname says nothing about the hub. */
70398
+ var SERVER_NAME_FALLBACK = "CamStack";
70399
+ /** A container id: Docker's default hostname (12 hex chars, or the full 64). */
70400
+ var CONTAINER_ID_PATTERN = /^(?:[0-9a-f]{12}|[0-9a-f]{64})$/;
70401
+ /**
70402
+ * The hostname without its domain (`nas.lan.example` becomes `nas`). A hostname
70403
+ * that names nothing (empty, `localhost`, a container id) yields
70404
+ * {@link SERVER_NAME_FALLBACK}.
70405
+ */
70248
70406
  function shortHostname(hostname) {
70249
70407
  const first = hostname.trim().split(".")[0] ?? "";
70250
- return first.length > 0 ? first : "hub";
70408
+ if (first.length === 0 || first.toLowerCase() === "localhost") return SERVER_NAME_FALLBACK;
70409
+ if (CONTAINER_ID_PATTERN.test(first)) return SERVER_NAME_FALLBACK;
70410
+ return first;
70251
70411
  }
70252
70412
  /**
70253
70413
  * Resolve a stored value (whatever the row held, `undefined` when unset) and the
@@ -78125,6 +78285,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
78125
78285
  addonId: null,
78126
78286
  access: "create"
78127
78287
  },
78288
+ "deviceManager.cleanupDeletedDevicesData": {
78289
+ capName: "device-manager",
78290
+ capScope: "system",
78291
+ addonId: null,
78292
+ access: "create"
78293
+ },
78128
78294
  "deviceManager.createDevice": {
78129
78295
  capName: "device-manager",
78130
78296
  capScope: "system",
@@ -78305,6 +78471,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
78305
78471
  addonId: null,
78306
78472
  access: "view"
78307
78473
  },
78474
+ "deviceManager.listDeletedSince": {
78475
+ capName: "device-manager",
78476
+ capScope: "system",
78477
+ addonId: null,
78478
+ access: "view"
78479
+ },
78308
78480
  "deviceManager.listDeviceIdsByCaps": {
78309
78481
  capName: "device-manager",
78310
78482
  capScope: "system",
@@ -78713,6 +78885,18 @@ var METHOD_ACCESS_MAP = Object.freeze({
78713
78885
  addonId: null,
78714
78886
  access: "create"
78715
78887
  },
78888
+ "deviceRemovalHook.listDeviceData": {
78889
+ capName: "device-removal-hook",
78890
+ capScope: "system",
78891
+ addonId: null,
78892
+ access: "view"
78893
+ },
78894
+ "deviceRemovalHook.onDeviceRemoved": {
78895
+ capName: "device-removal-hook",
78896
+ capScope: "system",
78897
+ addonId: null,
78898
+ access: "create"
78899
+ },
78716
78900
  "deviceState.claimFields": {
78717
78901
  capName: "device-state",
78718
78902
  capScope: "system",
@@ -79145,6 +79329,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
79145
79329
  addonId: null,
79146
79330
  access: "delete"
79147
79331
  },
79332
+ "keychain.deleteDeviceScope": {
79333
+ capName: "keychain",
79334
+ capScope: "system",
79335
+ addonId: null,
79336
+ access: "delete"
79337
+ },
79148
79338
  "keychain.getState": {
79149
79339
  capName: "keychain",
79150
79340
  capScope: "system",
@@ -84438,6 +84628,7 @@ var KNOWN_CAP_NAMES = [
84438
84628
  "device-manager",
84439
84629
  "device-ops",
84440
84630
  "device-provider",
84631
+ "device-removal-hook",
84441
84632
  "device-state",
84442
84633
  "device-status",
84443
84634
  "doorbell",
@@ -84676,6 +84867,7 @@ var SYSTEM_CAP_NAMES = [
84676
84867
  "device-history",
84677
84868
  "device-manager",
84678
84869
  "device-provider",
84870
+ "device-removal-hook",
84679
84871
  "device-state",
84680
84872
  "embedding-encoder",
84681
84873
  "face-gallery",
@@ -85484,7 +85676,7 @@ function resolveDeviceProfile(features) {
85484
85676
  //#endregion
85485
85677
  //#region src/device/path-util.ts
85486
85678
  /** Returns true when `x` is a non-null, non-array plain object. */
85487
- function isRecord(x) {
85679
+ function isRecord$1(x) {
85488
85680
  return x !== null && typeof x === "object" && !Array.isArray(x);
85489
85681
  }
85490
85682
  /** Read a dot-path (`a.b.c`) out of an object. Returns `undefined` for any
@@ -85493,7 +85685,7 @@ function getByPath(obj, path) {
85493
85685
  const parts = path.split(".");
85494
85686
  let cur = obj;
85495
85687
  for (const part of parts) {
85496
- if (!isRecord(cur)) return void 0;
85688
+ if (!isRecord$1(cur)) return void 0;
85497
85689
  cur = cur[part];
85498
85690
  }
85499
85691
  return cur;
@@ -85515,7 +85707,7 @@ function setByPath(obj, path, value) {
85515
85707
  const head = path.slice(0, dotIndex);
85516
85708
  const tail = path.slice(dotIndex + 1);
85517
85709
  const child = obj[head];
85518
- const childObj = isRecord(child) ? child : {};
85710
+ const childObj = isRecord$1(child) ? child : {};
85519
85711
  return {
85520
85712
  ...obj,
85521
85713
  [head]: setByPath(childObj, tail, value)
@@ -86708,6 +86900,7 @@ var CAPABILITY_NAMES = {
86708
86900
  deviceManager: "device-manager",
86709
86901
  deviceOps: "device-ops",
86710
86902
  deviceProvider: "device-provider",
86903
+ deviceRemovalHook: "device-removal-hook",
86711
86904
  deviceState: "device-state",
86712
86905
  deviceStatus: "device-status",
86713
86906
  doorbell: "doorbell",
@@ -87058,6 +87251,10 @@ var CAPABILITY_ROUTER_KEYS = [
87058
87251
  key: "deviceProvider",
87059
87252
  name: "device-provider"
87060
87253
  },
87254
+ {
87255
+ key: "deviceRemovalHook",
87256
+ name: "device-removal-hook"
87257
+ },
87061
87258
  {
87062
87259
  key: "deviceState",
87063
87260
  name: "device-state"
@@ -87587,6 +87784,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
87587
87784
  deviceManagerCapability,
87588
87785
  require_sleep.deviceOpsCapability,
87589
87786
  deviceProviderCapability,
87787
+ deviceRemovalHookCapability,
87590
87788
  deviceStateCapability,
87591
87789
  deviceStatusCapability,
87592
87790
  doorbellCapability,
@@ -88482,6 +88680,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
88482
88680
  form: "single",
88483
88681
  optional: false
88484
88682
  }],
88683
+ "deviceRemovalHook.onDeviceRemoved": [{
88684
+ name: "deviceId",
88685
+ form: "single",
88686
+ optional: false
88687
+ }],
88485
88688
  "deviceState.claimFields": [{
88486
88689
  name: "deviceId",
88487
88690
  form: "single",
@@ -88671,6 +88874,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
88671
88874
  form: "single",
88672
88875
  optional: false
88673
88876
  }],
88877
+ "keychain.deleteDeviceScope": [{
88878
+ name: "deviceId",
88879
+ form: "single",
88880
+ optional: false
88881
+ }],
88674
88882
  "lawnMowerControl.dock": [{
88675
88883
  name: "deviceId",
88676
88884
  form: "single",
@@ -90425,6 +90633,7 @@ var SYSTEM_SCOPE_DEVICE_METHODS = [
90425
90633
  "deviceManager.updateConfig",
90426
90634
  "deviceManager.updateDeviceField",
90427
90635
  "deviceManager.updateDeviceFieldsBatch",
90636
+ "deviceRemovalHook.onDeviceRemoved",
90428
90637
  "deviceState.claimFields",
90429
90638
  "deviceState.getCapSlice",
90430
90639
  "deviceState.getNativeCapSlice",
@@ -90434,6 +90643,7 @@ var SYSTEM_SCOPE_DEVICE_METHODS = [
90434
90643
  "deviceState.setCapSlice",
90435
90644
  "faceGallery.getFaceByTrack",
90436
90645
  "faceGallery.listRecentFaces",
90646
+ "keychain.deleteDeviceScope",
90437
90647
  "networkQuality.getDeviceStats",
90438
90648
  "networkQuality.reportClientStats",
90439
90649
  "notificationRules.getAlarmSensors",
@@ -91633,6 +91843,8 @@ function createSystemProxy(api) {
91633
91843
  getChildren: (input) => dispatch("deviceManager", "getChildren", "query", input),
91634
91844
  getChildrenBatch: (input) => dispatch("deviceManager", "getChildrenBatch", "query", input),
91635
91845
  getLinkedDevicesBatch: (input) => dispatch("deviceManager", "getLinkedDevicesBatch", "query", input),
91846
+ listDeletedSince: (input) => dispatch("deviceManager", "listDeletedSince", "query", input),
91847
+ cleanupDeletedDevicesData: (input) => dispatch("deviceManager", "cleanupDeletedDevicesData", "mutation", input),
91636
91848
  removeByIntegration: (input) => dispatch("deviceManager", "removeByIntegration", "mutation", input),
91637
91849
  getBindingsBatch: (input) => dispatch("deviceManager", "getBindingsBatch", "query", input),
91638
91850
  getAllBindings: (input) => dispatch("deviceManager", "getAllBindings", "query", input),
@@ -96537,6 +96749,91 @@ function eventKindLabel(kind, locale) {
96537
96749
  return isEventKindLabelKey(key) ? EVENT_KIND_LABELS[key][locale] : kind;
96538
96750
  }
96539
96751
  //#endregion
96752
+ //#region src/i18n/translation.ts
96753
+ /**
96754
+ * Server-side translation primitives (D863) - pure, zod only.
96755
+ *
96756
+ * A catalog is a FLAT `Record<key, string>` per (namespace, language). A
96757
+ * reference is `"<namespace>:<key>"`; the English text always travels next to
96758
+ * it (`label` beside `labelKey`), so a missing key or an unknown language is
96759
+ * the English text, never a blank or a raw key.
96760
+ */
96761
+ /** The languages a catalog may be written in. English is the mandatory base. */
96762
+ var CatalogLangSchema = AppPageLangSchema;
96763
+ var CATALOG_LANGS = CatalogLangSchema.options;
96764
+ var DEFAULT_CATALOG_LANG = "en";
96765
+ /** One catalog file: flat key to text. A file of any other shape is rejected whole. */
96766
+ var CatalogFileSchema = zod.z.record(zod.z.string().min(1), zod.z.string());
96767
+ /** Fills `{name}` placeholders; an unknown placeholder is left as written. */
96768
+ function interpolate(template, params) {
96769
+ if (params === void 0) return template;
96770
+ return template.replace(/\{(\w+)\}/g, (whole, name) => {
96771
+ const value = params[name];
96772
+ return value === void 0 ? whole : String(value);
96773
+ });
96774
+ }
96775
+ /** Splits `"ns:key"`; `null` when the reference has no namespace. */
96776
+ function splitTranslationRef(ref) {
96777
+ const at = ref.indexOf(":");
96778
+ if (at <= 0 || at === ref.length - 1) return null;
96779
+ return {
96780
+ ns: ref.slice(0, at),
96781
+ key: ref.slice(at + 1)
96782
+ };
96783
+ }
96784
+ function isRecord(value) {
96785
+ return typeof value === "object" && value !== null && !Array.isArray(value);
96786
+ }
96787
+ var KEYED_TEXTS = [
96788
+ {
96789
+ keyField: "labelKey",
96790
+ textField: "label"
96791
+ },
96792
+ {
96793
+ keyField: "descriptionKey",
96794
+ textField: "description"
96795
+ },
96796
+ {
96797
+ keyField: "titleKey",
96798
+ textField: "title"
96799
+ }
96800
+ ];
96801
+ /**
96802
+ * Returns `value` with every `labelKey` / `descriptionKey` / `titleKey` that
96803
+ * the catalog can resolve replaced into `label` / `description` / `title`.
96804
+ * Pure: the input is never mutated; a subtree with nothing to change is
96805
+ * returned as the SAME object. A key the catalog does not hold keeps the
96806
+ * English text that sits next to it.
96807
+ */
96808
+ function localizeConfigTree(value, lookup) {
96809
+ if (Array.isArray(value)) {
96810
+ let changed = false;
96811
+ const next = value.map((item) => {
96812
+ const out = localizeConfigTree(item, lookup);
96813
+ if (out !== item) changed = true;
96814
+ return out;
96815
+ });
96816
+ return changed ? next : value;
96817
+ }
96818
+ if (!isRecord(value)) return value;
96819
+ const patch = {};
96820
+ for (const [k, v] of Object.entries(value)) {
96821
+ const out = localizeConfigTree(v, lookup);
96822
+ if (out !== v) patch[k] = out;
96823
+ }
96824
+ for (const { keyField, textField } of KEYED_TEXTS) {
96825
+ const ref = value[keyField];
96826
+ if (typeof ref !== "string") continue;
96827
+ const parts = splitTranslationRef(ref);
96828
+ const text = parts === null ? void 0 : lookup(parts.ns, parts.key);
96829
+ if (text !== void 0) patch[textField] = text;
96830
+ }
96831
+ return Object.keys(patch).length === 0 ? value : {
96832
+ ...value,
96833
+ ...patch
96834
+ };
96835
+ }
96836
+ //#endregion
96540
96837
  //#region src/notification/timelapse-rule.ts
96541
96838
  /**
96542
96839
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
@@ -98809,6 +99106,48 @@ function slideInsideFrame(rect, frameWidth, frameHeight) {
98809
99106
  };
98810
99107
  }
98811
99108
  //#endregion
99109
+ //#region src/pipeline/face-rescore-schedule.ts
99110
+ /**
99111
+ * The cadence of the automatic whole-archive face rescore (D866).
99112
+ *
99113
+ * One cluster-wide knob in `pipeline-orchestrator`'s GLOBAL settings, read by
99114
+ * `pipeline-analytics` over the hub-routed `addon-settings` cap on every tick.
99115
+ * It lives here for the same reason the detail-crop convention does: the
99116
+ * writer (orchestrator) and the reader (analytics) are different addons, they
99117
+ * never import each other, and a key copied by hand is how a setting silently
99118
+ * stops arriving.
99119
+ */
99120
+ var FACE_RESCORE_SECTION_ID = "face-rescore";
99121
+ var FACE_RESCORE_INTERVAL_KEY = "faceRescoreIntervalMinutes";
99122
+ /** Slider bounds. `0` is "disabled"; anything in 1..9 is raised to `min`. */
99123
+ var FACE_RESCORE_INTERVAL_FIELD = {
99124
+ min: 0,
99125
+ max: 1440,
99126
+ step: 5,
99127
+ default: 60
99128
+ };
99129
+ /** The smallest period that actually runs; below it (but above 0) is clamped up. */
99130
+ var FACE_RESCORE_INTERVAL_MIN_RUNNING = 10;
99131
+ /**
99132
+ * Narrow a stored value to minutes. `0` ⇒ disabled; a positive value under
99133
+ * {@link FACE_RESCORE_INTERVAL_MIN_RUNNING} is raised to it; junk or absent ⇒
99134
+ * the default (an unreadable setting must not switch the job off nor storm it).
99135
+ */
99136
+ function readFaceRescoreIntervalMinutes(value) {
99137
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return FACE_RESCORE_INTERVAL_FIELD.default;
99138
+ if (value === 0) return 0;
99139
+ return Math.min(FACE_RESCORE_INTERVAL_FIELD.max, Math.max(10, Math.floor(value)));
99140
+ }
99141
+ /** The interval out of a hydrated payload; a `null` view (mid-boot) is the default. */
99142
+ function pickFaceRescoreIntervalMinutes(view) {
99143
+ if (view === null) return FACE_RESCORE_INTERVAL_FIELD.default;
99144
+ for (const section of view.sections) for (const entry of section.fields) {
99145
+ if (typeof entry !== "object" || entry === null || !("key" in entry)) continue;
99146
+ if (entry.key === "faceRescoreIntervalMinutes") return readFaceRescoreIntervalMinutes("value" in entry ? entry.value : void 0);
99147
+ }
99148
+ return FACE_RESCORE_INTERVAL_FIELD.default;
99149
+ }
99150
+ //#endregion
98812
99151
  //#region src/pipeline/native-lease.ts
98813
99152
  /**
98814
99153
  * THE native-frame **lease** knobs — hold depth, RAM budget, demand window and
@@ -100644,6 +100983,78 @@ function enumerateInferenceDevices(hw) {
100644
100983
  return out;
100645
100984
  }
100646
100985
  //#endregion
100986
+ //#region src/device/device-removal-reconcile.ts
100987
+ /** How often an implementer re-asks for tombstones after its start-up pass. */
100988
+ var REMOVAL_RECONCILE_INTERVAL_MS = 360 * 60 * 1e3;
100989
+ /** One reconcile pass over every tombstone inside the retention window. */
100990
+ async function reconcileRemovedDevices(opts) {
100991
+ const now = opts.now ?? (() => Date.now());
100992
+ const api = opts.api;
100993
+ if (api === void 0) {
100994
+ opts.logger.warn("device removal reconcile skipped — no device-manager api");
100995
+ return {
100996
+ read: false,
100997
+ applied: 0,
100998
+ failed: 0
100999
+ };
101000
+ }
101001
+ let tombstones;
101002
+ try {
101003
+ tombstones = await api.deviceManager.listDeletedSince.query({ sinceMs: now() - DEVICE_TOMBSTONE_RETENTION_MS });
101004
+ } catch (err) {
101005
+ opts.logger.warn("device removal reconcile skipped — tombstones unreadable, nothing deleted", { meta: { error: require_err_msg.errMsg(err) } });
101006
+ return {
101007
+ read: false,
101008
+ applied: 0,
101009
+ failed: 0
101010
+ };
101011
+ }
101012
+ let applied = 0;
101013
+ let failed = 0;
101014
+ for (const tombstone of tombstones) try {
101015
+ const result = await opts.remove(tombstone);
101016
+ applied += 1;
101017
+ if (Object.values(result.counts).reduce((sum, n) => sum + n, 0) > 0) opts.logger.info("device removal reconcile cleaned a missed deletion", {
101018
+ tags: { deviceId: tombstone.deviceId },
101019
+ meta: {
101020
+ counts: result.counts,
101021
+ deletedAt: tombstone.deletedAt
101022
+ }
101023
+ });
101024
+ } catch (err) {
101025
+ failed += 1;
101026
+ opts.logger.warn("device removal reconcile failed for a device — retried next pass", {
101027
+ tags: { deviceId: tombstone.deviceId },
101028
+ meta: { error: require_err_msg.errMsg(err) }
101029
+ });
101030
+ }
101031
+ return {
101032
+ read: true,
101033
+ applied,
101034
+ failed
101035
+ };
101036
+ }
101037
+ /**
101038
+ * Run the reconcile now and then periodically. Returns the disposer. The timer
101039
+ * is unref'd and a pass never overlaps the previous one.
101040
+ */
101041
+ function armRemovalReconcile(opts) {
101042
+ let running = false;
101043
+ const pass = () => {
101044
+ if (running) return;
101045
+ running = true;
101046
+ reconcileRemovedDevices(opts).catch((err) => {
101047
+ opts.logger.warn("device removal reconcile pass crashed", { meta: { error: require_err_msg.errMsg(err) } });
101048
+ }).finally(() => {
101049
+ running = false;
101050
+ });
101051
+ };
101052
+ pass();
101053
+ const timer = setInterval(pass, REMOVAL_RECONCILE_INTERVAL_MS);
101054
+ timer.unref?.();
101055
+ return () => clearInterval(timer);
101056
+ }
101057
+ //#endregion
100647
101058
  exports.ACCESSORY_LABEL = ACCESSORY_LABEL;
100648
101059
  exports.ACCESS_ROLES = ACCESS_ROLES;
100649
101060
  exports.AGENT_MDNS_QUERY_NAME = AGENT_MDNS_QUERY_NAME;
@@ -100823,6 +101234,7 @@ exports.CAPABILITY_ROUTER_KEYS = CAPABILITY_ROUTER_KEYS;
100823
101234
  exports.CAP_NAMES_WITH_STATUS = CAP_NAMES_WITH_STATUS;
100824
101235
  exports.CAP_NODE_PIN_CONTEXT_KEY = require_sleep.CAP_NODE_PIN_CONTEXT_KEY;
100825
101236
  exports.CAP_PROVIDER_KIND_MAP = CAP_PROVIDER_KIND_MAP;
101237
+ exports.CATALOG_LANGS = CATALOG_LANGS;
100826
101238
  exports.CLASS_MAP_MACRO_TARGETS = CLASS_MAP_MACRO_TARGETS;
100827
101239
  exports.CLIP_BROKER_PACED_RATES = CLIP_BROKER_PACED_RATES;
100828
101240
  exports.CLIP_PLAYBACK_OPTIONS = CLIP_PLAYBACK_OPTIONS;
@@ -100911,15 +101323,19 @@ exports.CameraSwitchIdSchema = CameraSwitchIdSchema;
100911
101323
  exports.CameraSwitchSchema = CameraSwitchSchema;
100912
101324
  exports.CameraSwitchUnavailableReasonSchema = CameraSwitchUnavailableReasonSchema;
100913
101325
  exports.CameraSwitchWarningSchema = CameraSwitchWarningSchema;
101326
+ exports.CamstackError = require_sleep.CamstackError;
100914
101327
  exports.CandidateQueryFilterSchema = CandidateQueryFilterSchema;
100915
101328
  exports.CapScopeSchema = CapScopeSchema;
100916
101329
  exports.CapabilityBindingsSchema = CapabilityBindingsSchema;
100917
101330
  exports.CapacityFallbackSchema = CapacityFallbackSchema;
100918
101331
  exports.CapacitySourceSchema = CapacitySourceSchema;
100919
101332
  exports.CarbonMonoxideStatusSchema = CarbonMonoxideStatusSchema;
101333
+ exports.CatalogFileSchema = CatalogFileSchema;
101334
+ exports.CatalogLangSchema = CatalogLangSchema;
100920
101335
  exports.ChargingStatus = require_err_msg.ChargingStatus;
100921
101336
  exports.ClaimOutcomeSchema = ClaimOutcomeSchema;
100922
101337
  exports.ClaimsListingSchema = ClaimsListingSchema;
101338
+ exports.CleanupDeletedDevicesResultSchema = CleanupDeletedDevicesResultSchema;
100923
101339
  exports.ClearTrackRelationInputSchema = ClearTrackRelationInputSchema;
100924
101340
  exports.ClearTrackRelationResultSchema = ClearTrackRelationResultSchema;
100925
101341
  exports.ClientNetworkStatsSchema = ClientNetworkStatsSchema;
@@ -101044,6 +101460,7 @@ exports.DEFAULT_ADDON_PLACEMENT = DEFAULT_ADDON_PLACEMENT;
101044
101460
  exports.DEFAULT_AUDIO_ANALYZER_CONFIG = DEFAULT_AUDIO_ANALYZER_CONFIG;
101045
101461
  exports.DEFAULT_CAMERA_FPS = DEFAULT_CAMERA_FPS;
101046
101462
  exports.DEFAULT_CAMERA_SENSOR_MODE = DEFAULT_CAMERA_SENSOR_MODE;
101463
+ exports.DEFAULT_CATALOG_LANG = DEFAULT_CATALOG_LANG;
101047
101464
  exports.DEFAULT_CLUSTER_STEP_MODELS = DEFAULT_CLUSTER_STEP_MODELS;
101048
101465
  exports.DEFAULT_CLUSTER_STEP_SETTINGS = DEFAULT_CLUSTER_STEP_SETTINGS;
101049
101466
  exports.DEFAULT_CORE_BLOCK_ENTRY = DEFAULT_CORE_BLOCK_ENTRY;
@@ -101098,6 +101515,7 @@ exports.DEVICE_SETTINGS_CONTRIBUTION_METHODS = require_sleep.DEVICE_SETTINGS_CON
101098
101515
  exports.DEVICE_SIGNATURE_MESSAGE_VERSION = DEVICE_SIGNATURE_MESSAGE_VERSION;
101099
101516
  exports.DEVICE_STATE_READERS = DEVICE_STATE_READERS;
101100
101517
  exports.DEVICE_STATUS_METHOD = require_sleep.DEVICE_STATUS_METHOD;
101518
+ exports.DEVICE_TOMBSTONE_RETENTION_MS = DEVICE_TOMBSTONE_RETENTION_MS;
101101
101519
  exports.DEVICE_TYPE_CONTROL_KIND = DEVICE_TYPE_CONTROL_KIND;
101102
101520
  exports.DEVICE_TYPE_DO_CAPS = DEVICE_TYPE_DO_CAPS;
101103
101521
  exports.DEVICE_TYPE_INFO = DEVICE_TYPE_INFO;
@@ -101132,6 +101550,7 @@ exports.DeviceCodeSeveritySchema = DeviceCodeSeveritySchema;
101132
101550
  exports.DeviceConfig = DeviceConfig;
101133
101551
  exports.DeviceCredentialSchema = DeviceCredentialSchema;
101134
101552
  exports.DeviceCredentialStatusSchema = DeviceCredentialStatusSchema;
101553
+ exports.DeviceDataEntrySchema = DeviceDataEntrySchema;
101135
101554
  exports.DeviceDiscoveryStatusSchema = DeviceDiscoveryStatusSchema;
101136
101555
  exports.DeviceEnrollProofSchema = DeviceEnrollProofSchema;
101137
101556
  exports.DeviceExportExposeInputSchema = ExposeInputSchema;
@@ -101151,12 +101570,15 @@ exports.DeviceProofInputSchema = DeviceProofInputSchema;
101151
101570
  exports.DeviceRecommendationSchema = DeviceRecommendationSchema;
101152
101571
  exports.DeviceRefusalReasonSchema = DeviceRefusalReasonSchema;
101153
101572
  exports.DeviceRefusalSchema = DeviceRefusalSchema;
101573
+ exports.DeviceRemovedInputSchema = DeviceRemovedInputSchema;
101574
+ exports.DeviceRemovedResultSchema = DeviceRemovedResultSchema;
101154
101575
  exports.DeviceRestoreRetryScheduler = DeviceRestoreRetryScheduler;
101155
101576
  exports.DeviceRole = require_err_msg.DeviceRole;
101156
101577
  exports.DeviceRuntimeState = DeviceRuntimeState;
101157
101578
  exports.DeviceSelectorSchema = DeviceSelectorSchema;
101158
101579
  exports.DeviceSignaturePurposeSchema = DeviceSignaturePurposeSchema;
101159
101580
  exports.DeviceStatusSchema = DeviceStatusSchema;
101581
+ exports.DeviceTombstoneSchema = DeviceTombstoneSchema;
101160
101582
  exports.DeviceType = require_err_msg.DeviceType;
101161
101583
  exports.DiagnosticIdSchema = DiagnosticIdSchema;
101162
101584
  exports.DiagnosticWindowPatchSchema = DiagnosticWindowPatchSchema;
@@ -101211,6 +101633,8 @@ exports.EnrichedWidgetMetadataSchema = EnrichedWidgetMetadataSchema;
101211
101633
  exports.EnrollSelfInputSchema = EnrollSelfInputSchema;
101212
101634
  exports.EnumSensorDateTimeFormatSchema = EnumSensorDateTimeFormatSchema;
101213
101635
  exports.EnumSensorStatusSchema = EnumSensorStatusSchema;
101636
+ exports.ErrorCodeSchema = require_sleep.ErrorCodeSchema;
101637
+ exports.ErrorI18nPayloadSchema = require_sleep.ErrorI18nPayloadSchema;
101214
101638
  exports.EventCategory = require_event_category.EventCategory;
101215
101639
  exports.EventDensityBucketSchema = EventDensityBucketSchema;
101216
101640
  exports.EventDensityForDeviceSchema = EventDensityForDeviceSchema;
@@ -101267,6 +101691,10 @@ exports.ExtensionSourceHealthSchema = ExtensionSourceHealthSchema;
101267
101691
  exports.ExtensionSourceSchema = ExtensionSourceSchema;
101268
101692
  exports.ExternalIdentityKeySchema = ExternalIdentityKeySchema;
101269
101693
  exports.ExternalIdentitySchema = ExternalIdentitySchema;
101694
+ exports.FACE_RESCORE_INTERVAL_FIELD = FACE_RESCORE_INTERVAL_FIELD;
101695
+ exports.FACE_RESCORE_INTERVAL_KEY = FACE_RESCORE_INTERVAL_KEY;
101696
+ exports.FACE_RESCORE_INTERVAL_MIN_RUNNING = FACE_RESCORE_INTERVAL_MIN_RUNNING;
101697
+ exports.FACE_RESCORE_SECTION_ID = FACE_RESCORE_SECTION_ID;
101270
101698
  exports.FEEDER_EXAMPLE_ADDON_ID = FEEDER_EXAMPLE_ADDON_ID;
101271
101699
  exports.FEEDER_EXAMPLE_HA_DEVICE_ID = FEEDER_EXAMPLE_HA_DEVICE_ID;
101272
101700
  exports.FFMPEG_PATH_ENV = require_composition.FFMPEG_PATH_ENV;
@@ -101843,6 +102271,7 @@ exports.OpsLogOpSchema = OpsLogOpSchema;
101843
102271
  exports.OpsLogQueryInputSchema = OpsLogQueryInputSchema;
101844
102272
  exports.OpsLogReasonSchema = OpsLogReasonSchema;
101845
102273
  exports.OrchestratorMetricsSchema = OrchestratorMetricsSchema;
102274
+ exports.OrphanDeviceDataSchema = OrphanDeviceDataSchema;
101846
102275
  exports.OsdNamedTemplateSchema = OsdNamedTemplateSchema;
101847
102276
  exports.OsdOverlayKindEnum = OsdOverlayKindEnum;
101848
102277
  exports.OsdOverlayPatchSchema = OsdOverlayPatchSchema;
@@ -101950,6 +102379,7 @@ exports.RECORDING_SOURCE_CAMSTACK = RECORDING_SOURCE_CAMSTACK;
101950
102379
  exports.RECORDING_SOURCE_CAMSTACK_ADDON = RECORDING_SOURCE_CAMSTACK_ADDON;
101951
102380
  exports.RECORDING_TIMELINE_BATCH_MAX = RECORDING_TIMELINE_BATCH_MAX;
101952
102381
  exports.REDACTED_SECRET = require_sleep.REDACTED_SECRET;
102382
+ exports.REMOVAL_RECONCILE_INTERVAL_MS = REMOVAL_RECONCILE_INTERVAL_MS;
101953
102383
  exports.REMOVED_MODEL_IDS = REMOVED_MODEL_IDS;
101954
102384
  exports.RESERVED_BINDING_NAMES = require_composition.RESERVED_BINDING_NAMES;
101955
102385
  exports.RESERVED_COLLECTION_SOURCES = RESERVED_COLLECTION_SOURCES;
@@ -102458,6 +102888,7 @@ exports.applyModeDeviceListEdit = applyModeDeviceListEdit;
102458
102888
  exports.applyModelBoundSettings = applyModelBoundSettings;
102459
102889
  exports.applyNonBlockingEdit = applyNonBlockingEdit;
102460
102890
  exports.applySecureOnArmEdit = applySecureOnArmEdit;
102891
+ exports.armRemovalReconcile = armRemovalReconcile;
102461
102892
  exports.arrayItemFieldPath = require_sleep.arrayItemFieldPath;
102462
102893
  exports.asBoolean = require_sleep.asBoolean;
102463
102894
  exports.asJsonArray = require_sleep.asJsonArray;
@@ -102663,6 +103094,7 @@ exports.deviceMatchesProfile = deviceMatchesProfile;
102663
103094
  exports.deviceOpsCapability = require_sleep.deviceOpsCapability;
102664
103095
  exports.deviceProviderCapability = deviceProviderCapability;
102665
103096
  exports.deviceRefusalFromMessage = deviceRefusalFromMessage;
103097
+ exports.deviceRemovalHookCapability = deviceRemovalHookCapability;
102666
103098
  exports.deviceSelectorMatches = deviceSelectorMatches;
102667
103099
  exports.deviceStateCapability = deviceStateCapability;
102668
103100
  exports.deviceStatusCapability = deviceStatusCapability;
@@ -102781,6 +103213,7 @@ exports.inferModelProvider = inferModelProvider;
102781
103213
  exports.initialPoolMemoryState = initialPoolMemoryState;
102782
103214
  exports.integrationsCapability = integrationsCapability;
102783
103215
  exports.intercomCapability = intercomCapability;
103216
+ exports.interpolate = interpolate;
102784
103217
  exports.interpretStoredClusterModel = interpretStoredClusterModel;
102785
103218
  exports.invalidClusterStepModelEntries = invalidClusterStepModelEntries;
102786
103219
  exports.invertPresetFeature = invertPresetFeature;
@@ -102873,6 +103306,7 @@ exports.llmCapability = llmCapability;
102873
103306
  exports.llmRuntimeCapability = llmRuntimeCapability;
102874
103307
  exports.loadContributionCapability = loadContributionCapability;
102875
103308
  exports.localNetworkCapability = localNetworkCapability;
103309
+ exports.localizeConfigTree = localizeConfigTree;
102876
103310
  exports.locationIconKey = locationIconKey;
102877
103311
  exports.locationSimilarity = locationSimilarity;
102878
103312
  exports.lockControlCapability = lockControlCapability;
@@ -102980,6 +103414,7 @@ exports.pickAppLinkHub = pickAppLinkHub;
102980
103414
  exports.pickClusterStepModels = pickClusterStepModels;
102981
103415
  exports.pickClusterStepSettings = pickClusterStepSettings;
102982
103416
  exports.pickDetailCropConvention = pickDetailCropConvention;
103417
+ exports.pickFaceRescoreIntervalMinutes = pickFaceRescoreIntervalMinutes;
102983
103418
  exports.pickInvalidClusterStepModels = pickInvalidClusterStepModels;
102984
103419
  exports.pickNativeLeaseOverride = pickNativeLeaseOverride;
102985
103420
  exports.pickPreferredRtspEntry = pickPreferredRtspEntry;
@@ -103016,6 +103451,8 @@ exports.readClusterStepModels = readClusterStepModels;
103016
103451
  exports.readClusterStepSettings = readClusterStepSettings;
103017
103452
  exports.readDetailCropConvention = readDetailCropConvention;
103018
103453
  exports.readDeviceStateFrom = readDeviceStateFrom;
103454
+ exports.readErrorI18n = require_sleep.readErrorI18n;
103455
+ exports.readFaceRescoreIntervalMinutes = readFaceRescoreIntervalMinutes;
103019
103456
  exports.readHubMotionDetected = readHubMotionDetected;
103020
103457
  exports.readHubMotionStatus = readHubMotionStatus;
103021
103458
  exports.readMotionTriggeredBy = readMotionTriggeredBy;
@@ -103027,6 +103464,7 @@ exports.readinessKey = require_sleep.readinessKey;
103027
103464
  exports.rebootCapability = rebootCapability;
103028
103465
  exports.recommendNode = recommendNode;
103029
103466
  exports.reconcileBlockDevices = reconcileBlockDevices;
103467
+ exports.reconcileRemovedDevices = reconcileRemovedDevices;
103030
103468
  exports.recordingArchiveCapability = recordingArchiveCapability;
103031
103469
  exports.recordingCapability = recordingCapability;
103032
103470
  exports.recordingExportCapability = recordingExportCapability;
@@ -103146,6 +103584,7 @@ exports.sliceChangedAt = require_composition.sliceChangedAt;
103146
103584
  exports.smokeCapability = smokeCapability;
103147
103585
  exports.smtpProviderCapability = smtpProviderCapability;
103148
103586
  exports.snapshotCapability = snapshotCapability;
103587
+ exports.splitTranslationRef = splitTranslationRef;
103149
103588
  exports.ssoBridgeCapability = ssoBridgeCapability;
103150
103589
  exports.startReachabilityPoll = startReachabilityPoll;
103151
103590
  exports.stateLabel = stateLabel;
@@ -103221,6 +103660,7 @@ exports.unitsForDimension = unitsForDimension;
103221
103660
  exports.unreachableExtensionSlotRow = unreachableExtensionSlotRow;
103222
103661
  exports.unwrapSchema = unwrapSchema;
103223
103662
  exports.updateCapability = updateCapability;
103663
+ exports.userError = require_sleep.userError;
103224
103664
  exports.userManagementCapability = userManagementCapability;
103225
103665
  exports.userPasskeysCapability = userPasskeysCapability;
103226
103666
  exports.vacuumControlCapability = vacuumControlCapability;