@camstack/addon-provider-homeassistant 1.2.33 → 1.2.35

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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("./dist-CkXDV-PV.js");
2
+ const require_dist = require("./dist-DCvHGfFW.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  let node_zlib = require("node:zlib");
5
5
  //#region src/ha-device-source.ts
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as pressureSensorCapability, A as coverCapability, B as imageCapability, C as buttonCapability, Ct as record, D as connectivityCapability, Dt as url, E as colorCapability, Et as unknown, F as fanControlCapability, G as normalizeUnit, H as lockControlCapability, I as floodCapability, J as numericSensorCapability, K as notificationOutputCapability, L as gasCapability, N as enumSensorCapability, O as contactCapability, Ot as EventCategory, P as eventEmitterCapability, Q as presenceCapability, R as humidifierCapability, S as buildAddonRouteProvider, St as object, T as climateControlCapability, Tt as union, U as mediaPlayerCapability, V as lawnMowerControlCapability, W as motionCapability, X as powerMeterCapability, Z as prepareNotification, _ as batteryCapability, _t as _enum, at as updateCapability, b as brightnessCapability, bt as literal, ct as vibrationCapability, d as accessoriesCapability, dt as errMsg, et as scriptRunnerCapability, f as addonRoutesCapability, g as automationControlCapability, gt as createEvent, h as ambientLightSensorCapability, ht as DeviceType, it as temperatureSensorCapability, j as deviceAdoptionCapability, k as controlCapability, lt as waterHeaterCapability, m as alarmPanelCapability, mt as DeviceRole, n as BaseDevice, nt as switchCapability, o as EnumSensorDateTimeFormatSchema, ot as vacuumControlCapability, p as airQualitySensorCapability, pt as DeviceFeature, q as notifierCapability, r as BaseDeviceProvider, rt as tamperCapability, st as valveCapability, tt as smokeCapability, u as TargetSchema, ut as weatherCapability, v as bestLocationMatch, vt as array, w as carbonMonoxideCapability, wt as string, x as brokerCapability, xt as number, y as binaryCapability, yt as discriminatedUnion, z as humiditySensorCapability } from "./dist-BlSbw9vH.mjs";
1
+ import { $ as pressureSensorCapability, A as coverCapability, B as imageCapability, C as buttonCapability, Ct as record, D as connectivityCapability, Dt as url, E as colorCapability, Et as unknown, F as fanControlCapability, G as normalizeUnit, H as lockControlCapability, I as floodCapability, J as numericSensorCapability, K as notificationOutputCapability, L as gasCapability, N as enumSensorCapability, O as contactCapability, Ot as EventCategory, P as eventEmitterCapability, Q as presenceCapability, R as humidifierCapability, S as buildAddonRouteProvider, St as object, T as climateControlCapability, Tt as union, U as mediaPlayerCapability, V as lawnMowerControlCapability, W as motionCapability, X as powerMeterCapability, Z as prepareNotification, _ as batteryCapability, _t as _enum, at as updateCapability, b as brightnessCapability, bt as literal, ct as vibrationCapability, d as accessoriesCapability, dt as errMsg, et as scriptRunnerCapability, f as addonRoutesCapability, g as automationControlCapability, gt as createEvent, h as ambientLightSensorCapability, ht as DeviceType, it as temperatureSensorCapability, j as deviceAdoptionCapability, k as controlCapability, lt as waterHeaterCapability, m as alarmPanelCapability, mt as DeviceRole, n as BaseDevice, nt as switchCapability, o as EnumSensorDateTimeFormatSchema, ot as vacuumControlCapability, p as airQualitySensorCapability, pt as DeviceFeature, q as notifierCapability, r as BaseDeviceProvider, rt as tamperCapability, st as valveCapability, tt as smokeCapability, u as TargetSchema, ut as weatherCapability, v as bestLocationMatch, vt as array, w as carbonMonoxideCapability, wt as string, x as brokerCapability, xt as number, y as binaryCapability, yt as discriminatedUnion, z as humiditySensorCapability } from "./dist-DObg5VV6.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
4
4
  //#region src/ha-device-source.ts
@@ -1,4 +1,4 @@
1
- //#region ../types/dist/event-category-Bxo5yJjt.mjs
1
+ //#region ../types/dist/event-category-XfKNtfCc.mjs
2
2
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
3
3
  EventCategory["SystemBoot"] = "system.boot";
4
4
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -15,9 +15,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
15
15
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
16
16
  /**
17
17
  * A newer addon or server-root package version was found by the
18
- * authoritative registry check. Emitted once per
19
- * `(target, packageName, currentVersion, latestVersion)` transition; repeated
20
- * polling of the same result is deduplicated by the checker.
18
+ * authoritative registry check. Emitted once when any observed
19
+ * `latestVersion` changes (or a package/node first appears behind);
20
+ * the payload carries the full currently-available list. Repeated
21
+ * polling of the same latests is silent.
21
22
  */
22
23
  EventCategory["UpdateAvailable"] = "update.available";
23
24
  /**
@@ -36,6 +37,22 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
36
37
  EventCategory["AddonInstalled"] = "addon.installed";
37
38
  EventCategory["AddonUninstalled"] = "addon.uninstalled";
38
39
  EventCategory["AddonCrashed"] = "addon.crashed";
40
+ /**
41
+ * A RUNNER the D6 crash circuit-breaker gave up on — terminal.
42
+ *
43
+ * `AddonCrashed` is the routine, self-healing fact ("it crashed; it is being
44
+ * respawned"); this is the one that never resolves itself. Emitted exactly
45
+ * once per trip, by `process-service.ts`, carrying the node, the runner, the
46
+ * addons it hosted and the crash count that tripped the breaker.
47
+ *
48
+ * It exists because a runner marked terminally `failed` used to be SILENT:
49
+ * on 2026-08-18 the `recorder` runner died of three unhandled ffmpeg spawn
50
+ * errors, the breaker stopped respawning it (correctly), `/health` kept
51
+ * returning 200, and fleet-wide recording was gone for 3h15 before the
52
+ * operator's phone told him. The Notification Center's system-event intake
53
+ * consumes this category and maps it to the `addon-crash-loop` kind.
54
+ */
55
+ EventCategory["AddonRunnerFailed"] = "addon.runner-failed";
39
56
  EventCategory["AddonError"] = "addon.error";
40
57
  EventCategory["AddonPageReady"] = "addon.page-ready";
41
58
  EventCategory["AddonWidgetReady"] = "addon.widget-ready";
