@camstack/addon-pipeline 1.2.232 → 1.2.234

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 (31) hide show
  1. package/dist/audio-analyzer/index.js +2 -2
  2. package/dist/audio-analyzer/index.mjs +2 -2
  3. package/dist/{default-detection-model-DcB4--Xd.js → default-detection-model-CDhXxOJQ.js} +1 -1
  4. package/dist/{default-detection-model-DNsmwQx0.mjs → default-detection-model-I8kuDTEi.mjs} +1 -1
  5. package/dist/detection-pipeline/index.js +4 -4
  6. package/dist/detection-pipeline/index.mjs +4 -4
  7. package/dist/{dist-BwQxOtXy.mjs → dist-But4XMDJ.mjs} +61 -17
  8. package/dist/{dist-CoRJjU1W.js → dist-NX0e_oWp.js} +61 -17
  9. package/dist/motion-wasm/index.js +1 -1
  10. package/dist/motion-wasm/index.mjs +1 -1
  11. package/dist/{node-BjScdHzE.mjs → node-BHxRrsoX.mjs} +1 -1
  12. package/dist/{node-DvcGhYd4.js → node-BgM4n8D4.js} +1 -1
  13. package/dist/pipeline-runner/index.js +205 -17
  14. package/dist/pipeline-runner/index.mjs +205 -17
  15. package/dist/{process-memory-62FAABqk.mjs → process-memory-C3-EOjjf.mjs} +1 -1
  16. package/dist/{process-memory-CIOO13cP.js → process-memory-C5_Mo9TI.js} +1 -1
  17. package/dist/recorder/index.js +3 -2
  18. package/dist/recorder/index.mjs +3 -2
  19. package/dist/{segment-demux-js-xLE3PxMz.js → segment-demux-js-BAD7i9RI.js} +1 -1
  20. package/dist/{segment-demux-js-CCnlSDIN.mjs → segment-demux-js-CVZACSOh.mjs} +1 -1
  21. package/dist/stream-broker/_stub.js +1 -1
  22. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BElWMGVT.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BWvbnTku.mjs} +2 -2
  23. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D3XkHB88.mjs +26 -0
  24. package/dist/stream-broker/demux-worker-child.js +1 -1
  25. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  26. package/dist/stream-broker/{hostInit-CU5lZ8MZ.mjs → hostInit-CoOZAV_n.mjs} +2 -2
  27. package/dist/stream-broker/index.js +3 -3
  28. package/dist/stream-broker/index.mjs +3 -3
  29. package/dist/stream-broker/remoteEntry.js +1 -1
  30. package/package.json +1 -1
  31. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Cdsf1_-A.mjs +0 -26
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-CoRJjU1W.js");
7
- const require_process_memory = require("../process-memory-CIOO13cP.js");
6
+ const require_dist = require("../dist-NX0e_oWp.js");
7
+ const require_process_memory = require("../process-memory-C5_Mo9TI.js");
8
8
  let node_fs = require("node:fs");
9
9
  node_fs = require_chunk.__toESM(node_fs);
10
10
  let node_path = require("node:path");
@@ -1,6 +1,6 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $t as hydrateSchema, At as resolvePoolMemoryPolicy, Kt as BaseAddon, N as audioAnalysisCapability, P as audioAnalyzerCapability, Qt as expandAudioChunkToF32le, Xt as audioChunkBytesPerSample, bn as EventCategory, ct as mapAudioLabelToMacro, n as AUDIO_BACKEND_CHOICES, rn as nodePin, s as DEFAULT_AUDIO_ANALYZER_CONFIG, w as PoolMemoryWatchdog, y as HF_BASE_URL, zt as errMsg } from "../dist-BwQxOtXy.mjs";
3
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-62FAABqk.mjs";
2
+ import { $t as hydrateSchema, At as resolvePoolMemoryPolicy, Kt as BaseAddon, N as audioAnalysisCapability, P as audioAnalyzerCapability, Qt as expandAudioChunkToF32le, Xt as audioChunkBytesPerSample, bn as EventCategory, ct as mapAudioLabelToMacro, n as AUDIO_BACKEND_CHOICES, rn as nodePin, s as DEFAULT_AUDIO_ANALYZER_CONFIG, w as PoolMemoryWatchdog, y as HF_BASE_URL, zt as errMsg } from "../dist-But4XMDJ.mjs";
3
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-C3-EOjjf.mjs";
4
4
  import * as fs from "node:fs";
5
5
  import * as path$1 from "node:path";
