@camstack/addon-post-analysis 1.2.169 → 1.2.171

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.
@@ -20213,7 +20213,20 @@ var RecentTracksQueryInput = object({
20213
20213
  projection: TrackProjectionSchema.optional(),
20214
20214
  /** Include stationary-promoted rows (parked objects). Default false: the
20215
20215
  * feed lists passages; parking records live on the stationary registry. */
20216
- includeStationary: boolean().optional()
20216
+ includeStationary: boolean().optional(),
20217
+ /**
20218
+ * Restrict to these track classes. ABSENT or EMPTY means no filter.
20219
+ *
20220
+ * The same filter `listTracks` takes, because the timeline's class chips must
20221
+ * mean the same thing whether the scope is one camera or twelve. Until this
20222
+ * existed the scoped feed downloaded a page and narrowed it on the phone
20223
+ * while the single-camera path narrowed the read — one filter, two costs.
20224
+ *
20225
+ * A SUPERSET prefilter on `classes[]`, like its single-camera twin: rows
20226
+ * whose class list is unreadable are kept, and the client's rule stays the
20227
+ * exact one.
20228
+ */
20229
+ classes: array(string()).optional()
20217
20230
  });
20218
20231
  var RecentTracksPageSchema = object({
20219
20232
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -20614,7 +20627,21 @@ var pipelineAnalyticsCapability = {
20614
20627
  /** Include stationary-promoted rows (parked objects handed to the
20615
20628
  * stationary registry). Default false: the timeline lists passages,
20616
20629
  * not parking records (operator decision, 2026-08-15). */
20617
- includeStationary: boolean().optional()
20630
+ includeStationary: boolean().optional(),
20631
+ /**
20632
+ * Restrict to these track classes. ABSENT or EMPTY means no filter.
20633
+ *
20634
+ * Added 2026-09-03: the timeline's class chips filtered in the CLIENT,
20635
+ * on a day of rows already downloaded. The zone filter had been moved
20636
+ * here for exactly that reason — and it is also what lets the rows come
20637
+ * back `slim` — but the class filter was left behind, so a narrow
20638
+ * selection was still a wide read followed by a wide discard.
20639
+ *
20640
+ * Empty is "show all", not "nothing matches": a chip row with nothing
20641
+ * selected is an operator who has not narrowed anything, and an empty
20642
+ * timeline would read as a camera that saw nothing.
20643
+ */
20644
+ classes: array(string()).optional()
20618
20645
  }), array(TrackSchema).readonly()),
20619
20646
  /**
20620
20647
  * Batched cluster-wide track listing — ONE call for the events page /
@@ -24950,8 +24977,22 @@ var automationControlCapability = {
24950
24977
  * threshold.
24951
24978
  */
24952
24979
  var BatteryStatusSchema = object({
24953
- /** 0..100 inclusive. Firmware-reported. */
24954
- percentage: number().min(0).max(100),
24980
+ /**
24981
+ * 0..100 inclusive, firmware-reported. **`null` means NOT YET KNOWN** — the
24982
+ * provider has registered the capability but no reading has landed.
24983
+ *
24984
+ * It is nullable because it was not, and the only value a provider could
24985
+ * seed with was `0`. A battery camera behind an NVR therefore announced
24986
+ * itself at 0% on every start and corrected itself a moment later, which is
24987
+ * indistinguishable from a real flat battery: it fires the low-battery alert
24988
+ * every time the hub restarts. Unknown is not empty (D315), and on a battery
24989
+ * reading the difference is an alarm.
24990
+ *
24991
+ * `vacuum-control` and `lawn-mower-control` already model it this way.
24992
+ * Consumers must SKIP a null rather than coerce it — `battery-band` already
24993
+ * declines to band a non-finite reading, which is the correct shape.
24994
+ */
24995
+ percentage: number().min(0).max(100).nullable(),
24955
24996
  /**
24956
24997
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
24957
24998
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -20182,7 +20182,20 @@ var RecentTracksQueryInput = object({
20182
20182
  projection: TrackProjectionSchema.optional(),
20183
20183
  /** Include stationary-promoted rows (parked objects). Default false: the
20184
20184
  * feed lists passages; parking records live on the stationary registry. */
20185
- includeStationary: boolean().optional()
20185
+ includeStationary: boolean().optional(),
20186
+ /**
20187
+ * Restrict to these track classes. ABSENT or EMPTY means no filter.
20188
+ *
20189
+ * The same filter `listTracks` takes, because the timeline's class chips must
20190
+ * mean the same thing whether the scope is one camera or twelve. Until this
20191
+ * existed the scoped feed downloaded a page and narrowed it on the phone
20192
+ * while the single-camera path narrowed the read — one filter, two costs.
20193
+ *
20194
+ * A SUPERSET prefilter on `classes[]`, like its single-camera twin: rows
20195
+ * whose class list is unreadable are kept, and the client's rule stays the
20196
+ * exact one.
20197
+ */
20198
+ classes: array(string()).optional()
20186
20199
  });