@@ -7666,6 +7683,10 @@ var RecordingBandSchema = object({
7666
7683
  preBufferSec: number().min(0).optional(),
7667
7684
  postBufferSec: number().min(0).optional()
7668
7685
  });
7686
+ ({
7687
+ preBufferSec: 10,
7688
+ postBufferSec: 30
7689
+ }).postBufferSec * 1e3;
7669
7690
  /**
7670
7691
  * Per-device retention overrides. Every field is optional; an unset or `0`
7671
7692
  * value inherits the node-wide recorder default. Only footage-lifetime limits
@@ -7713,6 +7734,12 @@ var RecordingConfigSchema = object({
7713
7734
  /** DERIVED summary of `bands`, stamped by the recorder on every save.
7714
7735
  * Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
7715
7736
  mode: RecordingStorageModeSchema.optional(),
7737
+ /**
7738
+ * Which assigned broker slots to record. Absent / empty = {@link
7739
+ * DEFAULT_RECORDING_PROFILES} (`high`+`low`) intersected with the
7740
+ * camera's currently assigned slots — never `mid` unless the operator
7741
+ * picks it, and never a slot the broker has not assigned.
7742
+ */
7716
7743
  profiles: array(CamProfileSchema).optional(),
7717
7744
  segmentSeconds: number().int().positive().optional(),
7718
7745
  /**
@@ -7793,7 +7820,11 @@ var RelocateFootageInputSchema = object({
7793
7820
  profiles: array(string()).optional(),
7794
7821
  /** Copy throttle in MB/s (default 40) — the drain is a background chore,
7795
7822
  * never allowed to starve live writers. */
7796
- throttleMbps: number().min(1).max(1e3).optional()
7823
+ throttleMbps: number().min(1).max(1e3).optional(),
7824
+ /** Move only segments whose startMs is >= this. Absent = the whole source
7825
+ * pile. Used when a full drain is too expensive and the operator only
7826
+ * wants the recent window on the new disk. */
7827
+ sinceMs: number().int().optional()
7797
7828
  });
7798
7829
  /** Internal, lease-scoped participant operation. It is intentionally separate
7799
7830
  * from persistent recording settings: a migration never changes
@@ -14827,6 +14858,7 @@ var NcSystemEventKindSchema = _enum([
14827
14858
  "node-offline",
14828
14859
  "node-inference-unavailable",
14829
14860
  "detection-blind",
14861
+ "addon-crash-loop",
14830
14862
  "addon-update-available",
14831
14863
  "server-update-available",
14832
14864
  "alarm-triggered",
@@ -14834,6 +14866,9 @@ var NcSystemEventKindSchema = _enum([
14834
14866
  "alarm-disarmed",
14835
14867
  "alarm-arming",
14836
14868
  "alarm-arm-refused",
14869
+ "addon-updated",
14870
+ "server-updated",
14871
+ "export-completed",
14837
14872
  "camera-online",
14838
14873
  "camera-offline",
14839
14874
  "camera-disabled",
@@ -16733,13 +16768,19 @@ var RetrainStatusSchema = _enum([
16733
16768
  * "never marked" from "already trained" must read `retrainStatus`.
16734
16769
  *
16735
16770
  * `debug` does NOT pin; it is attention, not durability.
16771
+ *
16772
+ * `favourited` IS a BOOLEAN pin (durability bit), not a retrain lifecycle.
16773
+ * A favourited track is skipped by retention the same way `staging` is, but
16774
+ * it does not enter `none|staging|trained` and has no staging budget.
16736
16775
  */
16737
16776
  var TrackFlagFields = {
16738
16777
  /** Operator marked this track as training material — i.e. `retrainStatus` is
16739
16778
  * `'staging'`. */
16740
16779
  markForTrain: boolean().optional(),
16741
16780
  /** Operator marked this track for diagnostic attention. */
16742
- debug: boolean().optional()
16781
+ debug: boolean().optional(),
16782
+ /** Operator favourited this track. Pins it against pruning. */
16783
+ favourited: boolean().optional()
16743
16784
  };
16744
16785
  /**
16745
16786
  * The lifecycle field itself, on the READ surfaces only (`Track`, `KeyEvent`).
@@ -16764,6 +16805,7 @@ var TrackFlagsSchema = object({
16764
16805
  trackId: string(),
16765
16806
  markForTrain: boolean(),
16766
16807
  debug: boolean(),
16808
+ favourited: boolean(),
16767
16809
  /** The lifecycle state the boolean was derived from. Required here (unlike on
16768
16810
  * a track row) because this shape is only ever produced by the write body,
16769
16811
  * which always knows it — and a surface that has just written needs to render
@@ -17396,6 +17438,12 @@ var TrackCascadeCountsSchema = object({
17396
17438
  /** Per-track CLIP search vectors removed (best-effort). */
17397
17439
  embeddings: number().int()
17398
17440
  });
17441
+ /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17442
+ var DiskReconcileCountsSchema = object({
17443
+ mediaDropped: number().int(),
17444
+ tracks: number().int(),
17445
+ events: number().int()
17446
+ });
17399
17447
  /** Event-store footprint for one camera. */
17400
17448
  var EventStoreDeviceFootprintSchema = object({
17401
17449
  deviceId: number(),
@@ -17572,6 +17620,9 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17572
17620
  }), method(object({ deviceId: number() }), TrackCascadeCountsSchema, {
17573
17621
  kind: "mutation",
17574
17622
  auth: "admin"
17623
+ }), method(object({ deviceId: number() }), DiskReconcileCountsSchema, {
17624
+ kind: "mutation",
17625
+ auth: "admin"
17575
17626
  }), method(object({
17576
17627
  deviceId: number(),
17577
17628
  trackIds: array(string()).min(1)
@@ -19122,6 +19173,24 @@ var CameraStatusDegradationSchema = object({
19122
19173
  *
19123
19174
  * See spec: `docs/superpowers/specs/2026-06-24-camera-status-aggregator-cap.md`
19124
19175
  */
19176
+ var DiskReconcileJobSchema = object({
19177
+ state: _enum([
19178
+ "idle",
19179
+ "running",
19180
+ "done",
19181
+ "error"
19182
+ ]),
19183
+ total: number().int().nonnegative(),
19184
+ completed: number().int().nonnegative(),
19185
+ currentDeviceId: number().int().nullable(),
19186
+ failed: array(number().int()).readonly(),
19187
+ mediaDropped: number().int().nonnegative(),
19188
+ tracks: number().int().nonnegative(),
19189
+ events: number().int().nonnegative(),
19190
+ startedAtMs: number().int().nullable(),
19191
+ finishedAtMs: number().int().nullable(),
19192
+ error: string().nullable()
19193
+ });
19125
19194
  var CameraStatusSchema = object({
19126
19195
  deviceId: number(),
19127
19196
  assignment: CameraAssignmentStatusSchema,
@@ -19353,7 +19422,10 @@ method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
19353
19422
  }), CameraSwitchGroupSchema, {
19354
19423
  kind: "mutation",
19355
19424
  auth: "admin"
19356
- }), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
19425
+ }), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), DiskReconcileJobSchema, {
19426
+ kind: "mutation",
19427
+ auth: "admin"
19428
+ }), method(_void(), DiskReconcileJobSchema, { auth: "admin" }), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
19357
19429
  name: string(),
