@camstack/addon-pipeline 1.2.90 → 1.2.94

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 (30) hide show
  1. package/dist/{addon-utils-yc-chXuC.js → addon-utils-DnUCCZVx.js} +1 -1
  2. package/dist/audio-analyzer/index.js +2 -2
  3. package/dist/audio-analyzer/index.mjs +1 -1
  4. package/dist/detection-pipeline/index.js +4 -4
  5. package/dist/detection-pipeline/index.mjs +2 -2
  6. package/dist/{dist-n4Nbnxx5.js → dist-BbRv3bM2.js} +139 -22
  7. package/dist/{dist-BJYwWEZ9.mjs → dist-XbrYiMV3.mjs} +134 -23
  8. package/dist/{event-loop-stall-monitor-BiPffk0D.mjs → event-loop-stall-monitor-CFWrOZ6G.mjs} +1 -1
  9. package/dist/{event-loop-stall-monitor-DG7QY00k.js → event-loop-stall-monitor-D9hqbc68.js} +1 -1
  10. package/dist/{lazy-sharp-EoSOHgoj.js → lazy-sharp-U0EtN7_C.js} +1 -1
  11. package/dist/motion-wasm/index.js +2 -2
  12. package/dist/motion-wasm/index.mjs +1 -1
  13. package/dist/pipeline-runner/index.js +195 -14
  14. package/dist/pipeline-runner/index.mjs +194 -13
  15. package/dist/recorder/index.js +655 -84
  16. package/dist/recorder/index.mjs +654 -83
  17. package/dist/session-decode/decode-worker-child.js +4 -4
  18. package/dist/session-decode/decode-worker-child.mjs +3 -3
  19. package/dist/stream-broker/_stub.js +2 -2
  20. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CsrMZYLB.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BNOPhQ-y.mjs} +2 -2
  21. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DMyOrQHq.mjs +26 -0
  22. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DgivrPsH.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DsIi4G5Q.mjs} +1 -1
  23. package/dist/stream-broker/{hostInit-DoFovQmc.mjs → hostInit-DCV2-mSi.mjs} +2 -2
  24. package/dist/stream-broker/index.js +194 -30
  25. package/dist/stream-broker/index.mjs +194 -30
  26. package/dist/stream-broker/remoteEntry.js +1 -1
  27. package/dist/{worker-protocol-DjuxhGo3.js → worker-protocol-CNC-ZcU3.js} +1 -1
  28. package/dist/{worker-protocol-XZ1e36rM.mjs → worker-protocol-D0ewr67U.mjs} +1 -1
  29. package/package.json +3 -2
  30. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DNSELPGi.mjs +0 -26
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-n4Nbnxx5.js");
1
+ const require_dist = require("./dist-BbRv3bM2.js");
2
2
  require("node:crypto");
3
3
  let node_path = require("node:path");
4
4
  node_path = require_dist.__toESM(node_path, 1);
@@ -2,9 +2,9 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-n4Nbnxx5.js");
5
+ const require_dist = require("../dist-BbRv3bM2.js");
6
6
  const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
7
- const require_addon_utils = require("../addon-utils-yc-chXuC.js");
7
+ const require_addon_utils = require("../addon-utils-DnUCCZVx.js");
8
8
  let node_path = require("node:path");
9
9
  node_path = require_dist.__toESM(node_path);
10
10
  let node_fs = require("node:fs");
@@ -1,5 +1,5 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { D as audioAnalyzerCapability, E as audioAnalysisCapability, U as mapAudioLabelToMacro, h as HF_BASE_URL, ht as hydrateSchema, it as errMsg, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG, ut as BaseAddon } from "../dist-BJYwWEZ9.mjs";
2
+ import { D as audioAnalyzerCapability, E as audioAnalysisCapability, U as mapAudioLabelToMacro, at as errMsg, dt as BaseAddon, gt as hydrateSchema, h as HF_BASE_URL, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG } from "../dist-XbrYiMV3.mjs";
3
3
  import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
4
4
  import { i as downloadFile } from "../addon-utils-A2S9D7pu.mjs";
5
5
  import * as path$1 from "node:path";
@@ -2,11 +2,11 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-n4Nbnxx5.js");
6
- const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DG7QY00k.js");
7
- const require_lazy_sharp = require("../lazy-sharp-EoSOHgoj.js");
5
+ const require_dist = require("../dist-BbRv3bM2.js");
6
+ const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-D9hqbc68.js");
7
+ const require_lazy_sharp = require("../lazy-sharp-U0EtN7_C.js");
8
8
  const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
9
- const require_addon_utils = require("../addon-utils-yc-chXuC.js");
9
+ const require_addon_utils = require("../addon-utils-DnUCCZVx.js");
10
10
  let sharp = require("sharp");
11
11
  sharp = require_dist.__toESM(sharp);
12
12
  let node_child_process = require("node:child_process");
