@camstack/addon-post-analysis 1.2.238 → 1.2.239

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.
@@ -23262,6 +23262,14 @@ var MotionSourceEnum = _enum([
23262
23262
  */
23263
23263
  var MotionSourcesSchema = array(MotionSourceEnum);
23264
23264
  /**
23265
+ * Which root detectors a camera runs. Deliberately the SAME vocabulary
23266
+ * post-analysis already tags every detection with (`DetectionSource`) rather
23267
+ * than a second spelling of the same two ideas — the value an operator picks
23268
+ * here is the value that comes back on the track, the overlay and the debug
23269
+ * row.
23270
+ */
23271
+ var DetectionSourcesSchema = array(DetectionSourceSchema);
23272
+ /**
23265
23273
  * Input shape for `pipeline-runner.reportMotion` cap method. Exported
23266
23274
  * so cap-side consumers (the orchestrator forward, the runner addon's
23267
23275
  * cap implementation, tests) can reuse the type instead of redeclaring
@@ -23412,6 +23420,35 @@ var RunnerCameraConfigSchema = object({
23412
23420
  * events; the orchestrator forwards to `reportMotion`.
23413
23421
  */
23414
23422
  motionSources: MotionSourcesSchema.default(["analyzer"]),
23423
+ /**
23424
+ * WHICH root detector runs for this camera. The detection counterpart of
23425
+ * {@link motionSources}, same shape and same discipline: a per-camera list
23426
+ * of sources the system understands, vendor-agnostic, owned here.
23427
+ *
23428
+ * - `pipeline` — this runner's own root step on decoded pixels (`steps`).
23429
+ * - `onboard` — the CAMERA's own detector, admitted only when it is named
23430
+ * here. Its boxes reach post-analysis on the same
23431
+ * `PipelineInferenceResult` payload as the pipeline's, so an onboard-born
23432
+ * track gets the same tracker, the same overlay and the same detail
23433
+ * subtree (face / plate / embedding).
23434
+ *
23435
+ * `['onboard']` alone is the REPLACEMENT: this runner's root step does not
23436
+ * run, and that is where a camera with a usable onboard detector buys back
23437
+ * its share of the accelerator. It saves the root inference, not the decode
23438
+ * — the detail subtree still needs pixels to cut crops from.
23439
+ *
23440
+ * A camera whose onboard detections carry no geometry cannot serve as a root
23441
+ * step at all (there is nothing to track), and the cap that knows this says
23442
+ * so on `native-object-detection.getOptions().geometry`. On Reolink that is
23443
+ * every battery camera: the boxes ride a sub-stream a battery camera never
23444
+ * attaches, so such a camera stays on `['pipeline']` and its onboard AI is
23445
+ * worth exactly what it already is — a wake signal with a class.
23446
+ *
23447
+ * Defaults to `['pipeline']`, which is byte-for-byte today's behaviour: a
23448
+ * vendor never turns a detector on for the operator, and neither does a
23449
+ * default.
23450
+ */
23451
+ detectionSources: DetectionSourcesSchema.default(["pipeline"]),
23415
23452
  pipelineEnabled: boolean().default(true),
23416
23453
  /** Ordered tree of video steps. Absent → runner skips video detection. */
23417
23454
  steps: array(PipelineStepInputSchema).readonly().optional(),
@@ -30552,31 +30589,38 @@ var NativeObjectDetectionStatusSchema = object({
30552
30589
  /**
30553
30590
  * Whether forwarding of onboard AI detections is enabled for this device.
30554
30591
  *
30555
- * The COLD-START default is the provider's, and it is not one value for
30556
- * every camera: a mains camera carries the boxed side-channel and its
30557
- * detections are usable subjects, so it defaults ON; a battery camera never
30558
- * attaches that channel, so the same toggle would buy it nothing but a write
30559
- * — it defaults OFF and an operator who wants it turns it on knowing what it
30560
- * costs. {@link NativeObjectDetectionOptionsSchema.geometry} is how the UI
30561
- * says which of the two a camera is.
30592
+ * Cold-start OFF on every camera. A vendor does not decide which detector a
30593
+ * camera runs — that is the operator's choice, and it is made where every
30594
+ * other detection choice is made. `geometry` on
30595
+ * {@link NativeObjectDetectionOptionsSchema} is how the form says what the
30596
+ * choice would buy this particular camera.
30562
30597
  */
30563
30598
  enabled: boolean()
30564
30599
  });
30565
30600
  /**
30566
- * What a camera's onboard detections actually CARRY.
30601
+ * WHEN a camera's onboard detections carry geometry.
30567
30602
  *
30568
- * `boxed` — the firmware ships a bounding box with the class, so a detection is
30569
- * a subject the pipeline can track, crop and score.
30570
- * `flag-only` — the firmware ships the class and nothing else. The pipeline
30571
- * needs geometry to make a subject out of it, so such a push reaches the
30572
- * tracker as motion and no further. On Reolink this is every battery camera:
30573
- * the boxes ride the BcMedia sub-stream, which a battery camera never attaches.
30603
+ * - `boxed` — always. The provider holds a standing channel for the boxes, so
30604
+ * a detection is a trackable subject whenever the camera sees one.
30605
+ * - `while-streaming` — only while some stream of this camera is already open.
30606
+ * The boxes ride the video's own side-channel rather than a feed of their
30607
+ * own, so they cost nothing and they exist only when something is pulling.
30608
+ * On Reolink this is every BATTERY camera: a persistent second feed is real
30609
+ * radio drain, but a camera that is awake is awake precisely because
30610
+ * something is in front of it, and its stream is already being pulled.
30611
+ * - `flag-only` — never. The firmware ships the class and nothing else; the
30612
+ * pipeline needs geometry to make a subject, so such a push reaches the
30613
+ * tracker as motion and no further.
30574
30614
  *
30575
30615
  * Reported and not inferred, because the operator's question in front of the
30576
- * toggle is "what do I get", and "a class with no box" and "a subject" are
30577
- * different answers (D14: the derived form is only as honest as `getOptions`).
30616
+ * picker is "what do I get", and these are three different answers (D14: the
30617
+ * derived form is only as honest as `getOptions`).
30578
30618
  */
30579
- var NativeObjectGeometryEnum = _enum(["boxed", "flag-only"]);
30619
+ var NativeObjectGeometryEnum = _enum([
30620
+ "boxed",
30621
+ "while-streaming",
30622
+ "flag-only"
30623
+ ]);
30580
30624
  var NativeObjectDetectionOptionsSchema = object({
30581
30625
  /** Classes this firmware can detect — the same list the status reports. */
30582
30626
  supportedClasses: array(NativeObjectClassEnum).readonly(),
@@ -30593,11 +30637,6 @@ var nativeObjectDetectionCapability = {
30593
30637
  deviceNative: true,
30594
30638
  mode: "singleton",
30595
30639
  deviceTypes: [DeviceType.Camera],
30596
- deviceConfig: { ui: {
30597
- kind: "derived-form",
30598
- builderId: "native-object-detection",
30599
- tab: "motion"
30600
- } },
30601
30640
  methods: {
30602
30641
  getOptions: method(object({ deviceId: number() }), NativeObjectDetectionOptionsSchema),
30603
30642
  setSettings: method(object({
@@ -23293,6 +23293,14 @@ var MotionSourceEnum = _enum([
23293
23293
  */
23294
23294
  var MotionSourcesSchema = array(MotionSourceEnum);
23295
23295
  /**
23296
+ * Which root detectors a camera runs. Deliberately the SAME vocabulary
23297
+ * post-analysis already tags every detection with (`DetectionSource`) rather
23298
+ * than a second spelling of the same two ideas — the value an operator picks
23299
+ * here is the value that comes back on the track, the overlay and the debug
23300
+ * row.
23301
+ */
23302
+ var DetectionSourcesSchema = array(DetectionSourceSchema);
23303
+ /**
23296
23304
  * Input shape for `pipeline-runner.reportMotion` cap method. Exported
23297
23305
  * so cap-side consumers (the orchestrator forward, the runner addon's
23298
23306
  * cap implementation, tests) can reuse the type instead of redeclaring
@@ -23443,6 +23451,35 @@ var RunnerCameraConfigSchema = object({
23443
23451
  * events; the orchestrator forwards to `reportMotion`.
23444
23452
  */
23445
23453
  motionSources: MotionSourcesSchema.default(["analyzer"]),
23454
+ /**
23455
+ * WHICH root detector runs for this camera. The detection counterpart of
23456
+ * {@link motionSources}, same shape and same discipline: a per-camera list
23457
+ * of sources the system understands, vendor-agnostic, owned here.
23458
+ *
23459
+ * - `pipeline` — this runner's own root step on decoded pixels (`steps`).
23460
+ * - `onboard` — the CAMERA's own detector, admitted only when it is named
23461
+ * here. Its boxes reach post-analysis on the same
23462
+ * `PipelineInferenceResult` payload as the pipeline's, so an onboard-born
23463
+ * track gets the same tracker, the same overlay and the same detail
23464
+ * subtree (face / plate / embedding).
23465
+ *
23466
+ * `['onboard']` alone is the REPLACEMENT: this runner's root step does not
23467
+ * run, and that is where a camera with a usable onboard detector buys back
23468
+ * its share of the accelerator. It saves the root inference, not the decode
23469
+ * — the detail subtree still needs pixels to cut crops from.
23470
+ *
23471
+ * A camera whose onboard detections carry no geometry cannot serve as a root
23472
+ * step at all (there is nothing to track), and the cap that knows this says
23473
+ * so on `native-object-detection.getOptions().geometry`. On Reolink that is
23474
+ * every battery camera: the boxes ride a sub-stream a battery camera never
23475
+ * attaches, so such a camera stays on `['pipeline']` and its onboard AI is
23476
+ * worth exactly what it already is — a wake signal with a class.
23477
+ *
23478
+ * Defaults to `['pipeline']`, which is byte-for-byte today's behaviour: a
23479
+ * vendor never turns a detector on for the operator, and neither does a
23480
+ * default.
23481
+ */
23482
+ detectionSources: DetectionSourcesSchema.default(["pipeline"]),
23446
23483
  pipelineEnabled: boolean().default(true),
23447
23484
  /** Ordered tree of video steps. Absent → runner skips video detection. */
23448
23485
  steps: array(PipelineStepInputSchema).readonly().optional(),
@@ -30583,31 +30620,38 @@ var NativeObjectDetectionStatusSchema = object({
30583
30620
  /**
30584
30621
  * Whether forwarding of onboard AI detections is enabled for this device.
30585
30622
  *
30586
- * The COLD-START default is the provider's, and it is not one value for
30587
- * every camera: a mains camera carries the boxed side-channel and its
30588
- * detections are usable subjects, so it defaults ON; a battery camera never
30589
- * attaches that channel, so the same toggle would buy it nothing but a write
30590
- * — it defaults OFF and an operator who wants it turns it on knowing what it
30591
- * costs. {@link NativeObjectDetectionOptionsSchema.geometry} is how the UI
30592
- * says which of the two a camera is.
30623
+ * Cold-start OFF on every camera. A vendor does not decide which detector a
30624
+ * camera runs — that is the operator's choice, and it is made where every
30625
+ * other detection choice is made. `geometry` on
30626
+ * {@link NativeObjectDetectionOptionsSchema} is how the form says what the
30627
+ * choice would buy this particular camera.
30593
30628
  */
30594
30629
  enabled: boolean()
30595
30630
  });
30596
30631
  /**
30597
- * What a camera's onboard detections actually CARRY.
30632
+ * WHEN a camera's onboard detections carry geometry.
30598
30633
  *
30599
- * `boxed` — the firmware ships a bounding box with the class, so a detection is
30600
- * a subject the pipeline can track, crop and score.
30601
- * `flag-only` — the firmware ships the class and nothing else. The pipeline
30602
- * needs geometry to make a subject out of it, so such a push reaches the
30603
- * tracker as motion and no further. On Reolink this is every battery camera:
30604
- * the boxes ride the BcMedia sub-stream, which a battery camera never attaches.
30634
+ * - `boxed` — always. The provider holds a standing channel for the boxes, so
30635
+ * a detection is a trackable subject whenever the camera sees one.
30636
+ * - `while-streaming` — only while some stream of this camera is already open.
30637
+ * The boxes ride the video's own side-channel rather than a feed of their
30638
+ * own, so they cost nothing and they exist only when something is pulling.
30639
+ * On Reolink this is every BATTERY camera: a persistent second feed is real
30640
+ * radio drain, but a camera that is awake is awake precisely because
30641
+ * something is in front of it, and its stream is already being pulled.
30642
+ * - `flag-only` — never. The firmware ships the class and nothing else; the
30643
+ * pipeline needs geometry to make a subject, so such a push reaches the
30644
+ * tracker as motion and no further.
30605
30645
  *
30606
30646
  * Reported and not inferred, because the operator's question in front of the
30607
- * toggle is "what do I get", and "a class with no box" and "a subject" are
30608
- * different answers (D14: the derived form is only as honest as `getOptions`).
30647
+ * picker is "what do I get", and these are three different answers (D14: the
30648
+ * derived form is only as honest as `getOptions`).
30609
30649
  */
30610
- var NativeObjectGeometryEnum = _enum(["boxed", "flag-only"]);
30650
+ var NativeObjectGeometryEnum = _enum([
30651
+ "boxed",
30652
+ "while-streaming",
30653
+ "flag-only"
30654
+ ]);
30611
30655
  var NativeObjectDetectionOptionsSchema = object({
30612
30656
  /** Classes this firmware can detect — the same list the status reports. */
30613
30657
  supportedClasses: array(NativeObjectClassEnum).readonly(),
@@ -30624,11 +30668,6 @@ var nativeObjectDetectionCapability = {
30624
30668
  deviceNative: true,
30625
30669
  mode: "singleton",
30626
30670
  deviceTypes: [DeviceType.Camera],
30627
- deviceConfig: { ui: {
30628
- kind: "derived-form",
30629
- builderId: "native-object-detection",
30630
- tab: "motion"
30631
- } },
30632
30671
  methods: {
30633
30672
  getOptions: method(object({ deviceId: number() }), NativeObjectDetectionOptionsSchema),
30634
30673
  setSettings: method(object({
@@ -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-Dxw5Onk5.js");
5
+ const require_dist = require("../dist-DjW7k4lv.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 { Dt as parseProcStatus, H as PoolMemoryWatchdog, Pt as resolvePoolMemoryPolicy, Ut as BaseAddon, ft as embeddingEncoderCapability, vt as hfModelUrl } from "../dist-Clk4x3Hp.mjs";
1
+ import { Dt as parseProcStatus, H as PoolMemoryWatchdog, Pt as resolvePoolMemoryPolicy, Ut as BaseAddon, ft as embeddingEncoderCapability, vt as hfModelUrl } from "../dist-CCw4SKRp.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";
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.190",
21
+ version: "1.2.191",
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.155",
36
+ version: "1.2.156",
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.190",
39
+ version: "1.2.191",
40
40
  scope: "default",
41
41
  shareConfig: {
42
42
  singleton: !0,
@@ -81,7 +81,7 @@ async function r() {
81
81
  }
82
82
  },
83
83
  "@camstack/ui-library": {
84
- version: "1.2.155",
84
+ version: "1.2.156",
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-Dxw5Onk5.js");
5
+ const require_dist = require("../dist-DjW7k4lv.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");
@@ -56853,63 +56853,6 @@ var MotionOnsetRegistry = class {
56853
56853
  }
56854
56854
  };
56855
56855
  //#endregion
56856
- //#region src/pipeline-analytics/pipeline/native-detection.ts
56857
- /**
56858
- * Nominal frame size used to denormalize native `[0,1]` boxes when a
56859
- * camera push doesn't carry real frame dimensions. Zone polygons are
56860
- * normalized too, so zone overlap + tracking are scale-invariant — any
56861
- * consistent size works. Stored bbox values then live in this nominal
56862
- * pixel space (documented; consumers treat native bbox as relative).
56863
- */
56864
- var NATIVE_NOMINAL_FRAME = {
56865
- width: 1e3,
56866
- height: 1e3
56867
- };
56868
- /**
56869
- * Convert a `detection.camera-native` push into the canonical
56870
- * {@link FrameResult} the analysis layer consumes, so native detections
56871
- * run through the SAME zoning/tracking/event pipeline as the ML source.
56872
- *
56873
- * Only detections carrying a `bbox` can be zoned/tracked — flag-only
56874
- * entries (the firmware's class-pulse without geometry) are dropped;
56875
- * returns `null` when none remain. Normalized `[0,1]` boxes are
56876
- * denormalized against the push's frame dimensions (or
56877
- * {@link NATIVE_NOMINAL_FRAME} when absent). No `frameHandle` is set: the
56878
- * native path has no decoded pixels, so pixel-based enrichment self-skips.
56879
- */
56880
- function nativeDetectionsToFrame(input) {
56881
- const boxed = input.detections.filter((d) => d.bbox != null);
56882
- if (boxed.length === 0) return null;
56883
- const width = input.frameWidth ?? NATIVE_NOMINAL_FRAME.width;
56884
- const height = input.frameHeight ?? NATIVE_NOMINAL_FRAME.height;
56885
- const timestamp = boxed.reduce((max, d) => Math.max(max, d.timestamp), 0);
56886
- const detections = boxed.map((d, i) => {
56887
- const [nx, ny, nw, nh] = d.bbox;
56888
- return {
56889
- id: `native-${timestamp}-${i}`,
56890
- kind: "first-level",
56891
- macroClass: d.class,
56892
- score: d.confidence ?? 1,
56893
- labels: [],
56894
- bbox: {
56895
- x: nx * width,
56896
- y: ny * height,
56897
- width: nw * width,
56898
- height: nh * height
56899
- }
56900
- };
56901
- });
56902
- return {
56903
- kind: "frame",
56904
- frameId: `native-${input.cameraId}-${timestamp}`,
56905
- deviceId: input.cameraId,
56906
- timestamp,
56907
- width,
56908
- height,
56909
- detections
56910
- };
56911
- }
56912
- //#endregion
56913
56856
  //#region src/pipeline-analytics/pipeline/object-embedding-selection.ts
56914
56857
  function isClipObjectEmbedding(t) {
56915
56858
  return Array.isArray(t.embedding) && t.embedding.length > 0 && typeof t.embeddingModelId === "string" && t.embeddingModelId.startsWith("mobileclip-");
@@ -67877,10 +67820,6 @@ function wireSubscriptions(deps) {
67877
67820
  const timestamp = typeof data.timestamp === "number" ? data.timestamp : ev.timestamp instanceof Date ? ev.timestamp.getTime() : Date.now();
67878
67821
  deps.onOnboardMotion(data.deviceId, data, timestamp);
67879
67822
  }));
67880
- unsubs.push(deps.eventBus.subscribe({ category: require_dist.EventCategory.DetectionCameraNative }, (ev) => {
67881
- const data = ev.data;
67882
- deps.onNativeDetection(data);
67883
- }));
67884
67823
  unsubs.push(deps.eventBus.subscribe({ category: require_dist.EventCategory.DeviceStateChanged }, (ev) => {
67885
67824
  const data = ev.data;
67886
67825
  const timestamp = ev.timestamp instanceof Date ? ev.timestamp.getTime() : Date.now();
@@ -75679,7 +75618,6 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_dist.B
75679
75618
  onAudioResult: (data) => this.handleAudioResult(data),
75680
75619
  onMotionAnalysis: (deviceId, data, timestampMs) => this.handleMotionAnalysis(deviceId, data, timestampMs),
75681
75620
  onOnboardMotion: (deviceId, data, timestampMs) => this.handleOnboardMotion(deviceId, data, timestampMs),
75682
- onNativeDetection: (data) => this.handleNativeDetection(data),
75683
75621
  onBatterySample: (deviceId, percentage, at) => this.lts?.note("battery", deviceId, percentage, at),
75684
75622
  onSensorStateChanged: (data, timestampMs) => this.handleSensorStateChanged(data, timestampMs),
75685
75623
  onBindingsChanged: (data) => this.handleBindingsChangedEvent(data),
@@ -78339,7 +78277,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_dist.B
78339
78277
  }
78340
78278
  });
78341
78279
  }
78342
- await this.processFrame(deviceId, frame, "pipeline", data.frameHandle, data.detailSteps);
78280
+ await this.processFrame(deviceId, frame, data.source ?? "pipeline", data.frameHandle, data.detailSteps);
78343
78281
  }
78344
78282
  /**
78345
78283
  * Run one detection frame through the analysis layers for a given
@@ -81545,24 +81483,6 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_dist.B
81545
81483
  }
81546
81484
  }
81547
81485
  /**
81548
- * Ingest a native (onboard) camera detection push and run it through
81549
- * the SAME analysis layers as the ML pipeline, tagged `source:
81550
- * 'onboard'`. Flag-only pushes (no bbox) can't be zoned/tracked and are
81551
- * dropped by the normalizer. Mirrors `handleInferenceResult` but for the
81552
- * native source — the pipeline itself is never touched.
81553
- */
81554
- async handleNativeDetection(payload) {
81555
- if (this.shuttingDown) return;
81556
- const frame = nativeDetectionsToFrame({
81557
- cameraId: payload.cameraId,
81558
- detections: payload.detections,
81559
- frameWidth: payload.frameWidth,
81560
- frameHeight: payload.frameHeight
81561
- });
81562
- if (!frame) return;
81563
- await this.processFrame(payload.cameraId, frame, "onboard");
81564
- }
81565
- /**
81566
81486
  * Best-effort bus notification for a gallery face-row change (buffer /
81567
81487
  * assign / unassign / delete). Passed into the `FaceRecognizer` and
81568
81488
  * `FaceGalleryProvider` as their `emitFaceGalleryChanged` dep. Telemetry
@@ -1,4 +1,4 @@
1
- import { $ as TimelapseRuleSchema, $t as boolean, A as NcConditionDescriptorSchema, At as plateGalleryCapability, B as NcTaxonomySchema, Bt as videoclipsCapability, C as MOTION_CLOSE_AFTER_MS, Ct as isSourceCap, D as NC_DEFAULT_SNOOZE_MINUTES, E as NC_CONDITION_CATALOG, Et as notificationRulesCapability, F as NcScheduleSchema, Ft as sceneMonitorCapability, Gt as DeviceType, Ht as errMsg$1, I as NcSnoozeInputSchema, It as storageOccupancyCapability, J as SCENE_DIVERGED, Jt as isDeviceScopedCap, K as SCENE_DEFAULT_ANCHOR_THRESHOLD, Kt as createEvent, L as NcSnoozeSchema, Lt as subKindsOf, M as NcRulePatchSchema, Mt as readTimelapseGeneratedAt, N as NcRuleSchema, Nt as resolveLocationMode, Ot as pickClusterStepModels, P as NcRuleTargetSchema, Q as TimelapseRulePatchSchema, Qt as array, R as NcSnoozeSuppressedSchema, Rt as systemEventFilterApplies, St as isScheduleActive, T as NC_ALARM_SYSTEM_EVENT_KINDS, Tt as mayWriteToLocation, U as RECORDING_EXPORT_MAX_READ_BYTES, Ut as BaseAddon, V as OpsLogEntrySchema, Vt as zoneAnalyticsCapability, W as RetrainStatusSchema, Wt as CamProfileSchema, X as TIMELAPSE_DENSE_FLOOR_SEC, Xt as sleep$1, Y as SceneMonitorSchema, Yt as nodePin, Z as TimelapseRuleInputSchema, Zt as _enum, _ as FULL_IMAGE_BBOX, _t as failureContributionCapability, a as CLUSTER_MODEL_SCOPED_STEPS, an as record, at as audioMetricsCapability, b as MAX_ARCHIVED_DEBUG_NOTES, bt as isEventOwnerType, cn as EventCategory, ct as cosineSimilarity$1, dt as deriveRecordingMode, en as discriminatedUnion, et as TrackSourceSchema, f as DeclaredDevices, g as FIRST_LEVEL_MACRO_CLASSES, gt as faceGalleryCapability, h as EVENT_PAD_MS, ht as evictionPolicyOfLocation, i as BirthDecisionRecordSchema, in as partialRecord, it as assertTimelapseCadences, j as NcRuleInputSchema, jt as readDeviceStateFrom, k as NC_TAXONOMY, kt as pipelineAnalyticsCapability, lt as customAction, m as EVENT_OWNER_TYPES, mt as evaluateSensorEdge, n as ArchivedDebugNoteSchema, nn as number, nt as addonWidgetsSourceCapability, o as COCO_TO_MACRO, on as string, ot as audioModeOf, p as EVENT_KIND_BY_CAP, pt as encodeVectorBase64, q as SCENE_DEFAULT_UNCOVERED_POLICY, qt as hydrateSchema, r as BaseDevice, rn as object, rt as alarmPanelCapability, s as DEFAULT_EVENT_COLOR, sn as unknown, st as buildEventKindDescriptor, t as AUDIO_MACRO_LABELS, tn as literal, tt as VISIT_MERGE_GAP_MS, u as DETECTION_MACRO_CLASSES, ut as defineCustomActions, v as FailureCounters, w as MediaFileKindEnum, wt as kebabToCamel, x as MAX_BIRTH_DECISION_RECORDS, xt as isMediaOwnerType, y as LabelAttributionSchema, yt as isDetectionMacroClass, z as NcSystemEventKindSchema, zt as vectorDimFromBase64 } from "../dist-Clk4x3Hp.mjs";
1
+ import { $ as TimelapseRuleSchema, $t as boolean, A as NcConditionDescriptorSchema, At as plateGalleryCapability, B as NcTaxonomySchema, Bt as videoclipsCapability, C as MOTION_CLOSE_AFTER_MS, Ct as isSourceCap, D as NC_DEFAULT_SNOOZE_MINUTES, E as NC_CONDITION_CATALOG, Et as notificationRulesCapability, F as NcScheduleSchema, Ft as sceneMonitorCapability, Gt as DeviceType, Ht as errMsg$1, I as NcSnoozeInputSchema, It as storageOccupancyCapability, J as SCENE_DIVERGED, Jt as isDeviceScopedCap, K as SCENE_DEFAULT_ANCHOR_THRESHOLD, Kt as createEvent, L as NcSnoozeSchema, Lt as subKindsOf, M as NcRulePatchSchema, Mt as readTimelapseGeneratedAt, N as NcRuleSchema, Nt as resolveLocationMode, Ot as pickClusterStepModels, P as NcRuleTargetSchema, Q as TimelapseRulePatchSchema, Qt as array, R as NcSnoozeSuppressedSchema, Rt as systemEventFilterApplies, St as isScheduleActive, T as NC_ALARM_SYSTEM_EVENT_KINDS, Tt as mayWriteToLocation, U as RECORDING_EXPORT_MAX_READ_BYTES, Ut as BaseAddon, V as OpsLogEntrySchema, Vt as zoneAnalyticsCapability, W as RetrainStatusSchema, Wt as CamProfileSchema, X as TIMELAPSE_DENSE_FLOOR_SEC, Xt as sleep$1, Y as SceneMonitorSchema, Yt as nodePin, Z as TimelapseRuleInputSchema, Zt as _enum, _ as FULL_IMAGE_BBOX, _t as failureContributionCapability, a as CLUSTER_MODEL_SCOPED_STEPS, an as record, at as audioMetricsCapability, b as MAX_ARCHIVED_DEBUG_NOTES, bt as isEventOwnerType, cn as EventCategory, ct as cosineSimilarity$1, dt as deriveRecordingMode, en as discriminatedUnion, et as TrackSourceSchema, f as DeclaredDevices, g as FIRST_LEVEL_MACRO_CLASSES, gt as faceGalleryCapability, h as EVENT_PAD_MS, ht as evictionPolicyOfLocation, i as BirthDecisionRecordSchema, in as partialRecord, it as assertTimelapseCadences, j as NcRuleInputSchema, jt as readDeviceStateFrom, k as NC_TAXONOMY, kt as pipelineAnalyticsCapability, lt as customAction, m as EVENT_OWNER_TYPES, mt as evaluateSensorEdge, n as ArchivedDebugNoteSchema, nn as number, nt as addonWidgetsSourceCapability, o as COCO_TO_MACRO, on as string, ot as audioModeOf, p as EVENT_KIND_BY_CAP, pt as encodeVectorBase64, q as SCENE_DEFAULT_UNCOVERED_POLICY, qt as hydrateSchema, r as BaseDevice, rn as object, rt as alarmPanelCapability, s as DEFAULT_EVENT_COLOR, sn as unknown, st as buildEventKindDescriptor, t as AUDIO_MACRO_LABELS, tn as literal, tt as VISIT_MERGE_GAP_MS, u as DETECTION_MACRO_CLASSES, ut as defineCustomActions, v as FailureCounters, w as MediaFileKindEnum, wt as kebabToCamel, x as MAX_BIRTH_DECISION_RECORDS, xt as isMediaOwnerType, y as LabelAttributionSchema, yt as isDetectionMacroClass, z as NcSystemEventKindSchema, zt as vectorDimFromBase64 } from "../dist-CCw4SKRp.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";
@@ -56779,63 +56779,6 @@ var MotionOnsetRegistry = class {
56779
56779
  }
56780
56780
  };
56781
56781
  //#endregion
56782
- //#region src/pipeline-analytics/pipeline/native-detection.ts
56783
- /**
56784
- * Nominal frame size used to denormalize native `[0,1]` boxes when a
56785
- * camera push doesn't carry real frame dimensions. Zone polygons are
56786
- * normalized too, so zone overlap + tracking are scale-invariant — any
56787
- * consistent size works. Stored bbox values then live in this nominal
56788
- * pixel space (documented; consumers treat native bbox as relative).
56789
- */
56790
- var NATIVE_NOMINAL_FRAME = {
56791
- width: 1e3,
56792
- height: 1e3
56793
- };
56794
- /**
56795
- * Convert a `detection.camera-native` push into the canonical
56796
- * {@link FrameResult} the analysis layer consumes, so native detections
56797
- * run through the SAME zoning/tracking/event pipeline as the ML source.
56798
- *
56799
- * Only detections carrying a `bbox` can be zoned/tracked — flag-only
56800
- * entries (the firmware's class-pulse without geometry) are dropped;
56801
- * returns `null` when none remain. Normalized `[0,1]` boxes are
56802
- * denormalized against the push's frame dimensions (or
56803
- * {@link NATIVE_NOMINAL_FRAME} when absent). No `frameHandle` is set: the
56804
- * native path has no decoded pixels, so pixel-based enrichment self-skips.
56805
- */
56806
- function nativeDetectionsToFrame(input) {
56807
- const boxed = input.detections.filter((d) => d.bbox != null);
56808
- if (boxed.length === 0) return null;
56809
- const width = input.frameWidth ?? NATIVE_NOMINAL_FRAME.width;
56810
- const height = input.frameHeight ?? NATIVE_NOMINAL_FRAME.height;
56811
- const timestamp = boxed.reduce((max, d) => Math.max(max, d.timestamp), 0);
56812
- const detections = boxed.map((d, i) => {
56813
- const [nx, ny, nw, nh] = d.bbox;
56814
- return {
56815
- id: `native-${timestamp}-${i}`,
56816
- kind: "first-level",
56817
- macroClass: d.class,
56818
- score: d.confidence ?? 1,
56819
- labels: [],
56820
- bbox: {
56821
- x: nx * width,
56822
- y: ny * height,
56823
- width: nw * width,
56824
- height: nh * height
56825
- }
56826
- };
56827
- });
56828
- return {
56829
- kind: "frame",
56830
- frameId: `native-${input.cameraId}-${timestamp}`,
56831
- deviceId: input.cameraId,
56832
- timestamp,
56833
- width,
56834
- height,
56835
- detections
56836
- };
56837
- }
56838
- //#endregion
56839
56782
  //#region src/pipeline-analytics/pipeline/object-embedding-selection.ts
56840
56783
  function isClipObjectEmbedding(t) {
56841
56784
  return Array.isArray(t.embedding) && t.embedding.length > 0 && typeof t.embeddingModelId === "string" && t.embeddingModelId.startsWith("mobileclip-");
@@ -67803,10 +67746,6 @@ function wireSubscriptions(deps) {
67803
67746
  const timestamp = typeof data.timestamp === "number" ? data.timestamp : ev.timestamp instanceof Date ? ev.timestamp.getTime() : Date.now();
67804
67747
  deps.onOnboardMotion(data.deviceId, data, timestamp);
67805
67748
  }));
67806
- unsubs.push(deps.eventBus.subscribe({ category: EventCategory.DetectionCameraNative }, (ev) => {
67807
- const data = ev.data;
67808
- deps.onNativeDetection(data);
67809
- }));
67810
67749
  unsubs.push(deps.eventBus.subscribe({ category: EventCategory.DeviceStateChanged }, (ev) => {
67811
67750
  const data = ev.data;
67812
67751
  const timestamp = ev.timestamp instanceof Date ? ev.timestamp.getTime() : Date.now();
@@ -75605,7 +75544,6 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
75605
75544
  onAudioResult: (data) => this.handleAudioResult(data),
75606
75545
  onMotionAnalysis: (deviceId, data, timestampMs) => this.handleMotionAnalysis(deviceId, data, timestampMs),
75607
75546
  onOnboardMotion: (deviceId, data, timestampMs) => this.handleOnboardMotion(deviceId, data, timestampMs),
75608
- onNativeDetection: (data) => this.handleNativeDetection(data),
75609
75547
  onBatterySample: (deviceId, percentage, at) => this.lts?.note("battery", deviceId, percentage, at),
75610
75548
  onSensorStateChanged: (data, timestampMs) => this.handleSensorStateChanged(data, timestampMs),
75611
75549
  onBindingsChanged: (data) => this.handleBindingsChangedEvent(data),
@@ -78265,7 +78203,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
78265
78203
  }
78266
78204
  });
78267
78205
  }
78268
- await this.processFrame(deviceId, frame, "pipeline", data.frameHandle, data.detailSteps);
78206
+ await this.processFrame(deviceId, frame, data.source ?? "pipeline", data.frameHandle, data.detailSteps);
78269
78207
  }
78270
78208
  /**
78271
78209
  * Run one detection frame through the analysis layers for a given
@@ -81471,24 +81409,6 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
81471
81409
  }
81472
81410
  }
81473
81411
  /**
81474
- * Ingest a native (onboard) camera detection push and run it through
81475
- * the SAME analysis layers as the ML pipeline, tagged `source:
81476
- * 'onboard'`. Flag-only pushes (no bbox) can't be zoned/tracked and are
81477
- * dropped by the normalizer. Mirrors `handleInferenceResult` but for the
81478
- * native source — the pipeline itself is never touched.
81479
- */
81480
- async handleNativeDetection(payload) {
81481
- if (this.shuttingDown) return;
81482
- const frame = nativeDetectionsToFrame({
81483
- cameraId: payload.cameraId,
81484
- detections: payload.detections,
81485
- frameWidth: payload.frameWidth,
81486
- frameHeight: payload.frameHeight
81487
- });
81488
- if (!frame) return;
81489
- await this.processFrame(payload.cameraId, frame, "onboard");
81490
- }
81491
- /**
81492
81412
  * Best-effort bus notification for a gallery face-row change (buffer /
81493
81413
  * assign / unassign / delete). Passed into the `FaceRecognizer` and
81494
81414
  * `FaceGalleryProvider` as their `emitFaceGalleryChanged` dep. Telemetry
@@ -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-FKof86Nh.mjs")).catch((e) => {
33
+ return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CK5DhAuN.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.238",
3
+ "version": "1.2.239",
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",