19358
19430
  description: string().optional(),
19359
19431
  config: CameraPipelineConfigSchema
@@ -20426,20 +20498,6 @@ var VectorStatsResultSchema = object({
20426
20498
  exact: boolean()
20427
20499
  });
20428
20500
  method(VectorDeclareIndexInputSchema, _void(), { kind: "mutation" }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, { kind: "mutation" }), method(VectorQueryInputSchema, VectorQueryResultSchema), method(VectorGetInputSchema, VectorGetResultSchema), method(VectorDeleteInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorStatsInputSchema, VectorStatsResultSchema);
20429
- /**
20430
- * `videoclips` — the unified, navigable-clip surface for a camera.
20431
- *
20432
- * A device-scoped WRAPPER cap (like `pipeline-analytics`): exactly one active
20433
- * provider per device, substitutable. The DEFAULT provider (registered by
20434
- * `addon-post-analysis`, `defaultActive: true`) composes the analytics event
20435
- * log (markers + thumbnails) with the recorder's `getPlaybackManifest` — a clip
20436
- * is a time-WINDOW over existing footage, never a separate file. A camera that
20437
- * exposes NATIVE onboard clips (Reolink/Hikvision NVR) can later substitute the
20438
- * wrapper provider for its device and serve its own clip catalog + URLs.
20439
- *
20440
- * A `Clip` is purely time-based (subtree-blind): playback resolves segments by
20441
- * temporal overlap, so the API never decides `continuous` vs `events`.
20442
- */
20443
20501
  var ClipSchema = object({
20444
20502
  /** Opaque, provider-namespaced id. The default provider encodes the time
20445
20503
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -20456,8 +20514,65 @@ var ClipSchema = object({
20456
20514
  startMs: number(),
20457
20515
  endMs: number()
20458
20516
  }),
20459
- /** Thumbnail URL (lazy; e.g. analytics `getEventMedia`). Never inlined. */
20460
- thumbnail: string().optional()
20517
+ /**
20518
+ * Distinct object classes attached to this visit (`person`, `car`, …),
20519
+ * dominant first, capped at {@link MAX_CLIP_LABELS}. The ribbon renders these
20520
+ * instead of the bare kind — "Object" tells the operator nothing a colour bar
20521
+ * did not. Absent (never empty) when the visit attached no classified object
20522
+ * event, so a motion/audio-only visit keeps its kind label.
20523
+ */
20524
+ labels: array(string()).max(3).optional(),
20525
+ /**
20526
+ * Lazy thumbnail URL, never inlined.
20527
+ *
20528
+ * Recording-derived clips (events-mode keep-window, and the prepared
20529
+ * continuous event+fragment visit) MUST use the snapshot of the **main
20530
+ * event of the interval** — `getEventMedia({ eventId, kind: 'snapshot' })`
20531
+ * of the event that owns `kind` (object > motion > audio). Do not extract
20532
+ * a keyframe from the recorded segments. Other providers (onboard, HKSV)
20533
+ * mint their own stills.
20534
+ *
20535
+ * **VOUCHED, never fabricated.** A provider emits this only for an event it
20536
+ * has CONFIRMED owns at least one media row (its own, or its owning track's).
20537
+ * Absent is meaningful — "this visit has no event still" — never "we did not
20538
+ * look". Stamping it from a URL template made 35% of one camera's clips point
20539
+ * at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
20540
+ * A read that FAILS drops the claim; it never invents it.
20541
+ */
20542
+ thumbnail: string().optional(),
20543
+ /**
20544
+ * An instant INSIDE this visit's footage, hole-safe, where a recorded still
20545
+ * can be decoded. Present whenever the visit came from recorded availability;
20546
+ * absent on a per-event padded window (there is no footage to promise).
20547
+ *
20548
+ * This is not a thumbnail and not a second byte path: it is the argument to
20549
+ * the recorder's existing still route. The surface — never the provider —
20550
+ * decides whether to use it. It is the midpoint of the visit's LONGEST
20551
+ * contiguous range, not of the visit: a visit spans its holes by
20552
+ * construction, so a naive midpoint lands in dead air.
20553
+ */
20554
+ stillAtMs: number().optional(),
20555
+ /**
20556
+ * Analytics event ids that overlap this visit — a BOUNDED sample, newest
20557
+ * first within kind (object → motion → audio), capped at
20558
+ * {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
20559
+ *
20560
+ * Bounded because it is not a payload the surface pages through: one visit on
20561
+ * device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
20562
+ * camera-day. Read {@link eventCount} for the true total.
20563
+ */
20564
+ eventIds: array(string()).optional(),
20565
+ /** How many analytics events actually overlap this visit. Differs from
20566
+ * `eventIds.length` exactly when the sample was capped — so a truncated
20567
+ * list is never mistaken for a quiet visit. */
20568
+ eventCount: number().int().nonnegative().optional(),
20569
+ /** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
20570
+ * than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
20571
+ * bar keeps showing them via `recording.getAvailability`. */
20572
+ holes: array(object({
20573
+ startMs: number(),
20574
+ endMs: number()
20575
+ })).optional()
20461
20576
  });