@@ -1,6 +1,6 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $ as runtimeDevices$1, B as enumerateInferenceDevices, Ct as sleep, Ft as EventCategory, J as pipelineExecutorCapability, L as detectionPipelineCapability, M as defaultDeviceFor$1, Nt as string, Pt as union, Tt as array, V as evaluateZoneRules, bt as parseJsonUnknown, d as DEVICE_BACKEND_TO_FORMAT, ht as hydrateSchema, it as errMsg, jt as object, mt as createEvent, nt as supportedRuntimes$1, t as APPLE_SA_TO_MACRO, ut as BaseAddon, w as YAMNET_TO_MACRO, yt as nodePin } from "../dist-BJYwWEZ9.mjs";
3
- import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, n as startEventLoopStallMonitor, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep } from "../event-loop-stall-monitor-BiPffk0D.mjs";
2
+ import { B as enumerateInferenceDevices, Et as array, Ft as union, It as EventCategory, J as pipelineExecutorCapability, L as detectionPipelineCapability, M as defaultDeviceFor$1, Mt as object, Pt as string, V as evaluateZoneRules, at as errMsg, bt as nodePin, d as DEVICE_BACKEND_TO_FORMAT, dt as BaseAddon, et as runtimeDevices$1, gt as hydrateSchema, ht as createEvent, rt as supportedRuntimes$1, t as APPLE_SA_TO_MACRO, w as YAMNET_TO_MACRO, wt as sleep, xt as parseJsonUnknown } from "../dist-XbrYiMV3.mjs";
3
+ import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, n as startEventLoopStallMonitor, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep } from "../event-loop-stall-monitor-CFWrOZ6G.mjs";
4
4
  import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
5
5
  import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
6
6
  import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../addon-utils-A2S9D7pu.mjs";
@@ -8608,6 +8608,12 @@ var RecordingConfigSchema = object({
8608
8608
  /** DERIVED summary of `bands`, stamped by the recorder on every save.
8609
8609
  * Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
8610
8610
  mode: RecordingStorageModeSchema.optional(),
8611
+ /**
8612
+ * Which assigned broker slots to record. Absent / empty = {@link
8613
+ * DEFAULT_RECORDING_PROFILES} (`high`+`low`) intersected with the
8614
+ * camera's currently assigned slots — never `mid` unless the operator
8615
+ * picks it, and never a slot the broker has not assigned.
8616
+ */
8611
8617
  profiles: array(CamProfileSchema).optional(),
8612
8618
  segmentSeconds: number().int().positive().optional(),
8613
8619
  /**
@@ -8632,7 +8638,7 @@ var RecordingConfigSchema = object({
8632
8638
  *
8633
8639
  * THE one definition: the recorder stamps `config.mode` with it on save and
8634
8640
  * reports it as the cap's `activeMode`, and the settings UI reads it back to
8635
- * decide which authoring tab a config opens in. Two copies would drift, and the
8641
+ * highlight the Off/Events/Continuous shortcut. Two copies would drift, and the
8636
8642
  * symptom (a status dot disagreeing with what is being recorded) is exactly the
8637
8643
  * bug this field was added to fix.
8638
8644
  */
@@ -8642,6 +8648,30 @@ function deriveRecordingMode(config) {
8642
8648
  return "events";
8643
8649
  }
8644
8650
  /**
8651
+ * Default recorded slots when a config omits `profiles`: high + low.
8652
+ * `mid` is opt-in — it is usually a second native encode the operator
8653
+ * did not ask to store twice.
8654
+ */
8655
+ var DEFAULT_RECORDING_PROFILES = ["high", "low"];
8656
+ /**
8657
+ * Pick which assigned broker slots to record. `assigned` is already the
8658
+ * broker's assigned∩deduped set (see `selectAssignedProfileSlots`).
8659
+ *
8660
+ * An operator `override` DISABLES unselected assigned slots (assigned ∩
8661
+ * selection). A selection matching none of the assigned sources, or an
8662
+ * absent/empty override, falls through: prefer {@link DEFAULT_RECORDING_PROFILES}
8663
+ * among assigned, else every assigned slot (a camera with only `mid`
8664
+ * still records something). Empty assigned → empty result.
8665
+ */
8666
+ function resolveRecordingProfiles(assigned, override) {
8667
+ if (override !== void 0 && override.length > 0) {
8668
+ const selected = assigned.filter((profile) => override.includes(profile));
8669
+ return selected.length > 0 ? selected : [...assigned];
8670
+ }
8671
+ const preferred = assigned.filter((profile) => DEFAULT_RECORDING_PROFILES.includes(profile));
8672
+ return preferred.length > 0 ? preferred : [...assigned];
8673
+ }
8674
+ /**
8645
8675
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
8646
8676
  *
8647
8677
  * One shape shared by the recorder and pipeline-analytics internal movers.
@@ -8704,7 +8734,11 @@ var RelocateFootageInputSchema = object({
8704
8734
  profiles: array(string()).optional(),
8705
8735
  /** Copy throttle in MB/s (default 40) — the drain is a background chore,
8706
8736
  * never allowed to starve live writers. */
8707
- throttleMbps: number().min(1).max(1e3).optional()
8737
+ throttleMbps: number().min(1).max(1e3).optional(),
8738
+ /** Move only segments whose startMs is >= this. Absent = the whole source
8739
+ * pile. Used when a full drain is too expensive and the operator only
8740
+ * wants the recent window on the new disk. */
8741
+ sinceMs: number().int().optional()
8708
8742
  });
8709
8743
  /** Internal, lease-scoped participant operation. It is intentionally separate
8710
8744
  * from persistent recording settings: a migration never changes
@@ -18633,6 +18667,12 @@ var TrackCascadeCountsSchema = object({
18633
18667
  /** Per-track CLIP search vectors removed (best-effort). */
18634
18668
  embeddings: number().int()
18635
18669
  });