6
6
  import { downloadFile } from "@camstack/system/addon-utils";
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-CoRJjU1W.js");
1
+ const require_dist = require("./dist-NX0e_oWp.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  //#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { F as audioKindId, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS, rt as hfModelUrl } from "./dist-BwQxOtXy.mjs";
1
+ import { F as audioKindId, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS, rt as hfModelUrl } from "./dist-But4XMDJ.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  //#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
4
4
  /**
@@ -3,11 +3,11 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-CoRJjU1W.js");
7
- const require_node = require("../node-DvcGhYd4.js");
8
- const require_default_detection_model = require("../default-detection-model-DcB4--Xd.js");
6
+ const require_dist = require("../dist-NX0e_oWp.js");
7
+ const require_node = require("../node-BgM4n8D4.js");
8
+ const require_default_detection_model = require("../default-detection-model-CDhXxOJQ.js");
9
9
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
10
- const require_process_memory = require("../process-memory-CIOO13cP.js");
10
+ const require_process_memory = require("../process-memory-C5_Mo9TI.js");
11
11
  let node_os = require("node:os");
12
12
  node_os = require_chunk.__toESM(node_os);
13
13
  let node_fs = require("node:fs");
@@ -1,9 +1,9 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $t as hydrateSchema, At as resolvePoolMemoryPolicy, Dt as resolveClusterStepModelId, H as defaultDeviceFor$1, Kt as BaseAddon, Lt as supportedRuntimes$1, Mt as runtimeDevices$1, Q as evaluateZoneRules, X as enumerateInferenceDevices, Zt as createEvent, _t as pickClusterStepModels, bn as EventCategory, c as DEFAULT_CLUSTER_STEP_MODELS, hn as object, ht as overlayClusterStepSettings, in as parseJsonUnknown, it as inferModelProvider, j as YAMNET_TO_MACRO, l as DEFAULT_CLUSTER_STEP_SETTINGS, ln as array, m as DEVICE_BACKEND_TO_FORMAT, ot as loadContributionCapability, q as detectionPipelineCapability, rn as nodePin, sn as sleep, t as APPLE_SA_TO_MACRO, vn as string, vt as pickClusterStepSettings, w as PoolMemoryWatchdog, xt as pipelineExecutorCapability, yn as union, zt as errMsg } from "../dist-BwQxOtXy.mjs";
3
- import { o as readProcessCost } from "../node-BjScdHzE.mjs";
4
- import { a as ALL_PIPELINE_STEPS, c as getStep, d as landmarkPrecisionVerdict, l as getStepDefinition, n as resolveDefaultDetectionModel, o as ALL_STEPS, r as localFrameRegistry, s as getDefaultModelForFormat, u as resolveModelForFormat } from "../default-detection-model-DNsmwQx0.mjs";
2
+ import { $t as hydrateSchema, At as resolvePoolMemoryPolicy, Dt as resolveClusterStepModelId, H as defaultDeviceFor$1, Kt as BaseAddon, Lt as supportedRuntimes$1, Mt as runtimeDevices$1, Q as evaluateZoneRules, X as enumerateInferenceDevices, Zt as createEvent, _t as pickClusterStepModels, bn as EventCategory, c as DEFAULT_CLUSTER_STEP_MODELS, hn as object, ht as overlayClusterStepSettings, in as parseJsonUnknown, it as inferModelProvider, j as YAMNET_TO_MACRO, l as DEFAULT_CLUSTER_STEP_SETTINGS, ln as array, m as DEVICE_BACKEND_TO_FORMAT, ot as loadContributionCapability, q as detectionPipelineCapability, rn as nodePin, sn as sleep, t as APPLE_SA_TO_MACRO, vn as string, vt as pickClusterStepSettings, w as PoolMemoryWatchdog, xt as pipelineExecutorCapability, yn as union, zt as errMsg } from "../dist-But4XMDJ.mjs";
3
+ import { o as readProcessCost } from "../node-BHxRrsoX.mjs";
4
+ import { a as ALL_PIPELINE_STEPS, c as getStep, d as landmarkPrecisionVerdict, l as getStepDefinition, n as resolveDefaultDetectionModel, o as ALL_STEPS, r as localFrameRegistry, s as getDefaultModelForFormat, u as resolveModelForFormat } from "../default-detection-model-I8kuDTEi.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-62FAABqk.mjs";
6
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-C3-EOjjf.mjs";
7
7
  import * as os from "node:os";
8
8
  import * as fs from "node:fs";
9
9
  import * as path$1 from "node:path";
@@ -23916,6 +23916,14 @@ var MotionSourceEnum = _enum([
23916
23916
  */
23917
23917
  var MotionSourcesSchema = array(MotionSourceEnum);
23918
23918
  /**
23919
+ * Which root detectors a camera runs. Deliberately the SAME vocabulary
23920
+ * post-analysis already tags every detection with (`DetectionSource`) rather
23921
+ * than a second spelling of the same two ideas — the value an operator picks
23922
+ * here is the value that comes back on the track, the overlay and the debug
23923
+ * row.
23924
+ */
23925
+ var DetectionSourcesSchema = array(DetectionSourceSchema);
23926
+ /**
23919
23927
  * Input shape for `pipeline-runner.reportMotion` cap method. Exported
23920
23928
  * so cap-side consumers (the orchestrator forward, the runner addon's
23921
23929
  * cap implementation, tests) can reuse the type instead of redeclaring
@@ -24066,6 +24074,35 @@ var RunnerCameraConfigSchema = object({
24066
24074
  * events; the orchestrator forwards to `reportMotion`.
24067
24075
  */
24068
24076
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24077
+ /**
24078
+ * WHICH root detector runs for this camera. The detection counterpart of
24079
+ * {@link motionSources}, same shape and same discipline: a per-camera list
24080
+ * of sources the system understands, vendor-agnostic, owned here.
24081
+ *
24082
+ * - `pipeline` — this runner's own root step on decoded pixels (`steps`).
24083
+ * - `onboard` — the CAMERA's own detector, admitted only when it is named
24084
+ * here. Its boxes reach post-analysis on the same
24085
+ * `PipelineInferenceResult` payload as the pipeline's, so an onboard-born
24086
+ * track gets the same tracker, the same overlay and the same detail
24087
+ * subtree (face / plate / embedding).
24088
+ *
24089
+ * `['onboard']` alone is the REPLACEMENT: this runner's root step does not
24090
+ * run, and that is where a camera with a usable onboard detector buys back
24091
+ * its share of the accelerator. It saves the root inference, not the decode
24092
+ * — the detail subtree still needs pixels to cut crops from.
24093
+ *
24094
+ * A camera whose onboard detections carry no geometry cannot serve as a root
24095
+ * step at all (there is nothing to track), and the cap that knows this says
24096
+ * so on `native-object-detection.getOptions().geometry`. On Reolink that is
24097
+ * every battery camera: the boxes ride a sub-stream a battery camera never
24098
+ * attaches, so such a camera stays on `['pipeline']` and its onboard AI is
24099
+ * worth exactly what it already is — a wake signal with a class.
24100
+ *
24101
+ * Defaults to `['pipeline']`, which is byte-for-byte today's behaviour: a
24102
+ * vendor never turns a detector on for the operator, and neither does a
24103
+ * default.
24104
+ */
24105
+ detectionSources: DetectionSourcesSchema.default(["pipeline"]),
24069
24106
  pipelineEnabled: boolean().default(true),
24070
24107
  /** Ordered tree of video steps. Absent → runner skips video detection. */
24071
24108
  steps: array(PipelineStepInputSchema).readonly().optional(),
@@ -30124,31 +30161,38 @@ var NativeObjectDetectionStatusSchema = object({
30124
30161
  /**
30125
30162
  * Whether forwarding of onboard AI detections is enabled for this device.
30126
30163
  *
30127
- * The COLD-START default is the provider's, and it is not one value for
30128
- * every camera: a mains camera carries the boxed side-channel and its
30129
- * detections are usable subjects, so it defaults ON; a battery camera never
30130
- * attaches that channel, so the same toggle would buy it nothing but a write
30131
- * — it defaults OFF and an operator who wants it turns it on knowing what it
30132
- * costs. {@link NativeObjectDetectionOptionsSchema.geometry} is how the UI
30133
- * says which of the two a camera is.
30164
+ * Cold-start OFF on every camera. A vendor does not decide which detector a
30165
+ * camera runs — that is the operator's choice, and it is made where every
30166
+ * other detection choice is made. `geometry` on
30167
+ * {@link NativeObjectDetectionOptionsSchema} is how the form says what the
30168
+ * choice would buy this particular camera.
30134
30169
  */
30135
30170
  enabled: boolean()
30136
30171
  });
30137
30172
  /**
30138
- * What a camera's onboard detections actually CARRY.
30173
+ * WHEN a camera's onboard detections carry geometry.
30139
30174
  *
30140
- * `boxed` — the firmware ships a bounding box with the class, so a detection is
30141
- * a subject the pipeline can track, crop and score.
30142
- * `flag-only` — the firmware ships the class and nothing else. The pipeline
30143
- * needs geometry to make a subject out of it, so such a push reaches the
30144
- * tracker as motion and no further. On Reolink this is every battery camera:
30145
- * the boxes ride the BcMedia sub-stream, which a battery camera never attaches.
30175
+ * - `boxed` — always. The provider holds a standing channel for the boxes, so
30176
+ * a detection is a trackable subject whenever the camera sees one.
30177
+ * - `while-streaming` — only while some stream of this camera is already open.
30178
+ * The boxes ride the video's own side-channel rather than a feed of their
30179
+ * own, so they cost nothing and they exist only when something is pulling.
30180
+ * On Reolink this is every BATTERY camera: a persistent second feed is real
30181
+ * radio drain, but a camera that is awake is awake precisely because
30182
+ * something is in front of it, and its stream is already being pulled.
30183
+ * - `flag-only` — never. The firmware ships the class and nothing else; the
30184
+ * pipeline needs geometry to make a subject, so such a push reaches the
30185
+ * tracker as motion and no further.
30146
30186
  *
30147
30187
  * Reported and not inferred, because the operator's question in front of the
30148
- * toggle is "what do I get", and "a class with no box" and "a subject" are
30149
- * different answers (D14: the derived form is only as honest as `getOptions`).
30188
+ * picker is "what do I get", and these are three different answers (D14: the
30189
+ * derived form is only as honest as `getOptions`).
30150
30190
  */
30151
- var NativeObjectGeometryEnum = _enum(["boxed", "flag-only"]);
30191
+ var NativeObjectGeometryEnum = _enum([
30192
+ "boxed",
30193
+ "while-streaming",
30194
+ "flag-only"
30195
+ ]);
30152
30196
  var NativeObjectDetectionOptionsSchema = object({
30153
30197
  /** Classes this firmware can detect — the same list the status reports. */
30154
30198
  supportedClasses: array(NativeObjectClassEnum).readonly(),
@@ -23916,6 +23916,14 @@ var MotionSourceEnum = _enum([
23916
23916
  */
23917
23917
  var MotionSourcesSchema = array(MotionSourceEnum);
23918
23918
  /**
23919
+ * Which root detectors a camera runs. Deliberately the SAME vocabulary
23920
+ * post-analysis already tags every detection with (`DetectionSource`) rather
23921
+ * than a second spelling of the same two ideas — the value an operator picks
23922
+ * here is the value that comes back on the track, the overlay and the debug
23923
+ * row.
23924
+ */
23925
+ var DetectionSourcesSchema = array(DetectionSourceSchema);
23926
+ /**
23919
23927
  * Input shape for `pipeline-runner.reportMotion` cap method. Exported
23920
23928
  * so cap-side consumers (the orchestrator forward, the runner addon's
23921
23929
  * cap implementation, tests) can reuse the type instead of redeclaring
@@ -24066,6 +24074,35 @@ var RunnerCameraConfigSchema = object({
24066
24074
  * events; the orchestrator forwards to `reportMotion`.
24067
24075
  */
24068
24076
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24077
+ /**
24078
+ * WHICH root detector runs for this camera. The detection counterpart of
24079
+ * {@link motionSources}, same shape and same discipline: a per-camera list
24080
+ * of sources the system understands, vendor-agnostic, owned here.
24081
+ *
24082
+ * - `pipeline` — this runner's own root step on decoded pixels (`steps`).
24083
+ * - `onboard` — the CAMERA's own detector, admitted only when it is named
24084
+ * here. Its boxes reach post-analysis on the same
24085
+ * `PipelineInferenceResult` payload as the pipeline's, so an onboard-born
24086
+ * track gets the same tracker, the same overlay and the same detail
24087
+ * subtree (face / plate / embedding).
24088
+ *
24089
+ * `['onboard']` alone is the REPLACEMENT: this runner's root step does not
24090
+ * run, and that is where a camera with a usable onboard detector buys back
24091
+ * its share of the accelerator. It saves the root inference, not the decode
24092
+ * — the detail subtree still needs pixels to cut crops from.
24093
+ *
24094
+ * A camera whose onboard detections carry no geometry cannot serve as a root
24095
+ * step at all (there is nothing to track), and the cap that knows this says
24096
+ * so on `native-object-detection.getOptions().geometry`. On Reolink that is
24097
+ * every battery camera: the boxes ride a sub-stream a battery camera never
24098
+ * attaches, so such a camera stays on `['pipeline']` and its onboard AI is
24099
+ * worth exactly what it already is — a wake signal with a class.
24100
+ *
24101
+ * Defaults to `['pipeline']`, which is byte-for-byte today's behaviour: a
24102
+ * vendor never turns a detector on for the operator, and neither does a
24103
+ * default.
24104
+ */
24105
+ detectionSources: DetectionSourcesSchema.default(["pipeline"]),
24069
24106
  pipelineEnabled: boolean().default(true),
24070
24107
  /** Ordered tree of video steps. Absent → runner skips video detection. */
24071
24108
  steps: array(PipelineStepInputSchema).readonly().optional(),
@@ -30124,31 +30161,38 @@ var NativeObjectDetectionStatusSchema = object({
30124
30161
  /**
30125
30162
  * Whether forwarding of onboard AI detections is enabled for this device.
30126
30163
  *
30127
- * The COLD-START default is the provider's, and it is not one value for
30128
- * every camera: a mains camera carries the boxed side-channel and its
30129
- * detections are usable subjects, so it defaults ON; a battery camera never
30130
- * attaches that channel, so the same toggle would buy it nothing but a write
30131
- * — it defaults OFF and an operator who wants it turns it on knowing what it
30132
- * costs. {@link NativeObjectDetectionOptionsSchema.geometry} is how the UI
30133
- * says which of the two a camera is.
30164
+ * Cold-start OFF on every camera. A vendor does not decide which detector a
30165
+ * camera runs — that is the operator's choice, and it is made where every
30166
+ * other detection choice is made. `geometry` on
30167
+ * {@link NativeObjectDetectionOptionsSchema} is how the form says what the
30168
+ * choice would buy this particular camera.
30134
30169
  */
30135
30170
  enabled: boolean()
30136
30171
  });
30137
30172
  /**
30138
- * What a camera's onboard detections actually CARRY.
30173
+ * WHEN a camera's onboard detections carry geometry.
30139
30174
  *
30140
- * `boxed` — the firmware ships a bounding box with the class, so a detection is
30141
- * a subject the pipeline can track, crop and score.
30142
- * `flag-only` — the firmware ships the class and nothing else. The pipeline
30143
- * needs geometry to make a subject out of it, so such a push reaches the
30144
- * tracker as motion and no further. On Reolink this is every battery camera:
30145
- * the boxes ride the BcMedia sub-stream, which a battery camera never attaches.
30175
+ * - `boxed` — always. The provider holds a standing channel for the boxes, so
30176
+ * a detection is a trackable subject whenever the camera sees one.
30177
+ * - `while-streaming` — only while some stream of this camera is already open.
30178
+ * The boxes ride the video's own side-channel rather than a feed of their
30179
+ * own, so they cost nothing and they exist only when something is pulling.
30180
+ * On Reolink this is every BATTERY camera: a persistent second feed is real
30181
+ * radio drain, but a camera that is awake is awake precisely because
30182
+ * something is in front of it, and its stream is already being pulled.
30183
+ * - `flag-only` — never. The firmware ships the class and nothing else; the
30184
+ * pipeline needs geometry to make a subject, so such a push reaches the
30185
+ * tracker as motion and no further.
30146
30186
  *
30147
30187
  * Reported and not inferred, because the operator's question in front of the
30148
- * toggle is "what do I get", and "a class with no box" and "a subject" are
30149
- * different answers (D14: the derived form is only as honest as `getOptions`).
30188
+ * picker is "what do I get", and these are three different answers (D14: the
30189
+ * derived form is only as honest as `getOptions`).
30150
30190
  */
30151
- var NativeObjectGeometryEnum = _enum(["boxed", "flag-only"]);
30191
+ var NativeObjectGeometryEnum = _enum([
30192
+ "boxed",
30193
+ "while-streaming",
30194
+ "flag-only"
30195
+ ]);
30152
30196
  var NativeObjectDetectionOptionsSchema = object({
30153
30197
  /** Classes this firmware can detect — the same list the status reports. */
30154
30198
  supportedClasses: array(NativeObjectClassEnum).readonly(),
@@ -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-CoRJjU1W.js");
5
+ const require_dist = require("../dist-NX0e_oWp.js");
6
6
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
7
7
  let node_fs = require("node:fs");
8
8
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { $t as hydrateSchema, Kt as BaseAddon, Q as evaluateZoneRules, Yt as DeviceType, mt as motionDetectionCapability } from "../dist-BwQxOtXy.mjs";
1
+ import { $t as hydrateSchema, Kt as BaseAddon, Q as evaluateZoneRules, Yt as DeviceType, mt as motionDetectionCapability } from "../dist-But4XMDJ.mjs";
2
2
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
@@ -1,4 +1,4 @@
1
- import { Ht as buildFfmpegArgs, Vt as Fmp4BoxSplitter, Wt as isSoftwareDecode, zt as errMsg } from "./dist-BwQxOtXy.mjs";
1
+ import { Ht as buildFfmpegArgs, Vt as Fmp4BoxSplitter, Wt as isSoftwareDecode, zt as errMsg } from "./dist-But4XMDJ.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { realpathSync } from "node:fs";
4
4
  import path from "node:path";
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-CoRJjU1W.js");
2
+ const require_dist = require("./dist-NX0e_oWp.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  let node_fs = require("node:fs");
5
5
  node_fs = require_chunk.__toESM(node_fs, 1);
@@ -3,9 +3,9 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-CoRJjU1W.js");
7
- const require_node = require("../node-DvcGhYd4.js");
8
- const require_default_detection_model = require("../default-detection-model-DcB4--Xd.js");
6
+ const require_dist = require("../dist-NX0e_oWp.js");
7
+ const require_node = require("../node-BgM4n8D4.js");
8
+ const require_default_detection_model = require("../default-detection-model-CDhXxOJQ.js");
9
9
  const require_worker_protocol = require("../worker-protocol-B2MfQLlu.js");
10
10
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
11
11
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
@@ -2096,6 +2096,73 @@ function startSessionDecodePump(deps) {
2096
2096
  iterator.return().catch(() => {});
2097
2097
  };
2098
2098
  }
2099
+ /**
2100
+ * Read the camera's `detectionSources`.
2101
+ *
2102
+ * ABSENT is the pipeline — a runner or an attach older than the field behaves
2103
+ * exactly as it always did. EMPTY is not the same thing and must never be
2104
+ * widened into "everything": it is a camera an operator left with no root
2105
+ * detector, and inventing one for them is how a default acts without anybody
2106
+ * choosing it.
2107
+ */
2108
+ function planDetectionSources(sources) {
2109
+ if (sources === void 0) return {
2110
+ runsPipeline: true,
2111
+ runsOnboard: false
2112
+ };
2113
+ return {
2114
+ runsPipeline: sources.includes("pipeline"),
2115
+ runsOnboard: sources.includes("onboard")
2116
+ };
2117
+ }
2118
+ /** Clamp a denormalised box into the frame; a firmware box may exceed it. */
2119
+ function clamp(value, max) {
2120
+ return Math.max(0, Math.min(value, max));
2121
+ }
2122
+ /**
2123
+ * Pair the camera's last detections with a decoded frame, in the FRAME's pixel
2124
+ * space.
2125
+ *
2126
+ * The old converter denormalised against a nominal 1000×1000 when the push
2127
+ * carried no dimensions, and documented that consumers should treat a native
2128
+ * bbox as relative. That was survivable while nothing cut pixels from it. Here
2129
+ * the boxes travel with a real frame and a real handle, so they are scaled to
2130
+ * that frame — the same space every other detection on this plane lives in.
2131
+ */
2132
+ function onboardRootDetections(slot, frame) {
2133
+ if (slot === null || slot.detections.length === 0) return { kind: "none" };
2134
+ const ageMs = Math.abs(frame.timestamp - slot.at);
2135
+ if (ageMs > 1e3) return {
2136
+ kind: "expired",
2137
+ ageMs
2138
+ };
2139
+ const boxed = slot.detections.filter((d) => d.bbox != null);
2140
+ if (boxed.length === 0) return {
2141
+ kind: "no-geometry",
2142
+ classes: slot.detections.map((d) => d.class)
2143
+ };
2144
+ return {
2145
+ kind: "paired",
2146
+ detections: boxed.map((d, i) => {
2147
+ const [nx, ny, nw, nh] = d.bbox;
2148
+ const x = clamp(nx * frame.width, frame.width);
2149
+ const y = clamp(ny * frame.height, frame.height);
2150
+ return {
2151
+ id: `onboard-${String(slot.at)}-${String(i)}`,
2152
+ kind: "first-level",
2153
+ macroClass: d.class,
2154
+ score: d.confidence ?? 1,
2155
+ labels: [],
2156
+ bbox: {
2157
+ x,
2158
+ y,
2159
+ width: clamp(nw * frame.width, frame.width - x),
2160
+ height: clamp(nh * frame.height, frame.height - y)
2161
+ }
2162
+ };
2163
+ })
2164
+ };
2165
+ }
2099
2166
  //#endregion
2100
2167
  //#region src/pipeline-runner/bench-step-schema.ts
2101
2168
  /**
@@ -5644,6 +5711,8 @@ var PipelineRunner = class {
5644
5711
  cameras = /* @__PURE__ */ new Map();
5645
5712
  semaphore;
5646
5713
  resultCallbacks = [];
5714
+ /** Last report per `deviceId:reason` for {@link noteOnboardRootIdle}. */
5715
+ onboardIdleReportedAt = /* @__PURE__ */ new Map();
5647
5716
  defaultRoundRobinKeys = [];
5648
5717
  defaultRoundRobinIndex = 0;
5649
5718
  intervalHandle = null;
@@ -5724,6 +5793,7 @@ var PipelineRunner = class {
5724
5793
  const initialPhase = registration.detectionMode === "disabled" ? "idle" : registration.detectionMode === "always-on" ? "active" : "watching";
5725
5794
  const state = {
5726
5795
  registration,
5796
+ onboardSlot: null,
5727
5797
  motionQueue,
5728
5798
  detectionQueue,
5729
5799
  preRollQueue: new PreRollLane({
@@ -6200,6 +6270,15 @@ var PipelineRunner = class {
6200
6270
  const { frame, handle } = entry;
6201
6271
  state.inflight += 1;
6202
6272
  const enqueuedAt = frame._enqueuedAt ?? pickedAt;
6273
+ const plan = planDetectionSources(state.registration.detectionSources);
6274
+ if (!plan.runsPipeline) {
6275
+ try {
6276
+ await this.processOnboardRoot(deviceId, entry, state, streamType, plan);
6277
+ } finally {
6278
+ state.inflight -= 1;
6279
+ }
6280
+ return;
6281
+ }
6203
6282
  const rawRelease = await this.semaphore.acquire();
6204
6283
  let released = false;
6205
6284
  const release = () => {
@@ -6223,7 +6302,7 @@ var PipelineRunner = class {
6223
6302
  state.processedCount++;
6224
6303
  if (result) {
6225
6304
  if (result.shed === true) state.shedFrames++;
6226
- await this.notifyCallbacks(deviceId, frame, result, streamType, handle);
6305
+ await this.notifyCallbacks(deviceId, frame, result, streamType, handle, "pipeline");
6227
6306
  frameReleaseReason = "success";
6228
6307
  const emittedAt = Date.now();
6229
6308
  const capturedAt = frame.capturedAt;
@@ -6250,6 +6329,96 @@ var PipelineRunner = class {
6250
6329
  }
6251
6330
  }
6252
6331
  /**
6332
+ * The CAMERA is this camera's root step.
6333
+ *
6334
+ * Same shape as the pipeline path and deliberately so: one decoded frame, one
6335
+ * `FrameResult`, the same `notifyCallbacks`, the same handle, the same
6336
+ * retention release. Everything downstream — subject tiles, birth evidence,
6337
+ * the `detailSteps` announce, the overlay, the tracker — cannot tell which
6338
+ * detector produced the boxes, which is the entire point. What it does NOT do
6339
+ * is take an inference permit: the accelerator is never asked.
6340
+ *
6341
+ * A frame with no fresh onboard detection produces NO result rather than an
6342
+ * empty one. An empty `FrameResult` is a positive statement ("I looked and
6343
+ * there was nothing"), and this path did not look — it decoded a frame while
6344
+ * the camera happened to be silent. Emitting emptiness would tell the
6345
+ * tracker every silent frame is evidence of absence and coast every subject
6346
+ * to death between two pushes.
6347
+ */
6348
+ async processOnboardRoot(deviceId, entry, state, streamType, plan) {
6349
+ const { frame, handle } = entry;
6350
+ let frameReleaseReason = "drop";
6351
+ try {
6352
+ if (!plan.runsOnboard) {
6353
+ this.noteOnboardRootIdle(deviceId, "no-source");
6354
+ return;
6355
+ }
6356
+ const pairing = onboardRootDetections(state.onboardSlot, {
6357
+ timestamp: Date.now(),
6358
+ width: frame.width,
6359
+ height: frame.height
6360
+ });
6361
+ if (pairing.kind !== "paired") {
6362
+ this.noteOnboardRootIdle(deviceId, pairing.kind);
6363
+ return;
6364
+ }
6365
+ state.onboardSlot = null;
6366
+ state.processedCount++;
6367
+ const result = {
6368
+ kind: "frame",
6369
+ frameId: `onboard-${String(deviceId)}-${String(frame.timestamp)}`,
6370
+ deviceId,
6371
+ timestamp: Date.now(),
6372
+ width: frame.width,
6373
+ height: frame.height,
6374
+ detections: pairing.detections
6375
+ };
6376
+ state.lastResultDetections = pairing.detections.length;
6377
+ await this.notifyCallbacks(deviceId, frame, result, streamType, handle, "onboard");
6378
+ frameReleaseReason = "success";
6379
+ } catch {
6380
+ frameReleaseReason = "error";
6381
+ } finally {
6382
+ try {
6383
+ if (frameReleaseReason === "success" && handle && isContinuousRetainEnabled()) await this.config.hydrateRetainedFrame?.(handle);
6384
+ } catch {}
6385
+ if (handle) this.config.releaseRetention?.(handle, frameReleaseReason);
6386
+ if (frame.frameRef) this.config.releaseFrameRef?.(frame.frameRef, frameReleaseReason);
6387
+ }
6388
+ }
6389
+ /**
6390
+ * Report — once per camera per interval — that the onboard root step decoded
6391
+ * a frame and produced nothing, with WHICH of the reasons it was. Sampled
6392
+ * because it fires at detection fps on a silent camera, which is most of the
6393
+ * time and is not itself a fault.
6394
+ */
6395
+ noteOnboardRootIdle(deviceId, reason) {
6396
+ const now = Date.now();
6397
+ const key = `${String(deviceId)}:${reason}`;
6398
+ if (now - (this.onboardIdleReportedAt.get(key) ?? 0) < 6e4) return;
6399
+ this.onboardIdleReportedAt.set(key, now);
6400
+ this.logger?.info("onboard root step produced nothing for a decoded frame", {
6401
+ tags: { deviceId },
6402
+ meta: { reason }
6403
+ });
6404
+ }
6405
+ /**
6406
+ * The camera spoke. Held until a decoded frame can be paired with it.
6407
+ *
6408
+ * Gated by the CALLER on `detectionSources` — this method is the mechanism,
6409
+ * not the policy, and a camera that does not name `onboard` never reaches it.
6410
+ */
6411
+ reportNativeDetection(deviceId, detections, frameWidth, frameHeight) {
6412
+ const state = this.cameras.get(deviceId);
6413
+ if (!state) return;
6414
+ state.onboardSlot = {
6415
+ at: Date.now(),
6416
+ detections,
6417
+ ...frameWidth !== void 0 ? { frameWidth } : {},
6418
+ ...frameHeight !== void 0 ? { frameHeight } : {}
6419
+ };
6420
+ }
6421
+ /**
6253
6422
  * Await `processFrame` with a hard bound. On expiry the permit is released
6254
6423
  * immediately (via the caller's release-once closure) and {@link TIMED_OUT}
6255
6424
  * is returned; the underlying call is left to settle into the void, since
@@ -6334,9 +6503,9 @@ var PipelineRunner = class {
6334
6503
  });
6335
6504
  }
6336
6505
  }
6337
- async notifyCallbacks(deviceId, frame, result, streamType, handle) {
6506
+ async notifyCallbacks(deviceId, frame, result, streamType, handle, source) {
6338
6507
  for (const callback of this.resultCallbacks) try {
6339
- await callback(deviceId, frame, result, streamType, handle);
6508
+ await callback(deviceId, frame, result, streamType, handle, source);
6340
6509
  } catch {}
6341
6510
  }
6342
6511
  pickNextDetectionFrame() {
@@ -7160,6 +7329,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
7160
7329
  /** Last runtime-label failure, so only a CHANGE is logged (D463). */
7161
7330
  lastRuntimeInfoFailure = null;
7162
7331
  unsubMotionEvents = null;
7332
+ unsubNativeDetections = null;
7163
7333
  /** Devices we have positively observed reporting `battery.sleeping: true`.
7164
7334
  * Absent = unknown or awake; both mean "do not gate" (D49). Fed only by
7165
7335
  * `BatteryOnStatusChanged`, so consulting it costs nothing and can never
@@ -7416,11 +7586,11 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
7416
7586
  this.runner.onDetectionStreamChange((deviceId, action) => {
7417
7587
  this.handleDetectionStreamChange(deviceId, action);
7418
7588
  });
7419
- this.runner.onResult(async (deviceId, frame, result, _streamType, handle) => {
7589
+ this.runner.onResult(async (deviceId, frame, result, _streamType, handle, source) => {
7420
7590
  this.retention?.noteInferenceResult(deviceId, handle, result);
7421
7591
  this.cutSubjectTiles(deviceId, result, handle);
7422
7592
  const carried = await this.attachBirthEvidence(deviceId, frame, result);
7423
- this.emitInferenceResult(deviceId, frame, carried, handle);
7593
+ this.emitInferenceResult(deviceId, frame, carried, handle, source);
7424
7594
  const detectionCount = result.detections?.length ?? 0;
7425
7595
  this.runner?.noteDetectionResult(deviceId, detectionCount);
7426
7596
  if (detectionCount > 0 && this.occupancyBurstInFlight.has(deviceId)) this.occupancyBurstFound.add(deviceId);
@@ -7444,13 +7614,26 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
7444
7614
  if (source === "analyzer" && cameraOwnsMotionViaSensor(attachment.config.motionSources)) return;
7445
7615
  this.runner?.reportMotion(deviceId, data.detected, source, data.regions ? [...data.regions] : void 0);
7446
7616
  });
7447
- if (this.ctx.eventBus) this.unsubBatteryEvents = this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.BatteryOnStatusChanged }, (event) => {
7448
- const data = event.data;
7449
- const deviceId = data.deviceId;
7450
- if (typeof deviceId !== "number") return;
7451
- if (data.status?.sleeping === true) this.sleepingBatteryDevices.add(deviceId);
7452
- else this.sleepingBatteryDevices.delete(deviceId);
7453
- });
7617
+ if (this.ctx.eventBus) {
7618
+ this.unsubNativeDetections = this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.DetectionCameraNative }, (event) => {
7619
+ const data = event.data;
7620
+ const deviceId = data.cameraId;
7621
+ if (typeof deviceId !== "number") return;
7622
+ const attachment = this.attached.get(deviceId);
7623
+ if (!attachment) return;
7624
+ if (!planDetectionSources(attachment.config.detectionSources).runsOnboard) return;
7625
+ const detections = data.detections;
7626
+ if (!detections || detections.length === 0) return;
7627
+ this.runner?.reportNativeDetection(deviceId, detections, data.frameWidth, data.frameHeight);
7628
+ });
7629
+ this.unsubBatteryEvents = this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.BatteryOnStatusChanged }, (event) => {
7630
+ const data = event.data;
7631
+ const deviceId = data.deviceId;
7632
+ if (typeof deviceId !== "number") return;
7633
+ if (data.status?.sleeping === true) this.sleepingBatteryDevices.add(deviceId);
7634
+ else this.sleepingBatteryDevices.delete(deviceId);
7635
+ });
7636
+ }
7454
7637
  this.metricsSnapshotTimer = setInterval(() => this.emitMetricsSnapshot(), METRICS_SNAPSHOT_INTERVAL_MS);
7455
7638
  return {
7456
7639
  providers: [
@@ -7499,6 +7682,10 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
7499
7682
  this.unsubMotionEvents();
7500
7683
  this.unsubMotionEvents = null;
7501
7684
  }
7685
+ if (this.unsubNativeDetections) {
7686
+ this.unsubNativeDetections();
7687
+ this.unsubNativeDetections = null;
7688
+ }
7502
7689
  if (this.unsubBatteryEvents) {
7503
7690
  this.unsubBatteryEvents();
7504
7691
  this.unsubBatteryEvents = null;
@@ -10611,7 +10798,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
10611
10798
  teardown();
10612
10799
  }
10613
10800
  }
10614
- emitInferenceResult(deviceId, frame, result, handle) {
10801
+ emitInferenceResult(deviceId, frame, result, handle, source) {
10615
10802
  if (!this.ctx?.eventBus) return;
10616
10803
  const capturedAt = frame.capturedAt;
10617
10804
  const detailSteps = this.attached.get(deviceId)?.detailSteps;
@@ -10622,7 +10809,8 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
10622
10809
  frameHandle: handle,
10623
10810
  emittedAt: Date.now(),
10624
10811
  ...typeof capturedAt === "number" && capturedAt > 0 ? { capturedAt } : {},
10625
- ...detailSteps && detailSteps.length > 0 ? { detailSteps } : {}
10812
+ ...detailSteps && detailSteps.length > 0 ? { detailSteps } : {},
10813
+ source
10626
10814
  };
10627
10815
  this.ctx.eventBus.emit(require_dist.createEvent(require_dist.EventCategory.PipelineInferenceResult, {
10628
10816
  type: "device",