20462
20577
  var ClipPlaybackSchema = object({
20463
20578
  /** HLS master URL through the hub data-plane (Range + token in path). */
@@ -20993,7 +21108,14 @@ var SearchResultSchema = object({
20993
21108
  });
20994
21109
  var AutoUpdateSettingsSchema = object({
20995
21110
  channel: ChannelSchema,
20996
- intervalSeconds: number()
21111
+ intervalSeconds: number(),
21112
+ /**
21113
+ * Cadence of the "an update exists" POLLER, in seconds. Independent of
21114
+ * `channel`: the poller runs while auto-apply is `off`, because being told
21115
+ * about a publish and installing it are different decisions. Clamped
21116
+ * server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
21117
+ */
21118
+ updateCheckIntervalSeconds: number()
20997
21119
  });
20998
21120
  var AddonAutoUpdateSchema = ChannelWithInheritSchema;
20999
21121
  var RestartAddonResultSchema = unknown();
@@ -21134,7 +21256,9 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21134
21256
  auth: "admin"
21135
21257
  }), method(_void(), AutoUpdateSettingsSchema, { auth: "admin" }), method(object({
21136
21258
  channel: ChannelSchema,
21137
- intervalSeconds: number().min(300).max(86400).optional()
21259
+ intervalSeconds: number().min(300).max(86400).optional(),
21260
+ /** Availability-poll cadence; see AutoUpdateSettingsSchema. */
21261
+ updateCheckIntervalSeconds: number().min(900).max(604800).optional()
21138
21262
  }), unknown(), {
21139
21263
  kind: "mutation",
21140
21264
  auth: "admin"
@@ -26832,7 +26956,9 @@ var ExportOptionsSchema = object({
26832
26956
  includeAudio: boolean(),
26833
26957
  maxLifeMs: number().int().positive(),
26834
26958
  deleteAfterDownload: boolean(),
26835
- title: string().max(200).optional()
26959
+ title: string().max(200).optional(),
26960
+ /** Notification-output target ids to ping when this export becomes ready. */
26961
+ notifyTargetIds: array(string().min(1)).max(20).optional()
26836
26962
  }).superRefine((v, ctx) => {
26837
26963
  if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
26838
26964
  code: ZodIssueCode.custom,
@@ -26891,10 +27017,18 @@ var ExportBytesSchema = object({
26891
27017
  });
26892
27018
  method(object({
26893
27019
  deviceId: number(),
26894
- profile: string(),
27020
+ /** @deprecated Prefer `profiles`. Kept so timelapse/notifiers keep working. */
27021
+ profile: string().optional(),
27022
+ profiles: array(string()).min(1).optional(),
26895
27023
  fromMs: number(),
26896
27024
  toMs: number(),
26897
27025
  options: ExportOptionsSchema
27026
+ }).superRefine((v, ctx) => {
27027
+ if ((v.profiles !== void 0 && v.profiles.length > 0 ? v.profiles : v.profile !== void 0 ? [v.profile] : []).length < 1) ctx.addIssue({
27028
+ code: ZodIssueCode.custom,
27029
+ message: "pass profiles[] (min 1) or legacy profile",
27030
+ path: ["profiles"]
27031
+ });
26898
27032
  }), ExportRecordSchema, {
26899
27033
  kind: "mutation",
26900
27034
  auth: "protected"
@@ -29836,15 +29970,6 @@ var BaseDeviceProvider = class extends BaseAddon {
29836
29970
  labels: ["probe not implemented"]
29837
29971
  };
29838
29972
  }
29839
- /**
29840
- * Top-level devices restored at once in {@link onRestoreDevices}.
29841
- *
29842
- * Four covers the fleets this ships to without turning a boot into a burst a
29843
- * camera NVR answers with a refusal. A provider whose upstream is a single
29844
- * session with a serial command channel (a Baichuan hub, an NVR that
29845
- * serialises ISAPI) should lower it; nothing needs to raise it.
29846
- */
29847
- restoreConcurrency = 4;
29848
29973
  async restoreDevices(savedDevices) {
29849
29974
  await this.onRestoreDevices(savedDevices);
29850
29975
  if (savedDevices.length > 0) this.ctx.logger.info(`Restored ${savedDevices.length} ${this.providerName} device(s)`);
@@ -29899,14 +30024,7 @@ var BaseDeviceProvider = class extends BaseAddon {
29899
30024
  });
29900
30025
  }
29901
30026
  };
29902
- let nextTopLevel = 0;
29903
- await Promise.all(Array.from({ length: Math.min(Math.max(1, this.restoreConcurrency), topLevel.length) }, async () => {
29904
- for (;;) {
29905
- const saved = topLevel[nextTopLevel++];
29906
- if (saved === void 0) return;
29907
- await restoreOne(saved);
29908
- }
29909
- }));
30027
+ await Promise.all(topLevel.map((saved) => restoreOne(saved)));
29910
30028
  const childRows = savedDevices.filter((s) => s.parentDeviceId !== null);
29911
30029
  for (const saved of childRows) {
29912
30030
  const Class = this.deviceClasses[saved.type];
@@ -33179,6 +33297,12 @@ Object.freeze({
33179
33297
  addonId: null,
33180
33298
  access: "create"
33181
33299
  },
33300
+ "pipelineAnalytics.reconcileFromDisk": {
33301
+ capName: "pipeline-analytics",
33302
+ capScope: "device",
33303
+ addonId: null,
33304
+ access: "create"
33305
+ },
33182
33306
  "pipelineAnalytics.refreshStorageLocationsForMigration": {
33183
33307
  capName: "pipeline-analytics",
33184
33308
  capScope: "device",
@@ -33581,6 +33705,12 @@ Object.freeze({
33581
33705
  addonId: null,
33582
33706
  access: "view"
33583
33707
  },
33708
+ "pipelineOrchestrator.getReconcileFromDiskStatus": {
33709
+ capName: "pipeline-orchestrator",
33710
+ capScope: "system",
33711
+ addonId: null,
33712
+ access: "view"
33713
+ },
33584
33714
  "pipelineOrchestrator.listAgentSettings": {
33585
33715
  capName: "pipeline-orchestrator",
33586
33716
  capScope: "system",
@@ -33605,6 +33735,12 @@ Object.freeze({
33605
33735
  addonId: null,
33606
33736
  access: "create"
33607
33737
  },
33738
+ "pipelineOrchestrator.reconcileFromDisk": {
33739
+ capName: "pipeline-orchestrator",
33740
+ capScope: "system",
33741
+ addonId: null,
33742
+ access: "create"
33743
+ },
33608
33744
  "pipelineOrchestrator.removeAgentSettings": {
33609
33745
  capName: "pipeline-orchestrator",
33610
33746
  capScope: "system",
@@ -36596,6 +36732,11 @@ Object.freeze({
36596
36732
  form: "single",
36597
36733
  optional: true
36598
36734
  }],
36735
+ "pipelineAnalytics.reconcileFromDisk": [{
36736
+ name: "deviceId",
36737
+ form: "single",
36738
+ optional: false
36739
+ }],
36599
36740
  "pipelineAnalytics.restageRetrainTrack": [{
36600
36741
  name: "deviceId",
36601
36742
  form: "single",
@@ -37920,6 +38061,8 @@ function bestLocationMatch(externalName, existing, threshold = .8) {
37920
38061
  }
37921
38062
  return best;
37922
38063
  }
38064
+ var MB = 1024 * 1024;
38065
+ 1024 * MB, 3072 * MB;
37923
38066
  //#endregion
37924
38067
  Object.defineProperty(exports, "AlarmArmModeSchema", {
37925
38068
  enumerable: true,
@@ -1,4 +1,4 @@
1
- //#region ../types/dist/event-category-Bxo5yJjt.mjs
1
+ //#region ../types/dist/event-category-XfKNtfCc.mjs
2
2
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
3
3
  EventCategory["SystemBoot"] = "system.boot";
4
4
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -15,9 +15,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
15
15
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
16
16
  /**
17
17
  * A newer addon or server-root package version was found by the
18
- * authoritative registry check. Emitted once per
19
- * `(target, packageName, currentVersion, latestVersion)` transition; repeated
20
- * polling of the same result is deduplicated by the checker.
18
+ * authoritative registry check. Emitted once when any observed
19
+ * `latestVersion` changes (or a package/node first appears behind);
20
+ * the payload carries the full currently-available list. Repeated
21
+ * polling of the same latests is silent.
21
22
  */
22
23
  EventCategory["UpdateAvailable"] = "update.available";
23
24
  /**
@@ -36,6 +37,22 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
36
37
  EventCategory["AddonInstalled"] = "addon.installed";
37
38
  EventCategory["AddonUninstalled"] = "addon.uninstalled";
38
39
  EventCategory["AddonCrashed"] = "addon.crashed";
40
+ /**
41
+ * A RUNNER the D6 crash circuit-breaker gave up on — terminal.
42
+ *
43
+ * `AddonCrashed` is the routine, self-healing fact ("it crashed; it is being
44
+ * respawned"); this is the one that never resolves itself. Emitted exactly
45
+ * once per trip, by `process-service.ts`, carrying the node, the runner, the
46
+ * addons it hosted and the crash count that tripped the breaker.
47
+ *
48
+ * It exists because a runner marked terminally `failed` used to be SILENT:
49
+ * on 2026-08-18 the `recorder` runner died of three unhandled ffmpeg spawn
50
+ * errors, the breaker stopped respawning it (correctly), `/health` kept
51
+ * returning 200, and fleet-wide recording was gone for 3h15 before the
52
+ * operator's phone told him. The Notification Center's system-event intake
53
+ * consumes this category and maps it to the `addon-crash-loop` kind.
54
+ */
55
+ EventCategory["AddonRunnerFailed"] = "addon.runner-failed";
39
56
  EventCategory["AddonError"] = "addon.error";
40
57
  EventCategory["AddonPageReady"] = "addon.page-ready";
41
58
  EventCategory["AddonWidgetReady"] = "addon.widget-ready";
@@ -7666,6 +7683,10 @@ var RecordingBandSchema = object({
7666
7683
  preBufferSec: number().min(0).optional(),
7667
7684
  postBufferSec: number().min(0).optional()
7668
7685
  });
7686
+ ({
7687
+ preBufferSec: 10,
7688
+ postBufferSec: 30
7689
+ }).postBufferSec * 1e3;
7669
7690
  /**
7670
7691
  * Per-device retention overrides. Every field is optional; an unset or `0`
7671
7692
  * value inherits the node-wide recorder default. Only footage-lifetime limits
@@ -7713,6 +7734,12 @@ var RecordingConfigSchema = object({
7713
7734
  /** DERIVED summary of `bands`, stamped by the recorder on every save.
7714
7735
  * Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
7715
7736
  mode: RecordingStorageModeSchema.optional(),
7737
+ /**
7738
+ * Which assigned broker slots to record. Absent / empty = {@link
7739
+ * DEFAULT_RECORDING_PROFILES} (`high`+`low`) intersected with the
7740
+ * camera's currently assigned slots — never `mid` unless the operator
7741
+ * picks it, and never a slot the broker has not assigned.
7742
+ */
7716
7743
  profiles: array(CamProfileSchema).optional(),
7717
7744
  segmentSeconds: number().int().positive().optional(),
7718
7745
  /**
@@ -7793,7 +7820,11 @@ var RelocateFootageInputSchema = object({
7793
7820
  profiles: array(string()).optional(),
7794
7821
  /** Copy throttle in MB/s (default 40) — the drain is a background chore,
7795
7822
  * never allowed to starve live writers. */
7796
- throttleMbps: number().min(1).max(1e3).optional()
7823
+ throttleMbps: number().min(1).max(1e3).optional(),
7824
+ /** Move only segments whose startMs is >= this. Absent = the whole source
7825
+ * pile. Used when a full drain is too expensive and the operator only
7826
+ * wants the recent window on the new disk. */
7827
+ sinceMs: number().int().optional()
7797
7828
  });
7798
7829
  /** Internal, lease-scoped participant operation. It is intentionally separate
7799
7830
  * from persistent recording settings: a migration never changes
@@ -14827,6 +14858,7 @@ var NcSystemEventKindSchema = _enum([
14827
14858
  "node-offline",
14828
14859
  "node-inference-unavailable",
14829
14860
  "detection-blind",
14861
+ "addon-crash-loop",
14830
14862
  "addon-update-available",
14831
14863
  "server-update-available",
14832
14864
  "alarm-triggered",
@@ -14834,6 +14866,9 @@ var NcSystemEventKindSchema = _enum([
14834
14866
  "alarm-disarmed",
14835
14867
  "alarm-arming",
14836
14868
  "alarm-arm-refused",
14869
+ "addon-updated",
14870
+ "server-updated",
14871
+ "export-completed",
14837
14872
  "camera-online",
14838
14873
  "camera-offline",
14839
14874
  "camera-disabled",
@@ -16733,13 +16768,19 @@ var RetrainStatusSchema = _enum([
16733
16768
  * "never marked" from "already trained" must read `retrainStatus`.
16734
16769
  *
16735
16770
  * `debug` does NOT pin; it is attention, not durability.
16771
+ *
16772
+ * `favourited` IS a BOOLEAN pin (durability bit), not a retrain lifecycle.
16773
+ * A favourited track is skipped by retention the same way `staging` is, but
16774
+ * it does not enter `none|staging|trained` and has no staging budget.
16736
16775
  */
16737
16776
  var TrackFlagFields = {
16738
16777
  /** Operator marked this track as training material — i.e. `retrainStatus` is
16739
16778
  * `'staging'`. */
16740
16779
  markForTrain: boolean().optional(),
16741
16780
  /** Operator marked this track for diagnostic attention. */
16742
- debug: boolean().optional()
16781
+ debug: boolean().optional(),
16782
+ /** Operator favourited this track. Pins it against pruning. */
16783
+ favourited: boolean().optional()
16743
16784
  };
16744
16785
  /**
16745
16786
  * The lifecycle field itself, on the READ surfaces only (`Track`, `KeyEvent`).
@@ -16764,6 +16805,7 @@ var TrackFlagsSchema = object({
16764
16805
  trackId: string(),
16765
16806
  markForTrain: boolean(),
16766
16807
  debug: boolean(),
16808
+ favourited: boolean(),
16767
16809
  /** The lifecycle state the boolean was derived from. Required here (unlike on
16768
16810
  * a track row) because this shape is only ever produced by the write body,
16769
16811
  * which always knows it — and a surface that has just written needs to render
@@ -17396,6 +17438,12 @@ var TrackCascadeCountsSchema = object({
17396
17438
  /** Per-track CLIP search vectors removed (best-effort). */
17397
17439
  embeddings: number().int()
17398
17440
  });
17441
+ /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
17442
+ var DiskReconcileCountsSchema = object({
17443
+ mediaDropped: number().int(),
17444
+ tracks: number().int(),
17445
+ events: number().int()
17446
+ });
17399
17447
  /** Event-store footprint for one camera. */
17400
17448
  var EventStoreDeviceFootprintSchema = object({
17401
17449
  deviceId: number(),
@@ -17572,6 +17620,9 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
17572
17620
  }), method(object({ deviceId: number() }), TrackCascadeCountsSchema, {
17573
17621
  kind: "mutation",
17574
17622
  auth: "admin"
17623
+ }), method(object({ deviceId: number() }), DiskReconcileCountsSchema, {
17624
+ kind: "mutation",
17625
+ auth: "admin"
17575
17626
  }), method(object({
17576
17627
  deviceId: number(),
17577
17628
  trackIds: array(string()).min(1)
@@ -19122,6 +19173,24 @@ var CameraStatusDegradationSchema = object({
19122
19173
  *
19123
19174
  * See spec: `docs/superpowers/specs/2026-06-24-camera-status-aggregator-cap.md`
19124
19175
  */
19176
+ var DiskReconcileJobSchema = object({
19177
+ state: _enum([
19178
+ "idle",
19179
+ "running",
19180
+ "done",
19181
+ "error"
19182
+ ]),
19183
+ total: number().int().nonnegative(),
19184
+ completed: number().int().nonnegative(),
19185
+ currentDeviceId: number().int().nullable(),
19186
+ failed: array(number().int()).readonly(),
19187
+ mediaDropped: number().int().nonnegative(),
19188
+ tracks: number().int().nonnegative(),
19189
+ events: number().int().nonnegative(),
19190
+ startedAtMs: number().int().nullable(),
19191
+ finishedAtMs: number().int().nullable(),
19192
+ error: string().nullable()
19193
+ });
19125
19194
  var CameraStatusSchema = object({
19126
19195
  deviceId: number(),
19127
19196
  assignment: CameraAssignmentStatusSchema,
@@ -19353,7 +19422,10 @@ method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
19353
19422
  }), CameraSwitchGroupSchema, {
19354
19423
  kind: "mutation",
19355
19424
  auth: "admin"
19356
- }), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
19425
+ }), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), DiskReconcileJobSchema, {
19426
+ kind: "mutation",
19427
+ auth: "admin"
19428
+ }), method(_void(), DiskReconcileJobSchema, { auth: "admin" }), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
19357
19429
  name: string(),
19358
19430
  description: string().optional(),
19359
19431
  config: CameraPipelineConfigSchema
@@ -20426,20 +20498,6 @@ var VectorStatsResultSchema = object({
20426
20498
  exact: boolean()
20427
20499
  });
20428
20500
  method(VectorDeclareIndexInputSchema, _void(), { kind: "mutation" }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, { kind: "mutation" }), method(VectorQueryInputSchema, VectorQueryResultSchema), method(VectorGetInputSchema, VectorGetResultSchema), method(VectorDeleteInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorStatsInputSchema, VectorStatsResultSchema);
20429
- /**
20430
- * `videoclips` — the unified, navigable-clip surface for a camera.
20431
- *
20432
- * A device-scoped WRAPPER cap (like `pipeline-analytics`): exactly one active
20433
- * provider per device, substitutable. The DEFAULT provider (registered by
20434
- * `addon-post-analysis`, `defaultActive: true`) composes the analytics event
20435
- * log (markers + thumbnails) with the recorder's `getPlaybackManifest` — a clip
20436
- * is a time-WINDOW over existing footage, never a separate file. A camera that
20437
- * exposes NATIVE onboard clips (Reolink/Hikvision NVR) can later substitute the
20438
- * wrapper provider for its device and serve its own clip catalog + URLs.
20439
- *
20440
- * A `Clip` is purely time-based (subtree-blind): playback resolves segments by
20441
- * temporal overlap, so the API never decides `continuous` vs `events`.
20442
- */
20443
20501
  var ClipSchema = object({
20444
20502
  /** Opaque, provider-namespaced id. The default provider encodes the time
20445
20503
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -20456,8 +20514,65 @@ var ClipSchema = object({
20456
20514
  startMs: number(),
20457
20515
  endMs: number()
20458
20516
  }),
20459
- /** Thumbnail URL (lazy; e.g. analytics `getEventMedia`). Never inlined. */
20460
- thumbnail: string().optional()
20517
+ /**
20518
+ * Distinct object classes attached to this visit (`person`, `car`, …),
20519
+ * dominant first, capped at {@link MAX_CLIP_LABELS}. The ribbon renders these
20520
+ * instead of the bare kind — "Object" tells the operator nothing a colour bar
20521
+ * did not. Absent (never empty) when the visit attached no classified object
20522
+ * event, so a motion/audio-only visit keeps its kind label.
20523
+ */
20524
+ labels: array(string()).max(3).optional(),
20525
+ /**
20526
+ * Lazy thumbnail URL, never inlined.
20527
+ *
20528
+ * Recording-derived clips (events-mode keep-window, and the prepared
20529
+ * continuous event+fragment visit) MUST use the snapshot of the **main
20530
+ * event of the interval** — `getEventMedia({ eventId, kind: 'snapshot' })`
20531
+ * of the event that owns `kind` (object > motion > audio). Do not extract
20532
+ * a keyframe from the recorded segments. Other providers (onboard, HKSV)
20533
+ * mint their own stills.
20534
+ *
20535
+ * **VOUCHED, never fabricated.** A provider emits this only for an event it
20536
+ * has CONFIRMED owns at least one media row (its own, or its owning track's).
20537
+ * Absent is meaningful — "this visit has no event still" — never "we did not
20538
+ * look". Stamping it from a URL template made 35% of one camera's clips point
20539
+ * at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
20540
+ * A read that FAILS drops the claim; it never invents it.
20541
+ */
20542
+ thumbnail: string().optional(),
20543
+ /**
20544
+ * An instant INSIDE this visit's footage, hole-safe, where a recorded still
20545
+ * can be decoded. Present whenever the visit came from recorded availability;
20546
+ * absent on a per-event padded window (there is no footage to promise).
20547
+ *
20548
+ * This is not a thumbnail and not a second byte path: it is the argument to
20549
+ * the recorder's existing still route. The surface — never the provider —
20550
+ * decides whether to use it. It is the midpoint of the visit's LONGEST
20551
+ * contiguous range, not of the visit: a visit spans its holes by
20552
+ * construction, so a naive midpoint lands in dead air.
20553
+ */
20554
+ stillAtMs: number().optional(),
20555
+ /**
20556
+ * Analytics event ids that overlap this visit — a BOUNDED sample, newest
20557
+ * first within kind (object → motion → audio), capped at
20558
+ * {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
20559
+ *
20560
+ * Bounded because it is not a payload the surface pages through: one visit on
20561
+ * device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
20562
+ * camera-day. Read {@link eventCount} for the true total.
20563
+ */
20564
+ eventIds: array(string()).optional(),
20565
+ /** How many analytics events actually overlap this visit. Differs from
20566
+ * `eventIds.length` exactly when the sample was capped — so a truncated
20567
+ * list is never mistaken for a quiet visit. */
20568
+ eventCount: number().int().nonnegative().optional(),
20569
+ /** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
20570
+ * than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
20571
+ * bar keeps showing them via `recording.getAvailability`. */
20572
+ holes: array(object({
20573
+ startMs: number(),
20574
+ endMs: number()
20575
+ })).optional()
20461
20576
  });
20462
20577
  var ClipPlaybackSchema = object({
20463
20578
  /** HLS master URL through the hub data-plane (Range + token in path). */
@@ -20993,7 +21108,14 @@ var SearchResultSchema = object({
20993
21108
  });
20994
21109
  var AutoUpdateSettingsSchema = object({
20995
21110
  channel: ChannelSchema,
20996
- intervalSeconds: number()
21111
+ intervalSeconds: number(),
21112
+ /**
21113
+ * Cadence of the "an update exists" POLLER, in seconds. Independent of
21114
+ * `channel`: the poller runs while auto-apply is `off`, because being told
21115
+ * about a publish and installing it are different decisions. Clamped
21116
+ * server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
21117
+ */
21118
+ updateCheckIntervalSeconds: number()
20997
21119
  });
20998
21120
  var AddonAutoUpdateSchema = ChannelWithInheritSchema;
20999
21121
  var RestartAddonResultSchema = unknown();
@@ -21134,7 +21256,9 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
21134
21256
  auth: "admin"
21135
21257
  }), method(_void(), AutoUpdateSettingsSchema, { auth: "admin" }), method(object({
21136
21258
  channel: ChannelSchema,
21137
- intervalSeconds: number().min(300).max(86400).optional()
21259
+ intervalSeconds: number().min(300).max(86400).optional(),
21260
+ /** Availability-poll cadence; see AutoUpdateSettingsSchema. */
21261
+ updateCheckIntervalSeconds: number().min(900).max(604800).optional()
21138
21262
  }), unknown(), {
21139
21263
  kind: "mutation",
21140
21264
  auth: "admin"
@@ -26832,7 +26956,9 @@ var ExportOptionsSchema = object({
26832
26956
  includeAudio: boolean(),
26833
26957
  maxLifeMs: number().int().positive(),
26834
26958
  deleteAfterDownload: boolean(),
26835
- title: string().max(200).optional()
26959
+ title: string().max(200).optional(),
26960
+ /** Notification-output target ids to ping when this export becomes ready. */
26961
+ notifyTargetIds: array(string().min(1)).max(20).optional()
26836
26962
  }).superRefine((v, ctx) => {
26837
26963
  if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
26838
26964
  code: ZodIssueCode.custom,
@@ -26891,10 +27017,18 @@ var ExportBytesSchema = object({
26891
27017
  });
26892
27018
  method(object({
26893
27019
  deviceId: number(),
26894
- profile: string(),
27020
+ /** @deprecated Prefer `profiles`. Kept so timelapse/notifiers keep working. */
27021
+ profile: string().optional(),
27022
+ profiles: array(string()).min(1).optional(),
26895
27023
  fromMs: number(),
26896
27024
  toMs: number(),
26897
27025
  options: ExportOptionsSchema
27026
+ }).superRefine((v, ctx) => {
27027
+ if ((v.profiles !== void 0 && v.profiles.length > 0 ? v.profiles : v.profile !== void 0 ? [v.profile] : []).length < 1) ctx.addIssue({
27028
+ code: ZodIssueCode.custom,
27029
+ message: "pass profiles[] (min 1) or legacy profile",
27030
+ path: ["profiles"]
27031
+ });
26898
27032
  }), ExportRecordSchema, {
26899
27033
  kind: "mutation",
26900
27034
  auth: "protected"
@@ -29836,15 +29970,6 @@ var BaseDeviceProvider = class extends BaseAddon {
29836
29970
  labels: ["probe not implemented"]
29837
29971
  };
29838
29972
  }
29839
- /**
29840
- * Top-level devices restored at once in {@link onRestoreDevices}.
29841
- *
29842
- * Four covers the fleets this ships to without turning a boot into a burst a
29843
- * camera NVR answers with a refusal. A provider whose upstream is a single
29844
- * session with a serial command channel (a Baichuan hub, an NVR that
29845
- * serialises ISAPI) should lower it; nothing needs to raise it.
29846
- */
29847
- restoreConcurrency = 4;
29848
29973
  async restoreDevices(savedDevices) {
29849
29974
  await this.onRestoreDevices(savedDevices);
29850
29975
  if (savedDevices.length > 0) this.ctx.logger.info(`Restored ${savedDevices.length} ${this.providerName} device(s)`);
@@ -29899,14 +30024,7 @@ var BaseDeviceProvider = class extends BaseAddon {
29899
30024
  });
29900
30025
  }
29901
30026
  };
29902
- let nextTopLevel = 0;
29903
- await Promise.all(Array.from({ length: Math.min(Math.max(1, this.restoreConcurrency), topLevel.length) }, async () => {
29904
- for (;;) {
29905
- const saved = topLevel[nextTopLevel++];
29906
- if (saved === void 0) return;
29907
- await restoreOne(saved);
29908
- }
29909
- }));
30027
+ await Promise.all(topLevel.map((saved) => restoreOne(saved)));
29910
30028
  const childRows = savedDevices.filter((s) => s.parentDeviceId !== null);
29911
30029
  for (const saved of childRows) {
29912
30030
  const Class = this.deviceClasses[saved.type];
@@ -33179,6 +33297,12 @@ Object.freeze({
33179
33297
  addonId: null,
33180
33298
  access: "create"
33181
33299
  },
33300
+ "pipelineAnalytics.reconcileFromDisk": {
33301
+ capName: "pipeline-analytics",
33302
+ capScope: "device",
33303
+ addonId: null,
33304
+ access: "create"
33305
+ },
33182
33306
  "pipelineAnalytics.refreshStorageLocationsForMigration": {
33183
33307
  capName: "pipeline-analytics",
33184
33308
  capScope: "device",
@@ -33581,6 +33705,12 @@ Object.freeze({
33581
33705
  addonId: null,
33582
33706
  access: "view"
33583
33707
  },
33708
+ "pipelineOrchestrator.getReconcileFromDiskStatus": {
33709
+ capName: "pipeline-orchestrator",
33710
+ capScope: "system",
33711
+ addonId: null,
33712
+ access: "view"
33713
+ },
33584
33714
  "pipelineOrchestrator.listAgentSettings": {
33585
33715
  capName: "pipeline-orchestrator",
33586
33716
  capScope: "system",
@@ -33605,6 +33735,12 @@ Object.freeze({
33605
33735
  addonId: null,
33606
33736
  access: "create"
33607
33737
  },
33738
+ "pipelineOrchestrator.reconcileFromDisk": {
33739
+ capName: "pipeline-orchestrator",
33740
+ capScope: "system",
33741
+ addonId: null,
33742
+ access: "create"
33743
+ },
33608
33744
  "pipelineOrchestrator.removeAgentSettings": {
33609
33745
  capName: "pipeline-orchestrator",
33610
33746
  capScope: "system",
@@ -36596,6 +36732,11 @@ Object.freeze({
36596
36732
  form: "single",
36597
36733
  optional: true
36598
36734
  }],
36735
+ "pipelineAnalytics.reconcileFromDisk": [{
36736
+ name: "deviceId",
36737
+ form: "single",
36738
+ optional: false
36739
+ }],
36599
36740
  "pipelineAnalytics.restageRetrainTrack": [{
36600
36741
  name: "deviceId",
36601
36742
  form: "single",
@@ -37920,5 +38061,7 @@ function bestLocationMatch(externalName, existing, threshold = .8) {
37920
38061
  }
37921
38062
  return best;
37922
38063
  }
38064
+ var MB = 1024 * 1024;
38065
+ 1024 * MB, 3072 * MB;
37923
38066
  //#endregion
37924
38067
  export { pressureSensorCapability as $, coverCapability as A, imageCapability as B, buttonCapability as C, record as Ct, connectivityCapability as D, url as Dt, colorCapability as E, unknown as Et, fanControlCapability as F, normalizeUnit as G, lockControlCapability as H, floodCapability as I, numericSensorCapability as J, notificationOutputCapability as K, gasCapability as L, deviceExportCapability as M, enumSensorCapability as N, contactCapability as O, EventCategory as Ot, eventEmitterCapability as P, presenceCapability as Q, humidifierCapability as R, buildAddonRouteProvider as S, object as St, climateControlCapability as T, union as Tt, mediaPlayerCapability as U, lawnMowerControlCapability as V, motionCapability as W, powerMeterCapability as X, oauthIntegrationCapability as Y, prepareNotification as Z, batteryCapability as _, _enum as _t, CameraSwitchIdSchema as a, updateCapability as at, brightnessCapability as b, literal as bt, HvacModeSchema as c, vibrationCapability as ct, accessoriesCapability as d, errMsg as dt, scriptRunnerCapability as et, addonRoutesCapability as f, BaseAddon as ft, automationControlCapability as g, createEvent as gt, ambientLightSensorCapability as h, DeviceType as ht, COCO_TO_MACRO as i, temperatureSensorCapability as it, deviceAdoptionCapability as j, controlCapability as k, MediaPlayerRepeatSchema as l, waterHeaterCapability as lt, alarmPanelCapability as m, DeviceRole as mt, BaseDevice as n, switchCapability as nt, EnumSensorDateTimeFormatSchema as o, vacuumControlCapability as ot, airQualitySensorCapability as p, DeviceFeature as pt, notifierCapability as q, BaseDeviceProvider as r, tamperCapability as rt, FanDirectionSchema as s, valveCapability as st, AlarmArmModeSchema as t, smokeCapability as tt, TargetSchema as u, weatherCapability as ut, bestLocationMatch as v, array as vt, carbonMonoxideCapability as w, string as wt, brokerCapability as x, number as xt, binaryCapability as y, discriminatedUnion as yt, humiditySensorCapability as z };
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  //#endregion
6
- const require_dist = require("../dist-CkXDV-PV.js");
6
+ const require_dist = require("../dist-DCvHGfFW.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  //#region src/ha-export/topics.ts
9
9
  /**
@@ -1,4 +1,4 @@
1
- import { M as deviceExportCapability, Ot as EventCategory, S as buildAddonRouteProvider, Y as oauthIntegrationCapability, a as CameraSwitchIdSchema, c as HvacModeSchema, f as addonRoutesCapability, ft as BaseAddon, i as COCO_TO_MACRO, l as MediaPlayerRepeatSchema, s as FanDirectionSchema, t as AlarmArmModeSchema, wt as string } from "../dist-BlSbw9vH.mjs";
1
+ import { M as deviceExportCapability, Ot as EventCategory, S as buildAddonRouteProvider, Y as oauthIntegrationCapability, a as CameraSwitchIdSchema, c as HvacModeSchema, f as addonRoutesCapability, ft as BaseAddon, i as COCO_TO_MACRO, l as MediaPlayerRepeatSchema, s as FanDirectionSchema, t as AlarmArmModeSchema, wt as string } from "../dist-DObg5VV6.mjs";
2
2
  import { createHmac, timingSafeEqual } from "node:crypto";
3
3
  //#region src/ha-export/topics.ts
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homeassistant",
3
- "version": "1.2.33",
3
+ "version": "1.2.35",
4
4
  "description": "Home Assistant device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",