18670
+ /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
18671
+ var DiskReconcileCountsSchema = object({
18672
+ mediaDropped: number().int(),
18673
+ tracks: number().int(),
18674
+ events: number().int()
18675
+ });
18636
18676
  /** Event-store footprint for one camera. */
18637
18677
  var EventStoreDeviceFootprintSchema = object({
18638
18678
  deviceId: number(),
@@ -18809,6 +18849,9 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18809
18849
  }), method(object({ deviceId: number() }), TrackCascadeCountsSchema, {
18810
18850
  kind: "mutation",
18811
18851
  auth: "admin"
18852
+ }), method(object({ deviceId: number() }), DiskReconcileCountsSchema, {
18853
+ kind: "mutation",
18854
+ auth: "admin"
18812
18855
  }), method(object({
18813
18856
  deviceId: number(),
18814
18857
  trackIds: array(string()).min(1)
@@ -20613,6 +20656,24 @@ var CameraStatusDegradationSchema = object({
20613
20656
  *
20614
20657
  * See spec: `docs/superpowers/specs/2026-06-24-camera-status-aggregator-cap.md`
20615
20658
  */
20659
+ var DiskReconcileJobSchema = object({
20660
+ state: _enum([
20661
+ "idle",
20662
+ "running",
20663
+ "done",
20664
+ "error"
20665
+ ]),
20666
+ total: number().int().nonnegative(),
20667
+ completed: number().int().nonnegative(),
20668
+ currentDeviceId: number().int().nullable(),
20669
+ failed: array(number().int()).readonly(),
20670
+ mediaDropped: number().int().nonnegative(),
20671
+ tracks: number().int().nonnegative(),
20672
+ events: number().int().nonnegative(),
20673
+ startedAtMs: number().int().nullable(),
20674
+ finishedAtMs: number().int().nullable(),
20675
+ error: string().nullable()
20676
+ });
20616
20677
  var CameraStatusSchema = object({
20617
20678
  deviceId: number(),
20618
20679
  assignment: CameraAssignmentStatusSchema,
@@ -20844,7 +20905,10 @@ method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
20844
20905
  }), CameraSwitchGroupSchema, {
20845
20906
  kind: "mutation",
20846
20907
  auth: "admin"
20847
- }), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
20908
+ }), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), DiskReconcileJobSchema, {
20909
+ kind: "mutation",
20910
+ auth: "admin"
20911
+ }), method(_void(), DiskReconcileJobSchema, { auth: "admin" }), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
20848
20912
  name: string(),
20849
20913
  description: string().optional(),
20850
20914
  config: CameraPipelineConfigSchema
@@ -21932,20 +21996,6 @@ var VectorStatsResultSchema = object({
21932
21996
  exact: boolean()
21933
21997
  });
21934
21998
  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);