20187
20200
  var RecentTracksPageSchema = object({
20188
20201
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -20583,7 +20596,21 @@ var pipelineAnalyticsCapability = {
20583
20596
  /** Include stationary-promoted rows (parked objects handed to the
20584
20597
  * stationary registry). Default false: the timeline lists passages,
20585
20598
  * not parking records (operator decision, 2026-08-15). */
20586
- includeStationary: boolean().optional()
20599
+ includeStationary: boolean().optional(),
20600
+ /**
20601
+ * Restrict to these track classes. ABSENT or EMPTY means no filter.
20602
+ *
20603
+ * Added 2026-09-03: the timeline's class chips filtered in the CLIENT,
20604
+ * on a day of rows already downloaded. The zone filter had been moved
20605
+ * here for exactly that reason — and it is also what lets the rows come
20606
+ * back `slim` — but the class filter was left behind, so a narrow
20607
+ * selection was still a wide read followed by a wide discard.
20608
+ *
20609
+ * Empty is "show all", not "nothing matches": a chip row with nothing
20610
+ * selected is an operator who has not narrowed anything, and an empty
20611
+ * timeline would read as a camera that saw nothing.
20612
+ */
20613
+ classes: array(string()).optional()
20587
20614
  }), array(TrackSchema).readonly()),
20588
20615
  /**
20589
20616
  * Batched cluster-wide track listing — ONE call for the events page /
@@ -24919,8 +24946,22 @@ var automationControlCapability = {
24919
24946
  * threshold.
24920
24947
  */
24921
24948
  var BatteryStatusSchema = object({
24922
- /** 0..100 inclusive. Firmware-reported. */
24923
- percentage: number().min(0).max(100),
24949
+ /**
24950
+ * 0..100 inclusive, firmware-reported. **`null` means NOT YET KNOWN** — the
24951
+ * provider has registered the capability but no reading has landed.
24952
+ *
24953
+ * It is nullable because it was not, and the only value a provider could
24954
+ * seed with was `0`. A battery camera behind an NVR therefore announced
24955
+ * itself at 0% on every start and corrected itself a moment later, which is
24956
+ * indistinguishable from a real flat battery: it fires the low-battery alert
24957
+ * every time the hub restarts. Unknown is not empty (D315), and on a battery
24958
+ * reading the difference is an alarm.
24959
+ *
24960
+ * `vacuum-control` and `lawn-mower-control` already model it this way.
24961
+ * Consumers must SKIP a null rather than coerce it — `battery-band` already
24962
+ * declines to band a non-finite reading, which is the correct shape.
24963
+ */
24964
+ percentage: number().min(0).max(100).nullable(),
24924
24965
  /**
24925
24966
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
24926
24967
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-DQVA7q-T.js");
5
+ const require_dist = require("../dist-0kEjfSjL.js");
6
6
  let node_fs = require("node:fs");
7
7
  node_fs = require_dist.__toESM(node_fs);
8
8
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { At as BaseAddon, F as PoolMemoryWatchdog, St as resolvePoolMemoryPolicy, at as embeddingEncoderCapability, gt as parseProcStatus, ut as hfModelUrl } from "../dist-Cubb8Avj.mjs";
1
+ import { At as BaseAddon, F as PoolMemoryWatchdog, St as resolvePoolMemoryPolicy, at as embeddingEncoderCapability, gt as parseProcStatus, ut as hfModelUrl } from "../dist-DZmz2kP-.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import * as fs from "node:fs";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
3
3
  var e = {
4
4
  "@camstack/sdk": {
5
5
  name: "@camstack/sdk",
6
- version: "1.2.59",
6
+ version: "1.2.61",
7
7
  scope: ["default"],
8
8
  loaded: !1,
9
9
  from: "addon_pipeline_analytics_widgets",
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.139",
21
+ version: "1.2.141",
22
22
  scope: ["default"],
23
23
  loaded: !1,
24
24
  from: "addon_pipeline_analytics_widgets",
@@ -33,7 +33,7 @@ var e = {
33
33
  },
34
34
  "@camstack/ui-library": {
35
35
  name: "@camstack/ui-library",
36
- version: "1.2.105",
36
+ version: "1.2.107",
37
37
  scope: ["default"],
38
38
  loaded: !1,
39
39
  from: "addon_pipeline_analytics_widgets",
@@ -36,7 +36,7 @@ async function r() {
36
36
  }
37
37
  },
38
38
  "@camstack/types": {
39
- version: "1.2.139",
39
+ version: "1.2.141",
40
40
  scope: "default",
41
41
  shareConfig: {
42
42
  singleton: !0,
@@ -45,7 +45,7 @@ async function r() {
45
45
  }
46
46
  },
47
47
  "@camstack/sdk": {
48
- version: "1.2.59",
48
+ version: "1.2.61",
49
49
  scope: "default",
50
50
  shareConfig: {
51
51
  singleton: !0,
@@ -81,7 +81,7 @@ async function r() {
81
81
  }
82
82
  },
83
83
  "@camstack/ui-library": {
84
- version: "1.2.105",
84
+ version: "1.2.107",
85
85
  scope: "default",
86
86
  shareConfig: {
87
87
  singleton: !0,
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-DQVA7q-T.js");
5
+ const require_dist = require("../dist-0kEjfSjL.js");
6
6
  let node_fs = require("node:fs");
7
7
  node_fs = require_dist.__toESM(node_fs, 1);
8
8
  let node_path = require("node:path");
@@ -40571,12 +40571,14 @@ var TrackStore = class {
40571
40571
  const limit = params.limit ?? 50;
40572
40572
  const timeBetween = params.since !== void 0 || params.until !== void 0 ? { firstSeen: [params.since ?? 0, params.until ?? Date.now()] } : {};
40573
40573
  const stationaryExclusion = params.excludeStationaryPromotions === true ? { whereNot: { closedReason: "stationary-promotion" } } : {};
40574
+ const classFilter = params.classes !== void 0 && params.classes.length > 0 ? { whereJsonArrayAny: { classes: [...params.classes] } } : {};
40574
40575
  if (params.zone === void 0) return (await this.store.query.query({
40575
40576
  collection: TRACKS_COLLECTION,
40576
40577
  filter: {
40577
40578
  where: { deviceId: params.deviceId },
40578
40579
  ...Object.keys(timeBetween).length > 0 ? { whereBetween: timeBetween } : {},
40579
40580
  ...stationaryExclusion,
40581
+ ...classFilter,
40580
40582
  orderBy: {
40581
40583
  field: "firstSeen",
40582
40584
  direction: "desc"
@@ -40592,6 +40594,7 @@ var TrackStore = class {
40592
40594
  filter: {
40593
40595
  where: { deviceId: params.deviceId },
40594
40596
  ...stationaryExclusion,
40597
+ ...classFilter,
40595
40598
  whereBetween: {
40596
40599
  ...timeBetween,
40597
40600
  envMinX: [-1e6, bounds.maxX],
@@ -40612,6 +40615,7 @@ var TrackStore = class {
40612
40615
  filter: {
40613
40616
  where: { deviceId: params.deviceId },
40614
40617
  ...stationaryExclusion,
40618
+ ...classFilter,
40615
40619
  ...Object.keys(timeBetween).length > 0 ? { whereBetween: timeBetween } : {},
40616
40620
  orderBy: {
40617
40621
  field: "firstSeen",
@@ -40734,11 +40738,13 @@ var TrackStore = class {
40734
40738
  nextCursor: null
40735
40739
  };
40736
40740
  const stationaryExclusion = params.excludeStationaryPromotions === true ? { whereNot: { closedReason: "stationary-promotion" } } : {};
40741
+ const classFilter = params.classes !== void 0 && params.classes.length > 0 ? { whereJsonArrayAny: { classes: [...params.classes] } } : {};
40737
40742
  const fetchRange = async (deviceId, range, pageLimit) => this.store.query.query({
40738
40743
  collection: TRACKS_COLLECTION,
40739
40744
  filter: {
40740
40745
  where: { deviceId },
40741
40746
  ...stationaryExclusion,
40747
+ ...classFilter,
40742
40748
  whereBetween: { lastSeen: range },
40743
40749
  orderBy: {
40744
40750
  field: "lastSeen",
@@ -1,4 +1,4 @@
1
- import { $ as audioModeOf, A as NcSnoozeSchema, At as BaseAddon, B as SCENE_DEFAULT_UNCOVERED_POLICY, Bt as boolean, C as NcConditionDescriptorSchema, Ct as sceneMonitorCapability, D as NcRuleTargetSchema, Dt as videoclipsCapability, E as NcRuleSchema, Et as vectorDimFromBase64, Ft as isDeviceScopedCap, G as TimelapseRulePatchSchema, Gt as partialRecord, H as SceneMonitorSchema, Ht as literal, I as RECORDING_EXPORT_MAX_READ_BYTES, It as nodePin, J as VISIT_MERGE_GAP_MS, Jt as unknown, K as TimelapseRuleSchema, Kt as record, L as RetrainStatusSchema, Lt as sleep$1, M as NcSystemEventKindSchema, Mt as DeviceType, N as NcTaxonomySchema, Nt as createEvent, O as NcScheduleSchema, Ot as zoneAnalyticsCapability, P as OpsLogEntrySchema, Pt as hydrateSchema, Q as audioMetricsCapability, Rt as _enum, S as NC_TAXONOMY, T as NcRulePatchSchema, Tt as systemEventFilterApplies, U as TIMELAPSE_DENSE_FLOOR_SEC, Ut as number, V as SCENE_DIVERGED, Vt as discriminatedUnion, W as TimelapseRuleInputSchema, Wt as object, X as alarmPanelCapability, Y as addonWidgetsSourceCapability, Yt as EventCategory, Z as assertTimelapseCadences, _ as MediaFileKindEnum, _t as pickClusterStepModels, a as DEFAULT_EVENT_COLOR, b as NC_DEFAULT_SNOOZE_MINUTES, bt as readDeviceStateFrom, c as DETECTION_MACRO_CLASSES, ct as faceGalleryCapability, d as EVENT_KIND_BY_CAP, dt as isDetectionMacroClass, et as buildEventKindDescriptor, f as EVENT_PAD_MS, ft as isScheduleActive, g as MACRO_LABELS, h as LabelAttributionSchema, ht as notificationRulesCapability, i as COCO_TO_MACRO, it as deriveRecordingMode, j as NcSnoozeSuppressedSchema, jt as CamProfileSchema, k as NcSnoozeInputSchema, kt as errMsg, lt as failureContributionCapability, m as FailureCounters, mt as kebabToCamel, n as BaseDevice, nt as customAction, ot as encodeVectorBase64, p as FULL_IMAGE_BBOX, pt as isSourceCap, q as TrackSourceSchema, qt as string, r as CLUSTER_MODEL_SCOPED_STEPS, rt as defineCustomActions, st as evaluateSensorEdge, t as AUDIO_MACRO_LABELS, tt as cosineSimilarity$1, u as DeclaredDevices, v as NC_ALARM_SYSTEM_EVENT_KINDS, vt as pipelineAnalyticsCapability, w as NcRuleInputSchema, wt as subKindsOf, xt as readTimelapseGeneratedAt, y as NC_CONDITION_CATALOG, yt as plateGalleryCapability, z as SCENE_DEFAULT_ANCHOR_THRESHOLD, zt as array } from "../dist-Cubb8Avj.mjs";
1
+ import { $ as audioModeOf, A as NcSnoozeSchema, At as BaseAddon, B as SCENE_DEFAULT_UNCOVERED_POLICY, Bt as boolean, C as NcConditionDescriptorSchema, Ct as sceneMonitorCapability, D as NcRuleTargetSchema, Dt as videoclipsCapability, E as NcRuleSchema, Et as vectorDimFromBase64, Ft as isDeviceScopedCap, G as TimelapseRulePatchSchema, Gt as partialRecord, H as SceneMonitorSchema, Ht as literal, I as RECORDING_EXPORT_MAX_READ_BYTES, It as nodePin, J as VISIT_MERGE_GAP_MS, Jt as unknown, K as TimelapseRuleSchema, Kt as record, L as RetrainStatusSchema, Lt as sleep$1, M as NcSystemEventKindSchema, Mt as DeviceType, N as NcTaxonomySchema, Nt as createEvent, O as NcScheduleSchema, Ot as zoneAnalyticsCapability, P as OpsLogEntrySchema, Pt as hydrateSchema, Q as audioMetricsCapability, Rt as _enum, S as NC_TAXONOMY, T as NcRulePatchSchema, Tt as systemEventFilterApplies, U as TIMELAPSE_DENSE_FLOOR_SEC, Ut as number, V as SCENE_DIVERGED, Vt as discriminatedUnion, W as TimelapseRuleInputSchema, Wt as object, X as alarmPanelCapability, Y as addonWidgetsSourceCapability, Yt as EventCategory, Z as assertTimelapseCadences, _ as MediaFileKindEnum, _t as pickClusterStepModels, a as DEFAULT_EVENT_COLOR, b as NC_DEFAULT_SNOOZE_MINUTES, bt as readDeviceStateFrom, c as DETECTION_MACRO_CLASSES, ct as faceGalleryCapability, d as EVENT_KIND_BY_CAP, dt as isDetectionMacroClass, et as buildEventKindDescriptor, f as EVENT_PAD_MS, ft as isScheduleActive, g as MACRO_LABELS, h as LabelAttributionSchema, ht as notificationRulesCapability, i as COCO_TO_MACRO, it as deriveRecordingMode, j as NcSnoozeSuppressedSchema, jt as CamProfileSchema, k as NcSnoozeInputSchema, kt as errMsg, lt as failureContributionCapability, m as FailureCounters, mt as kebabToCamel, n as BaseDevice, nt as customAction, ot as encodeVectorBase64, p as FULL_IMAGE_BBOX, pt as isSourceCap, q as TrackSourceSchema, qt as string, r as CLUSTER_MODEL_SCOPED_STEPS, rt as defineCustomActions, st as evaluateSensorEdge, t as AUDIO_MACRO_LABELS, tt as cosineSimilarity$1, u as DeclaredDevices, v as NC_ALARM_SYSTEM_EVENT_KINDS, vt as pipelineAnalyticsCapability, w as NcRuleInputSchema, wt as subKindsOf, xt as readTimelapseGeneratedAt, y as NC_CONDITION_CATALOG, yt as plateGalleryCapability, z as SCENE_DEFAULT_ANCHOR_THRESHOLD, zt as array } from "../dist-DZmz2kP-.mjs";
2
2
  import { t as __exportAll } from "../embedding-encoder/index.mjs";
3
3
  import * as fs from "node:fs";
4
4
  import { promises } from "node:fs";
@@ -40546,12 +40546,14 @@ var TrackStore = class {
40546
40546
  const limit = params.limit ?? 50;
40547
40547
  const timeBetween = params.since !== void 0 || params.until !== void 0 ? { firstSeen: [params.since ?? 0, params.until ?? Date.now()] } : {};
40548
40548
  const stationaryExclusion = params.excludeStationaryPromotions === true ? { whereNot: { closedReason: "stationary-promotion" } } : {};
40549
+ const classFilter = params.classes !== void 0 && params.classes.length > 0 ? { whereJsonArrayAny: { classes: [...params.classes] } } : {};
40549
40550
  if (params.zone === void 0) return (await this.store.query.query({
40550
40551
  collection: TRACKS_COLLECTION,
40551
40552
  filter: {
40552
40553
  where: { deviceId: params.deviceId },
40553
40554
  ...Object.keys(timeBetween).length > 0 ? { whereBetween: timeBetween } : {},
40554
40555
  ...stationaryExclusion,
40556
+ ...classFilter,
40555
40557
  orderBy: {
40556
40558
  field: "firstSeen",
40557
40559
  direction: "desc"
@@ -40567,6 +40569,7 @@ var TrackStore = class {
40567
40569
  filter: {
40568
40570
  where: { deviceId: params.deviceId },
40569
40571
  ...stationaryExclusion,
40572
+ ...classFilter,
40570
40573
  whereBetween: {
40571
40574
  ...timeBetween,
40572
40575
  envMinX: [-1e6, bounds.maxX],
@@ -40587,6 +40590,7 @@ var TrackStore = class {
40587
40590
  filter: {
40588
40591
  where: { deviceId: params.deviceId },
40589
40592
  ...stationaryExclusion,
40593
+ ...classFilter,
40590
40594
  ...Object.keys(timeBetween).length > 0 ? { whereBetween: timeBetween } : {},
40591
40595
  orderBy: {
40592
40596
  field: "firstSeen",
@@ -40709,11 +40713,13 @@ var TrackStore = class {
40709
40713
  nextCursor: null
40710
40714
  };
40711
40715
  const stationaryExclusion = params.excludeStationaryPromotions === true ? { whereNot: { closedReason: "stationary-promotion" } } : {};
40716
+ const classFilter = params.classes !== void 0 && params.classes.length > 0 ? { whereJsonArrayAny: { classes: [...params.classes] } } : {};
40712
40717
  const fetchRange = async (deviceId, range, pageLimit) => this.store.query.query({
40713
40718
  collection: TRACKS_COLLECTION,
40714
40719
  filter: {
40715
40720
  where: { deviceId },
40716
40721
  ...stationaryExclusion,
40722
+ ...classFilter,
40717
40723
  whereBetween: { lastSeen: range },
40718
40724
  orderBy: {
40719
40725
  field: "lastSeen",
@@ -30,7 +30,7 @@ async function d(e) {
30
30
  }
31
31
  }
32
32
  async function f() {
33
- return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-D74iweVp.mjs")).catch((e) => {
33
+ return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-Bb93NF26.mjs")).catch((e) => {
34
34
  throw l = void 0, e;
35
35
  }), l;
36
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-post-analysis",
3
- "version": "1.2.169",
3
+ "version": "1.2.171",
4
4
  "description": "Post-Analysis bundle — enrichment, embedding-encoder, pipeline-analytics. Multi-entry npm package shipping addons that consume pipeline output.",
5
5
  "keywords": [
6
6
  "camstack",