21935
- /**
21936
- * `videoclips` — the unified, navigable-clip surface for a camera.
21937
- *
21938
- * A device-scoped WRAPPER cap (like `pipeline-analytics`): exactly one active
21939
- * provider per device, substitutable. The DEFAULT provider (registered by
21940
- * `addon-post-analysis`, `defaultActive: true`) composes the analytics event
21941
- * log (markers + thumbnails) with the recorder's `getPlaybackManifest` — a clip
21942
- * is a time-WINDOW over existing footage, never a separate file. A camera that
21943
- * exposes NATIVE onboard clips (Reolink/Hikvision NVR) can later substitute the
21944
- * wrapper provider for its device and serve its own clip catalog + URLs.
21945
- *
21946
- * A `Clip` is purely time-based (subtree-blind): playback resolves segments by
21947
- * temporal overlap, so the API never decides `continuous` vs `events`.
21948
- */
21949
21999
  var ClipSchema = object({
21950
22000
  /** Opaque, provider-namespaced id. The default provider encodes the time
21951
22001
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -21971,12 +22021,41 @@ var ClipSchema = object({
21971
22021
  * of the event that owns `kind` (object > motion > audio). Do not extract
21972
22022
  * a keyframe from the recorded segments. Other providers (onboard, HKSV)
21973
22023
  * mint their own stills.
22024
+ *
22025
+ * **VOUCHED, never fabricated.** A provider emits this only for an event it
22026
+ * has CONFIRMED owns at least one media row (its own, or its owning track's).
22027
+ * Absent is meaningful — "this visit has no event still" — never "we did not
22028
+ * look". Stamping it from a URL template made 35% of one camera's clips point
22029
+ * at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
22030
+ * A read that FAILS drops the claim; it never invents it.
21974
22031
  */
21975
22032
  thumbnail: string().optional(),
21976
- /** Analytics event ids that overlap this visit. Empty on footage-only clips.
21977
- * The default provider's visit grain puts many motion heartbeats on one clip
21978
- * instead of minting one clip per marker. */
22033
+ /**
22034
+ * An instant INSIDE this visit's footage, hole-safe, where a recorded still
22035
+ * can be decoded. Present whenever the visit came from recorded availability;
22036
+ * absent on a per-event padded window (there is no footage to promise).
22037
+ *
22038
+ * This is not a thumbnail and not a second byte path: it is the argument to
22039
+ * the recorder's existing still route. The surface — never the provider —
22040
+ * decides whether to use it. It is the midpoint of the visit's LONGEST
22041
+ * contiguous range, not of the visit: a visit spans its holes by
22042
+ * construction, so a naive midpoint lands in dead air.
22043
+ */
22044
+ stillAtMs: number().optional(),
22045
+ /**
22046
+ * Analytics event ids that overlap this visit — a BOUNDED sample, newest
22047
+ * first within kind (object → motion → audio), capped at
22048
+ * {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
22049
+ *
22050
+ * Bounded because it is not a payload the surface pages through: one visit on
22051
+ * device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
22052
+ * camera-day. Read {@link eventCount} for the true total.
22053
+ */
21979
22054
  eventIds: array(string()).optional(),
22055
+ /** How many analytics events actually overlap this visit. Differs from
22056
+ * `eventIds.length` exactly when the sample was capped — so a truncated
22057
+ * list is never mistaken for a quiet visit. */
22058
+ eventCount: number().int().nonnegative().optional(),
21980
22059
  /** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
21981
22060
  * than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
21982
22061
  * bar keeps showing them via `recording.getAvailability`. */
@@ -22527,7 +22606,14 @@ var SearchResultSchema = object({
22527
22606
  });
22528
22607
  var AutoUpdateSettingsSchema = object({
22529
22608
  channel: ChannelSchema,
22530
- intervalSeconds: number()
22609
+ intervalSeconds: number(),
22610
+ /**
22611
+ * Cadence of the "an update exists" POLLER, in seconds. Independent of
22612
+ * `channel`: the poller runs while auto-apply is `off`, because being told
22613
+ * about a publish and installing it are different decisions. Clamped
22614
+ * server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
22615
+ */
22616
+ updateCheckIntervalSeconds: number()
22531
22617
  });
22532
22618
  var AddonAutoUpdateSchema = ChannelWithInheritSchema;
22533
22619
  var RestartAddonResultSchema = unknown();
@@ -22668,7 +22754,9 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
22668
22754
  auth: "admin"
22669
22755
  }), method(_void(), AutoUpdateSettingsSchema, { auth: "admin" }), method(object({
22670
22756
  channel: ChannelSchema,
22671
- intervalSeconds: number().min(300).max(86400).optional()
22757
+ intervalSeconds: number().min(300).max(86400).optional(),
22758
+ /** Availability-poll cadence; see AutoUpdateSettingsSchema. */
22759
+ updateCheckIntervalSeconds: number().min(900).max(604800).optional()
22672
22760
  }), unknown(), {
22673
22761
  kind: "mutation",
22674
22762
  auth: "admin"
@@ -31572,6 +31660,12 @@ Object.freeze({
31572
31660
  addonId: null,
31573
31661
  access: "create"
31574
31662
  },
31663
+ "pipelineAnalytics.reconcileFromDisk": {
31664
+ capName: "pipeline-analytics",
31665
+ capScope: "device",
31666
+ addonId: null,
31667
+ access: "create"
31668
+ },
31575
31669
  "pipelineAnalytics.refreshStorageLocationsForMigration": {
31576
31670
  capName: "pipeline-analytics",
31577
31671
  capScope: "device",
@@ -31974,6 +32068,12 @@ Object.freeze({
31974
32068
  addonId: null,
31975
32069
  access: "view"
31976
32070
  },
32071
+ "pipelineOrchestrator.getReconcileFromDiskStatus": {
32072
+ capName: "pipeline-orchestrator",
32073
+ capScope: "system",
32074
+ addonId: null,
32075
+ access: "view"
32076
+ },
31977
32077
  "pipelineOrchestrator.listAgentSettings": {
31978
32078
  capName: "pipeline-orchestrator",
31979
32079
  capScope: "system",
@@ -31998,6 +32098,12 @@ Object.freeze({
31998
32098
  addonId: null,
31999
32099
  access: "create"
32000
32100
  },
32101
+ "pipelineOrchestrator.reconcileFromDisk": {
32102
+ capName: "pipeline-orchestrator",
32103
+ capScope: "system",
32104
+ addonId: null,
32105
+ access: "create"
32106
+ },
32001
32107
  "pipelineOrchestrator.removeAgentSettings": {
32002
32108
  capName: "pipeline-orchestrator",
32003
32109
  capScope: "system",
@@ -34989,6 +35095,11 @@ Object.freeze({
34989
35095
  form: "single",
34990
35096
  optional: true
34991
35097
  }],
35098
+ "pipelineAnalytics.reconcileFromDisk": [{
35099
+ name: "deviceId",
35100
+ form: "single",
35101
+ optional: false
35102
+ }],
34992
35103
  "pipelineAnalytics.restageRetrainTrack": [{
34993
35104
  name: "deviceId",
34994
35105
  form: "single",
@@ -37166,6 +37277,12 @@ Object.defineProperty(exports, "resolveEgressDecodeHwAccel", {
37166
37277
  return resolveEgressDecodeHwAccel;
37167
37278
  }
37168
37279
  });
37280
+ Object.defineProperty(exports, "resolveRecordingProfiles", {
37281
+ enumerable: true,
37282
+ get: function() {
37283
+ return resolveRecordingProfiles;
37284
+ }
37285
+ });
37169
37286
  Object.defineProperty(exports, "runtimeDevices", {
37170
37287
  enumerable: true,
37171
37288
  get: function() {
@@ -8585,6 +8585,12 @@ var RecordingConfigSchema = object({
8585
8585
  /** DERIVED summary of `bands`, stamped by the recorder on every save.
8586
8586
  * Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
8587
8587
  mode: RecordingStorageModeSchema.optional(),
8588
+ /**
8589
+ * Which assigned broker slots to record. Absent / empty = {@link
8590
+ * DEFAULT_RECORDING_PROFILES} (`high`+`low`) intersected with the
8591
+ * camera's currently assigned slots — never `mid` unless the operator
8592
+ * picks it, and never a slot the broker has not assigned.
8593
+ */
8588
8594
  profiles: array(CamProfileSchema).optional(),
8589
8595
  segmentSeconds: number().int().positive().optional(),
8590
8596
  /**
@@ -8609,7 +8615,7 @@ var RecordingConfigSchema = object({
8609
8615
  *
8610
8616
  * THE one definition: the recorder stamps `config.mode` with it on save and
8611
8617
  * reports it as the cap's `activeMode`, and the settings UI reads it back to
8612
- * decide which authoring tab a config opens in. Two copies would drift, and the
8618
+ * highlight the Off/Events/Continuous shortcut. Two copies would drift, and the
8613
8619
  * symptom (a status dot disagreeing with what is being recorded) is exactly the
8614
8620
  * bug this field was added to fix.
8615
8621
  */
@@ -8619,6 +8625,30 @@ function deriveRecordingMode(config) {
8619
8625
  return "events";
8620
8626
  }
8621
8627
  /**
8628
+ * Default recorded slots when a config omits `profiles`: high + low.
8629
+ * `mid` is opt-in — it is usually a second native encode the operator
8630
+ * did not ask to store twice.
8631
+ */
8632
+ var DEFAULT_RECORDING_PROFILES = ["high", "low"];
8633
+ /**
8634
+ * Pick which assigned broker slots to record. `assigned` is already the
8635
+ * broker's assigned∩deduped set (see `selectAssignedProfileSlots`).
8636
+ *
8637
+ * An operator `override` DISABLES unselected assigned slots (assigned ∩
8638
+ * selection). A selection matching none of the assigned sources, or an
8639
+ * absent/empty override, falls through: prefer {@link DEFAULT_RECORDING_PROFILES}
8640
+ * among assigned, else every assigned slot (a camera with only `mid`
8641
+ * still records something). Empty assigned → empty result.
8642
+ */
8643
+ function resolveRecordingProfiles(assigned, override) {
8644
+ if (override !== void 0 && override.length > 0) {
8645
+ const selected = assigned.filter((profile) => override.includes(profile));
8646
+ return selected.length > 0 ? selected : [...assigned];
8647
+ }
8648
+ const preferred = assigned.filter((profile) => DEFAULT_RECORDING_PROFILES.includes(profile));
8649
+ return preferred.length > 0 ? preferred : [...assigned];
8650
+ }
8651
+ /**
8622
8652
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
8623
8653
  *
8624
8654
  * One shape shared by the recorder and pipeline-analytics internal movers.
@@ -8681,7 +8711,11 @@ var RelocateFootageInputSchema = object({
8681
8711
  profiles: array(string()).optional(),
8682
8712
  /** Copy throttle in MB/s (default 40) — the drain is a background chore,
8683
8713
  * never allowed to starve live writers. */
8684
- throttleMbps: number().min(1).max(1e3).optional()
8714
+ throttleMbps: number().min(1).max(1e3).optional(),
8715
+ /** Move only segments whose startMs is >= this. Absent = the whole source
8716
+ * pile. Used when a full drain is too expensive and the operator only
8717
+ * wants the recent window on the new disk. */
8718
+ sinceMs: number().int().optional()
8685
8719
  });
8686
8720
  /** Internal, lease-scoped participant operation. It is intentionally separate
8687
8721
  * from persistent recording settings: a migration never changes
@@ -18610,6 +18644,12 @@ var TrackCascadeCountsSchema = object({
18610
18644
  /** Per-track CLIP search vectors removed (best-effort). */
18611
18645
  embeddings: number().int()
18612
18646
  });
18647
+ /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
18648
+ var DiskReconcileCountsSchema = object({
18649
+ mediaDropped: number().int(),
18650
+ tracks: number().int(),
18651
+ events: number().int()
18652
+ });
18613
18653
  /** Event-store footprint for one camera. */
18614
18654
  var EventStoreDeviceFootprintSchema = object({
18615
18655
  deviceId: number(),
@@ -18786,6 +18826,9 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18786
18826
  }), method(object({ deviceId: number() }), TrackCascadeCountsSchema, {
18787
18827
  kind: "mutation",
18788
18828
  auth: "admin"
18829
+ }), method(object({ deviceId: number() }), DiskReconcileCountsSchema, {
18830
+ kind: "mutation",
18831
+ auth: "admin"
18789
18832
  }), method(object({
18790
18833
  deviceId: number(),
18791
18834
  trackIds: array(string()).min(1)
@@ -20590,6 +20633,24 @@ var CameraStatusDegradationSchema = object({
20590
20633
  *
20591
20634
  * See spec: `docs/superpowers/specs/2026-06-24-camera-status-aggregator-cap.md`
20592
20635
  */
20636
+ var DiskReconcileJobSchema = object({
20637
+ state: _enum([
20638
+ "idle",
20639
+ "running",
20640
+ "done",
20641
+ "error"
20642
+ ]),
20643
+ total: number().int().nonnegative(),
20644
+ completed: number().int().nonnegative(),
20645
+ currentDeviceId: number().int().nullable(),
20646
+ failed: array(number().int()).readonly(),
20647
+ mediaDropped: number().int().nonnegative(),
20648
+ tracks: number().int().nonnegative(),
20649
+ events: number().int().nonnegative(),
20650
+ startedAtMs: number().int().nullable(),
20651
+ finishedAtMs: number().int().nullable(),
20652
+ error: string().nullable()
20653
+ });
20593
20654
  var CameraStatusSchema = object({
20594
20655
  deviceId: number(),
20595
20656
  assignment: CameraAssignmentStatusSchema,
@@ -20821,7 +20882,10 @@ method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
20821
20882
  }), CameraSwitchGroupSchema, {
20822
20883
  kind: "mutation",
20823
20884
  auth: "admin"
20824
- }), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
20885
+ }), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), DiskReconcileJobSchema, {
20886
+ kind: "mutation",
20887
+ auth: "admin"
20888
+ }), method(_void(), DiskReconcileJobSchema, { auth: "admin" }), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
20825
20889
  name: string(),
20826
20890
  description: string().optional(),
20827
20891
  config: CameraPipelineConfigSchema
@@ -21909,20 +21973,6 @@ var VectorStatsResultSchema = object({
21909
21973
  exact: boolean()
21910
21974
  });
21911
21975
  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);
21912
- /**
21913
- * `videoclips` — the unified, navigable-clip surface for a camera.
21914
- *
21915
- * A device-scoped WRAPPER cap (like `pipeline-analytics`): exactly one active
21916
- * provider per device, substitutable. The DEFAULT provider (registered by
21917
- * `addon-post-analysis`, `defaultActive: true`) composes the analytics event
21918
- * log (markers + thumbnails) with the recorder's `getPlaybackManifest` — a clip
21919
- * is a time-WINDOW over existing footage, never a separate file. A camera that
21920
- * exposes NATIVE onboard clips (Reolink/Hikvision NVR) can later substitute the
21921
- * wrapper provider for its device and serve its own clip catalog + URLs.
21922
- *
21923
- * A `Clip` is purely time-based (subtree-blind): playback resolves segments by
21924
- * temporal overlap, so the API never decides `continuous` vs `events`.
21925
- */
21926
21976
  var ClipSchema = object({
21927
21977
  /** Opaque, provider-namespaced id. The default provider encodes the time
21928
21978
  * window so `getClipPlayback` is self-contained (no event re-query). */
@@ -21948,12 +21998,41 @@ var ClipSchema = object({
21948
21998
  * of the event that owns `kind` (object > motion > audio). Do not extract
21949
21999
  * a keyframe from the recorded segments. Other providers (onboard, HKSV)
21950
22000
  * mint their own stills.
22001
+ *
22002
+ * **VOUCHED, never fabricated.** A provider emits this only for an event it
22003
+ * has CONFIRMED owns at least one media row (its own, or its owning track's).
22004
+ * Absent is meaningful — "this visit has no event still" — never "we did not
22005
+ * look". Stamping it from a URL template made 35% of one camera's clips point
22006
+ * at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
22007
+ * A read that FAILS drops the claim; it never invents it.
21951
22008
  */
21952
22009
  thumbnail: string().optional(),
21953
- /** Analytics event ids that overlap this visit. Empty on footage-only clips.
21954
- * The default provider's visit grain puts many motion heartbeats on one clip
21955
- * instead of minting one clip per marker. */
22010
+ /**
22011
+ * An instant INSIDE this visit's footage, hole-safe, where a recorded still
22012
+ * can be decoded. Present whenever the visit came from recorded availability;
22013
+ * absent on a per-event padded window (there is no footage to promise).
22014
+ *
22015
+ * This is not a thumbnail and not a second byte path: it is the argument to
22016
+ * the recorder's existing still route. The surface — never the provider —
22017
+ * decides whether to use it. It is the midpoint of the visit's LONGEST
22018
+ * contiguous range, not of the visit: a visit spans its holes by
22019
+ * construction, so a naive midpoint lands in dead air.
22020
+ */
22021
+ stillAtMs: number().optional(),
22022
+ /**
22023
+ * Analytics event ids that overlap this visit — a BOUNDED sample, newest
22024
+ * first within kind (object → motion → audio), capped at
22025
+ * {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
22026
+ *
22027
+ * Bounded because it is not a payload the surface pages through: one visit on
22028
+ * device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
22029
+ * camera-day. Read {@link eventCount} for the true total.
22030
+ */
21956
22031
  eventIds: array(string()).optional(),
22032
+ /** How many analytics events actually overlap this visit. Differs from
22033
+ * `eventIds.length` exactly when the sample was capped — so a truncated
22034
+ * list is never mistaken for a quiet visit. */
22035
+ eventCount: number().int().nonnegative().optional(),
21957
22036
  /** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
21958
22037
  * than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
21959
22038
  * bar keeps showing them via `recording.getAvailability`. */
@@ -22504,7 +22583,14 @@ var SearchResultSchema = object({
22504
22583
  });
22505
22584
  var AutoUpdateSettingsSchema = object({
22506
22585
  channel: ChannelSchema,
22507
- intervalSeconds: number()
22586
+ intervalSeconds: number(),
22587
+ /**
22588
+ * Cadence of the "an update exists" POLLER, in seconds. Independent of
22589
+ * `channel`: the poller runs while auto-apply is `off`, because being told
22590
+ * about a publish and installing it are different decisions. Clamped
22591
+ * server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
22592
+ */
22593
+ updateCheckIntervalSeconds: number()
22508
22594
  });
22509
22595
  var AddonAutoUpdateSchema = ChannelWithInheritSchema;
22510
22596
  var RestartAddonResultSchema = unknown();
@@ -22645,7 +22731,9 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
22645
22731
  auth: "admin"
22646
22732
  }), method(_void(), AutoUpdateSettingsSchema, { auth: "admin" }), method(object({
22647
22733
  channel: ChannelSchema,
22648
- intervalSeconds: number().min(300).max(86400).optional()
22734
+ intervalSeconds: number().min(300).max(86400).optional(),
22735
+ /** Availability-poll cadence; see AutoUpdateSettingsSchema. */
22736
+ updateCheckIntervalSeconds: number().min(900).max(604800).optional()
22649
22737
  }), unknown(), {
22650
22738
  kind: "mutation",
22651
22739
  auth: "admin"
@@ -31549,6 +31637,12 @@ Object.freeze({
31549
31637
  addonId: null,
31550
31638
  access: "create"
31551
31639
  },
31640
+ "pipelineAnalytics.reconcileFromDisk": {
31641
+ capName: "pipeline-analytics",
31642
+ capScope: "device",
31643
+ addonId: null,
31644
+ access: "create"
31645
+ },
31552
31646
  "pipelineAnalytics.refreshStorageLocationsForMigration": {
31553
31647
  capName: "pipeline-analytics",
31554
31648
  capScope: "device",
@@ -31951,6 +32045,12 @@ Object.freeze({
31951
32045
  addonId: null,
31952
32046
  access: "view"
31953
32047
  },
32048
+ "pipelineOrchestrator.getReconcileFromDiskStatus": {
32049
+ capName: "pipeline-orchestrator",
32050
+ capScope: "system",
32051
+ addonId: null,
32052
+ access: "view"
32053
+ },
31954
32054
  "pipelineOrchestrator.listAgentSettings": {
31955
32055
  capName: "pipeline-orchestrator",
31956
32056
  capScope: "system",
@@ -31975,6 +32075,12 @@ Object.freeze({
31975
32075
  addonId: null,
31976
32076
  access: "create"
31977
32077
  },
32078
+ "pipelineOrchestrator.reconcileFromDisk": {
32079
+ capName: "pipeline-orchestrator",
32080
+ capScope: "system",
32081
+ addonId: null,
32082
+ access: "create"
32083
+ },
31978
32084
  "pipelineOrchestrator.removeAgentSettings": {
31979
32085
  capName: "pipeline-orchestrator",
31980
32086
  capScope: "system",
@@ -34966,6 +35072,11 @@ Object.freeze({
34966
35072
  form: "single",
34967
35073
  optional: true
34968
35074
  }],
35075
+ "pipelineAnalytics.reconcileFromDisk": [{
35076
+ name: "deviceId",
35077
+ form: "single",
35078
+ optional: false
35079
+ }],
34969
35080
  "pipelineAnalytics.restageRetrainTrack": [{
34970
35081
  name: "deviceId",
34971
35082
  form: "single",
@@ -36651,4 +36762,4 @@ function enumerateInferenceDevices(hw) {
36651
36762
  return out;
36652
36763
  }
36653
36764
  //#endregion
36654
- export { runtimeDevices as $, createHwAccelCache as A, number as At, enumerateInferenceDevices as B, RingBuffer as C, sleep as Ct, audioAnalyzerCapability as D, discriminatedUnion as Dt, audioAnalysisCapability as E, boolean as Et, deriveDetailCropRect as F, EventCategory as Ft, motionDetectionCapability as G, hfModelUrl as H, deriveRecordingMode as I, pipelineExecutorCapability as J, pickDetailCropConvention as K, detectionPipelineCapability as L, defaultDeviceFor as M, record as Mt, defineCustomActions as N, string as Nt, batteryCapability as O, lazy as Ot, deriveBatteryPresence as P, union as Pt, resolveEgressDecodeHwAccel as Q, egressTranscodeSharingKey as R, RecordingConfigSchema as S, selectAssignedProfileSlots as St, addonWidgetsSourceCapability as T, array as Tt, mapAudioLabelToMacro as U, evaluateZoneRules as V, maskUrlCredentials as W, recordingCapability as X, pipelineRunnerCapability as Y, recordingExportCapability as Z, NativeLeaseSettingsSchema as _, makeProfileBrokerId as _t, COCO_80_LABELS as a, AUDIO_PRESETS as at, RATE_CONTROL_TIGHT as b, parseJsonUnknown as bt, DEFAULT_DETAIL_CROP_CONVENTION as c, invocationFromEncodeProfile as ct, DEVICE_BACKEND_TO_FORMAT as d, CAM_PROFILE_ORDER as dt, storageEvictableCapability as et, EVENT_PAD_MS as f, DeviceFeature as ft, NativeLeaseAdmissionSchema as g, isEvent as gt, HF_BASE_URL as h, hydrateSchema as ht, BatteryStatusSchema as i, errMsg as it, customAction as j, object as jt, cameraStreamsCapability as k, literal as kt, DEFAULT_EVENTS_BAND_BUFFER_SEC as l, isSoftwareDecode as lt, ExportRecordSchema as m, createEvent as mt, AUDIO_BACKEND_CHOICES as n, supportedRuntimes as nt, COCO_TO_MACRO as o, Fmp4BoxSplitter as ot, EncodeProfileSchema as p, DeviceType as pt, pickNativeLeaseOverride as q, AUDIO_MACRO_LABELS as r, webrtcSessionCapability as rt, DEFAULT_AUDIO_ANALYZER_CONFIG as s, buildFfmpegArgs as st, APPLE_SA_TO_MACRO as t, streamBrokerCapability as tt, DEFAULT_NATIVE_LEASE_SETTINGS as u, BaseAddon as ut, OpsLogEntrySchema as v, makeSourceBrokerId as vt, YAMNET_TO_MACRO as w, _enum as wt, RECORDING_EXPORT_MAX_READ_BYTES as x, parseProfileBrokerId as xt, RATE_CONTROL_RELAXED as y, nodePin as yt, egressTransportFromRequest as z };
36765
+ export { resolveRecordingProfiles as $, createHwAccelCache as A, literal as At, enumerateInferenceDevices as B, RingBuffer as C, selectAssignedProfileSlots as Ct, audioAnalyzerCapability as D, boolean as Dt, audioAnalysisCapability as E, array as Et, deriveDetailCropRect as F, union as Ft, motionDetectionCapability as G, hfModelUrl as H, deriveRecordingMode as I, EventCategory as It, pipelineExecutorCapability as J, pickDetailCropConvention as K, detectionPipelineCapability as L, defaultDeviceFor as M, object as Mt, defineCustomActions as N, record as Nt, batteryCapability as O, discriminatedUnion as Ot, deriveBatteryPresence as P, string as Pt, resolveEgressDecodeHwAccel as Q, egressTranscodeSharingKey as R, RecordingConfigSchema as S, parseProfileBrokerId as St, addonWidgetsSourceCapability as T, _enum as Tt, mapAudioLabelToMacro as U, evaluateZoneRules as V, maskUrlCredentials as W, recordingCapability as X, pipelineRunnerCapability as Y, recordingExportCapability as Z, NativeLeaseSettingsSchema as _, isEvent as _t, COCO_80_LABELS as a, errMsg as at, RATE_CONTROL_TIGHT as b, nodePin as bt, DEFAULT_DETAIL_CROP_CONVENTION as c, buildFfmpegArgs as ct, DEVICE_BACKEND_TO_FORMAT as d, BaseAddon as dt, runtimeDevices as et, EVENT_PAD_MS as f, CAM_PROFILE_ORDER as ft, NativeLeaseAdmissionSchema as g, hydrateSchema as gt, HF_BASE_URL as h, createEvent as ht, BatteryStatusSchema as i, webrtcSessionCapability as it, customAction as j, number as jt, cameraStreamsCapability as k, lazy as kt, DEFAULT_EVENTS_BAND_BUFFER_SEC as l, invocationFromEncodeProfile as lt, ExportRecordSchema as m, DeviceType as mt, AUDIO_BACKEND_CHOICES as n, streamBrokerCapability as nt, COCO_TO_MACRO as o, AUDIO_PRESETS as ot, EncodeProfileSchema as p, DeviceFeature as pt, pickNativeLeaseOverride as q, AUDIO_MACRO_LABELS as r, supportedRuntimes as rt, DEFAULT_AUDIO_ANALYZER_CONFIG as s, Fmp4BoxSplitter as st, APPLE_SA_TO_MACRO as t, storageEvictableCapability as tt, DEFAULT_NATIVE_LEASE_SETTINGS as u, isSoftwareDecode as ut, OpsLogEntrySchema as v, makeProfileBrokerId as vt, YAMNET_TO_MACRO as w, sleep as wt, RECORDING_EXPORT_MAX_READ_BYTES as x, parseJsonUnknown as xt, RATE_CONTROL_RELAXED as y, makeSourceBrokerId as yt, egressTransportFromRequest as z };
@@ -1,4 +1,4 @@
1
- import { H as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-BJYwWEZ9.mjs";
1
+ import { H as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-XbrYiMV3.mjs";
2
2
  import { PerformanceObserver } from "node:perf_hooks";
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-n4Nbnxx5.js");
1
+ const require_dist = require("./dist-BbRv3bM2.js");
2
2
  let node_perf_hooks = require("node:perf_hooks");
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-n4Nbnxx5.js");
1
+ const require_dist = require("./dist-BbRv3bM2.js");
2
2
  let node_url = require("node:url");
3
3
  let node_module = require("node:module");
4
4
  let node_path = require("node:path");
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-n4Nbnxx5.js");
6
- const require_lazy_sharp = require("../lazy-sharp-EoSOHgoj.js");
5
+ const require_dist = require("../dist-BbRv3bM2.js");
6
+ const require_lazy_sharp = require("../lazy-sharp-U0EtN7_C.js");
7
7
  let node_path = require("node:path");
8
8
  let node_fs = require("node:fs");
9
9
  //#region src/motion-wasm/wasm-motion-detector.ts
@@ -1,4 +1,4 @@
1
- import { G as motionDetectionCapability, V as evaluateZoneRules, ht as hydrateSchema, pt as DeviceType, ut as BaseAddon } from "../dist-BJYwWEZ9.mjs";
1
+ import { G as motionDetectionCapability, V as evaluateZoneRules, dt as BaseAddon, gt as hydrateSchema, mt as DeviceType } from "../dist-XbrYiMV3.mjs";
2
2
  import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
3
3
  import { join } from "node:path";
4
4
  import { readFileSync } from "node:fs";