@camstack/addon-pipeline 1.2.244 → 1.2.246

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 (33) 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-CPwmR_XE.js → default-detection-model-BokEDZLK.js} +42 -1
  4. package/dist/{default-detection-model-Be8-TzIO.mjs → default-detection-model-b1HWNGyF.mjs} +31 -2
  5. package/dist/detection-pipeline/index.js +5 -16
  6. package/dist/detection-pipeline/index.mjs +5 -16
  7. package/dist/{dist-C1PeUaZn.js → dist-FF-KPXS7.js} +97 -10
  8. package/dist/{dist-D5j2hIVU.mjs → dist-XAp9FVoN.mjs} +97 -10
  9. package/dist/motion-wasm/index.js +1 -1
  10. package/dist/motion-wasm/index.mjs +1 -1
  11. package/dist/{node-DHN6cJXp.js → node-C-KslKQf.js} +1 -1
  12. package/dist/{node-CpJcoSCa.mjs → node-umwnvSsV.mjs} +1 -1
  13. package/dist/pipeline-runner/index.js +38 -24
  14. package/dist/pipeline-runner/index.mjs +38 -24
  15. package/dist/{process-memory-CYMg9OKh.js → process-memory-ByvPOmQm.js} +1 -1
  16. package/dist/{process-memory-DO-CvzV3.mjs → process-memory-DkBPSh44.mjs} +1 -1
  17. package/dist/recorder/index.js +2 -9
  18. package/dist/recorder/index.mjs +2 -9
  19. package/dist/{segment-demux-js-B7Ot40Oz.js → segment-demux-js-BCzxobGz.js} +1 -1
  20. package/dist/{segment-demux-js-D6luJnWU.mjs → segment-demux-js-BodSgaxj.mjs} +1 -1
  21. package/dist/stream-broker/_stub.js +2 -2
  22. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CMr_02iL.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C2-mCqUf.mjs} +3 -3
  23. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DVqDp5VD.mjs +26 -0
  24. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CJunbWSo.mjs +26 -0
  25. package/dist/stream-broker/demux-worker-child.js +1 -1
  26. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  27. package/dist/stream-broker/{hostInit-Df8n-1_5.mjs → hostInit-BVEP1sys.mjs} +3 -3
  28. package/dist/stream-broker/index.js +567 -52
  29. package/dist/stream-broker/index.mjs +567 -52
  30. package/dist/stream-broker/remoteEntry.js +1 -1
  31. package/package.json +2 -2
  32. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DhmYsj50.mjs +0 -26
  33. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-m_mN1dE-.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-C1PeUaZn.js");
7
- const require_process_memory = require("../process-memory-CYMg9OKh.js");
6
+ const require_dist = require("../dist-FF-KPXS7.js");
7
+ const require_process_memory = require("../process-memory-ByvPOmQm.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, Jt as audioChunkBytesPerSample, Lt as errMsg, N as audioAnalysisCapability, Ot as resolvePoolMemoryPolicy, P as audioAnalyzerCapability, Qt as expandAudioChunkToF32le, Wt as BaseAddon, bn as EventCategory, n as AUDIO_BACKEND_CHOICES, ot as mapAudioLabelToMacro, rn as nodePin, s as DEFAULT_AUDIO_ANALYZER_CONFIG, w as PoolMemoryWatchdog, y as HF_BASE_URL } from "../dist-D5j2hIVU.mjs";
3
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DO-CvzV3.mjs";
2
+ import { $t as hydrateSchema, Jt as audioChunkBytesPerSample, Lt as errMsg, N as audioAnalysisCapability, Ot as resolvePoolMemoryPolicy, P as audioAnalyzerCapability, Qt as expandAudioChunkToF32le, Wt as BaseAddon, bn as EventCategory, n as AUDIO_BACKEND_CHOICES, ot as mapAudioLabelToMacro, rn as nodePin, s as DEFAULT_AUDIO_ANALYZER_CONFIG, w as PoolMemoryWatchdog, y as HF_BASE_URL } from "../dist-XAp9FVoN.mjs";
3
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DkBPSh44.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-C1PeUaZn.js");
1
+ const require_dist = require("./dist-FF-KPXS7.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  //#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
4
4
  /**
@@ -2114,6 +2114,35 @@ var localFrameRegistry = new LocalFrameRegistry({
2114
2114
  maxBytes: envPositiveInt("CAMSTACK_LOCAL_FRAME_BUDGET_MB", DEFAULT_MAX_BYTES / 1048576) * 1048576
2115
2115
  });
2116
2116
  //#endregion
2117
+ //#region src/detection-pipeline/pipeline/macro-gate.ts
2118
+ function capitalize(s) {
2119
+ if (s.length === 0) return s;
2120
+ return s.charAt(0).toUpperCase() + s.slice(1);
2121
+ }
2122
+ /** Apply the operator's class list and per-macro confidence floor. */
2123
+ function macroGateVerdict(macroClass, score, settings) {
2124
+ if (!settings) return "pass";
2125
+ const enabled = settings["enabledMacroClasses"];
2126
+ if (Array.isArray(enabled) && enabled.length > 0) {
2127
+ if (!enabled.includes(macroClass)) return "class-filter";
2128
+ }
2129
+ const perMacroThreshold = settings[`minConfidence${capitalize(macroClass)}`];
2130
+ if (typeof perMacroThreshold === "number" && score < perMacroThreshold) return "below-threshold";
2131
+ return "pass";
2132
+ }
2133
+ /**
2134
+ * The operator's gate, read off the ROOT step.
2135
+ *
2136
+ * The root is the first ENABLED step — the same one `executor.ts` picks
2137
+ * (`enabledSteps[0]`) — because that is the step whose settings the device
2138
+ * UI writes `enabledMacroClasses` and `minConfidence<Macro>` into. `undefined`
2139
+ * when there is no enabled step or it carries no settings, which the gate
2140
+ * itself reads as "pass everything": an absent gate must never mute a camera.
2141
+ */
2142
+ function rootObjectGate(steps) {
2143
+ return (steps?.find((s) => s.enabled !== false))?.settings;
2144
+ }
2145
+ //#endregion
2117
2146
  //#region src/detection-pipeline/default-detection-model.ts
2118
2147
  /** The object-detection step id — the only slot this resolver applies to. */
2119
2148
  var OBJECT_DETECTION_STEP_ID = "object-detection";
@@ -2244,6 +2273,12 @@ Object.defineProperty(exports, "localFrameRegistry", {
2244
2273
  return localFrameRegistry;
2245
2274
  }
2246
2275
  });
2276
+ Object.defineProperty(exports, "macroGateVerdict", {
2277
+ enumerable: true,
2278
+ get: function() {
2279
+ return macroGateVerdict;
2280
+ }
2281
+ });
2247
2282
  Object.defineProperty(exports, "resolveDefaultDetectionModel", {
2248
2283
  enumerable: true,
2249
2284
  get: function() {
@@ -2262,3 +2297,9 @@ Object.defineProperty(exports, "resolveModelForFormat", {
2262
2297
  return resolveModelForFormat;
2263
2298
  }
2264
2299
  });
2300
+ Object.defineProperty(exports, "rootObjectGate", {
2301
+ enumerable: true,
2302
+ get: function() {
2303
+ return rootObjectGate;
2304
+ }
2305
+ });
@@ -1,4 +1,4 @@
1
- import { F as audioKindId, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS, tt as hfModelUrl } from "./dist-D5j2hIVU.mjs";
1
+ import { F as audioKindId, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS, tt as hfModelUrl } from "./dist-XAp9FVoN.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  //#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
4
4
  /**
@@ -2114,6 +2114,35 @@ var localFrameRegistry = new LocalFrameRegistry({
2114
2114
  maxBytes: envPositiveInt("CAMSTACK_LOCAL_FRAME_BUDGET_MB", DEFAULT_MAX_BYTES / 1048576) * 1048576
2115
2115
  });
2116
2116
  //#endregion
2117
+ //#region src/detection-pipeline/pipeline/macro-gate.ts
2118
+ function capitalize(s) {
2119
+ if (s.length === 0) return s;
2120
+ return s.charAt(0).toUpperCase() + s.slice(1);
2121
+ }
2122
+ /** Apply the operator's class list and per-macro confidence floor. */
2123
+ function macroGateVerdict(macroClass, score, settings) {
2124
+ if (!settings) return "pass";
2125
+ const enabled = settings["enabledMacroClasses"];
2126
+ if (Array.isArray(enabled) && enabled.length > 0) {
2127
+ if (!enabled.includes(macroClass)) return "class-filter";
2128
+ }
2129
+ const perMacroThreshold = settings[`minConfidence${capitalize(macroClass)}`];
2130
+ if (typeof perMacroThreshold === "number" && score < perMacroThreshold) return "below-threshold";
2131
+ return "pass";
2132
+ }
2133
+ /**
2134
+ * The operator's gate, read off the ROOT step.
2135
+ *
2136
+ * The root is the first ENABLED step — the same one `executor.ts` picks
2137
+ * (`enabledSteps[0]`) — because that is the step whose settings the device
2138
+ * UI writes `enabledMacroClasses` and `minConfidence<Macro>` into. `undefined`
2139
+ * when there is no enabled step or it carries no settings, which the gate
2140
+ * itself reads as "pass everything": an absent gate must never mute a camera.
2141
+ */
2142
+ function rootObjectGate(steps) {
2143
+ return (steps?.find((s) => s.enabled !== false))?.settings;
2144
+ }
2145
+ //#endregion
2117
2146
  //#region src/detection-pipeline/default-detection-model.ts
2118
2147
  /** The object-detection step id — the only slot this resolver applies to. */
2119
2148
  var OBJECT_DETECTION_STEP_ID = "object-detection";
@@ -2196,4 +2225,4 @@ function resolveDefaultDetectionModel(backend, device, format, getStepDef = getS
2196
2225
  return getDefaultModelForFormatFromDef(def, format);
2197
2226
  }
2198
2227
  //#endregion
2199
- export { ALL_PIPELINE_STEPS as a, getStep as c, landmarkPrecisionVerdict as d, resolveFrameViewGeometry as i, getStepDefinition as l, resolveDefaultDetectionModel as n, ALL_STEPS as o, localFrameRegistry as r, getDefaultModelForFormat as s, OBJECT_DETECTION_STEP_ID as t, resolveModelForFormat as u };
2228
+ export { localFrameRegistry as a, ALL_STEPS as c, getStepDefinition as d, resolveModelForFormat as f, rootObjectGate as i, getDefaultModelForFormat as l, resolveDefaultDetectionModel as n, resolveFrameViewGeometry as o, landmarkPrecisionVerdict as p, macroGateVerdict as r, ALL_PIPELINE_STEPS as s, OBJECT_DETECTION_STEP_ID as t, getStep as u };
@@ -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-C1PeUaZn.js");
7
- const require_node = require("../node-DHN6cJXp.js");
8
- const require_default_detection_model = require("../default-detection-model-CPwmR_XE.js");
6
+ const require_dist = require("../dist-FF-KPXS7.js");
7
+ const require_node = require("../node-C-KslKQf.js");
8
+ const require_default_detection_model = require("../default-detection-model-BokEDZLK.js");
9
9
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
10
- const require_process_memory = require("../process-memory-CYMg9OKh.js");
10
+ const require_process_memory = require("../process-memory-ByvPOmQm.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");
@@ -5891,20 +5891,9 @@ var PipelineExecutor = class {
5891
5891
  * - `minConfidence<Macro>`: number (e.g. `minConfidencePerson: 0.5`)
5892
5892
  */
5893
5893
  macroFilterVerdict(macroClass, score, settings) {
5894
- if (!settings) return "pass";
5895
- const enabled = settings["enabledMacroClasses"];
5896
- if (Array.isArray(enabled) && enabled.length > 0) {
5897
- if (!enabled.includes(macroClass)) return "class-filter";
5898
- }
5899
- const perMacroThreshold = settings[`minConfidence${capitalize(macroClass)}`];
5900
- if (typeof perMacroThreshold === "number" && score < perMacroThreshold) return "below-threshold";
5901
- return "pass";
5894
+ return require_default_detection_model.macroGateVerdict(macroClass, score, settings);
5902
5895
  }
5903
5896
  };
5904
- function capitalize(s) {
5905
- if (s.length === 0) return s;
5906
- return s.charAt(0).toUpperCase() + s.slice(1);
5907
- }
5908
5897
  //#endregion
5909
5898
  //#region src/detection-pipeline/pipeline/native-crop-compose.ts
5910
5899
  /** Clamp `v` into `[lo, hi]`. */
@@ -1,9 +1,9 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $t as hydrateSchema, At as runtimeDevices$1, Ft as supportedRuntimes$1, G as detectionPipelineCapability, J as enumerateInferenceDevices, Lt as errMsg, Ot as resolvePoolMemoryPolicy, Tt as resolveClusterStepModelId, V as defaultDeviceFor$1, Wt as BaseAddon, X as evaluateZoneRules, Yt as createEvent, bn as EventCategory, c as DEFAULT_CLUSTER_STEP_MODELS, gt as pickClusterStepSettings, hn as object, ht as pickClusterStepModels, in as parseJsonUnknown, it as loadContributionCapability, j as YAMNET_TO_MACRO, l as DEFAULT_CLUSTER_STEP_SETTINGS, ln as array, m as DEVICE_BACKEND_TO_FORMAT, nt as inferModelProvider, pt as overlayClusterStepSettings, rn as nodePin, sn as sleep, t as APPLE_SA_TO_MACRO, vn as string, w as PoolMemoryWatchdog, yn as union, yt as pipelineExecutorCapability } from "../dist-D5j2hIVU.mjs";
3
- import { o as readProcessCost } from "../node-CpJcoSCa.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-Be8-TzIO.mjs";
2
+ import { $t as hydrateSchema, At as runtimeDevices$1, Ft as supportedRuntimes$1, G as detectionPipelineCapability, J as enumerateInferenceDevices, Lt as errMsg, Ot as resolvePoolMemoryPolicy, Tt as resolveClusterStepModelId, V as defaultDeviceFor$1, Wt as BaseAddon, X as evaluateZoneRules, Yt as createEvent, bn as EventCategory, c as DEFAULT_CLUSTER_STEP_MODELS, gt as pickClusterStepSettings, hn as object, ht as pickClusterStepModels, in as parseJsonUnknown, it as loadContributionCapability, j as YAMNET_TO_MACRO, l as DEFAULT_CLUSTER_STEP_SETTINGS, ln as array, m as DEVICE_BACKEND_TO_FORMAT, nt as inferModelProvider, pt as overlayClusterStepSettings, rn as nodePin, sn as sleep, t as APPLE_SA_TO_MACRO, vn as string, w as PoolMemoryWatchdog, yn as union, yt as pipelineExecutorCapability } from "../dist-XAp9FVoN.mjs";
3
+ import { o as readProcessCost } from "../node-umwnvSsV.mjs";
4
+ import { a as localFrameRegistry, c as ALL_STEPS, d as getStepDefinition, f as resolveModelForFormat, l as getDefaultModelForFormat, n as resolveDefaultDetectionModel, p as landmarkPrecisionVerdict, r as macroGateVerdict, s as ALL_PIPELINE_STEPS, u as getStep } from "../default-detection-model-b1HWNGyF.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DO-CvzV3.mjs";
6
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DkBPSh44.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";
@@ -5884,20 +5884,9 @@ var PipelineExecutor = class {
5884
5884
  * - `minConfidence<Macro>`: number (e.g. `minConfidencePerson: 0.5`)
5885
5885
  */
5886
5886
  macroFilterVerdict(macroClass, score, settings) {
5887
- if (!settings) return "pass";
5888
- const enabled = settings["enabledMacroClasses"];
5889
- if (Array.isArray(enabled) && enabled.length > 0) {
5890
- if (!enabled.includes(macroClass)) return "class-filter";
5891
- }
5892
- const perMacroThreshold = settings[`minConfidence${capitalize(macroClass)}`];
5893
- if (typeof perMacroThreshold === "number" && score < perMacroThreshold) return "below-threshold";
5894
- return "pass";
5887
+ return macroGateVerdict(macroClass, score, settings);
5895
5888
  }
5896
5889
  };
5897
- function capitalize(s) {
5898
- if (s.length === 0) return s;
5899
- return s.charAt(0).toUpperCase() + s.slice(1);
5900
- }
5901
5890
  //#endregion
5902
5891
  //#region src/detection-pipeline/pipeline/native-crop-compose.ts
5903
5892
  /** Clamp `v` into `[lo, hi]`. */
@@ -5360,7 +5360,7 @@ var ZodIssueCode = {
5360
5360
  var ZodFirstPartyTypeKind;
5361
5361
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5362
5362
  //#endregion
5363
- //#region ../types/dist/sleep-e0RweZzn.mjs
5363
+ //#region ../types/dist/sleep-BDR76Ykr.mjs
5364
5364
  /**
5365
5365
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5366
5366
  * window to float samples (D455).
@@ -20514,6 +20514,48 @@ var NcAlarmConfigSchema = object({
20514
20514
  settings: NcAlarmSettingsSchema,
20515
20515
  coverage: array(NcAlarmModeCoverageSchema)
20516
20516
  });
20517
+ /**
20518
+ * ONE rule's demand on ONE camera's clip ring.
20519
+ *
20520
+ * A rule, not a camera: the broker takes the MAX over the asks that reach a
20521
+ * camera, so the answer stays a faithful description of the rules and the
20522
+ * bounding (the byte budget, the broker's own ceiling) stays where the cost
20523
+ * lives. A camera that appears in no ask is being told **nothing** — which is
20524
+ * a different thing from never having been told, and only the envelope
20525
+ * (`rulesLoaded`) can tell those apart.
20526
+ */
20527
+ var NcClipRetentionAskSchema = object({
20528
+ /**
20529
+ * The camera this ask is about. **Absent = every camera**, which is what a
20530
+ * rule with no `conditions.devices` means: it can fire anywhere, so it is
20531
+ * asking everywhere.
20532
+ */
20533
+ deviceId: number().int().nonnegative().optional(),
20534
+ /** Seconds of history the rule needs held for it. Never zero — a rule that
20535
+ * needs nothing produces no ask at all. */
20536
+ seconds: number().min(0).max(60),
20537
+ /** The profile the rule cuts from, when it named one. Absent = the cheapest
20538
+ * assigned, which is what the cut defaults to. */
20539
+ profile: CamProfileSchema.optional(),
20540
+ /** Who is asking — so a retention the operator did not expect names a rule. */
20541
+ ruleId: string(),
20542
+ ruleName: string(),
20543
+ /** Why this many seconds: the rule's own window, or the occupancy ceiling. */
20544
+ reason: _enum(["window", "occupancy"])
20545
+ });
20546
+ /**
20547
+ * The whole answer, with the one bit that keeps absence from reading as zero.
20548
+ *
20549
+ * `rulesLoaded` is false until the rule ledger has completed a load at least
20550
+ * once. A centre that is up but has not read its rules yet answers with an
20551
+ * empty ask list that means nothing at all — applying it would drop every
20552
+ * camera's ring to zero for the first events after a restart, which is the
20553
+ * footage this mechanism exists to keep.
20554
+ */
20555
+ var NcClipRetentionPlanSchema = object({
20556
+ rulesLoaded: boolean(),
20557
+ asks: array(NcClipRetentionAskSchema).readonly()
20558
+ });
20517
20559
  method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), method(object({ ruleId: string() }), object({ rule: NcRuleSchema.nullable() }), { auth: "admin" }), method(object({ rule: NcRuleInputSchema }), object({ rule: NcRuleSchema }), {
20518
20560
  kind: "mutation",
20519
20561
  auth: "admin",
@@ -20534,7 +20576,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20534
20576
  }), object({ success: literal(true) }), {
20535
20577
  kind: "mutation",
20536
20578
  auth: "admin"
20537
- }), method(object({}), object({ mutedDeviceIds: array(number().int()).readonly() }), { auth: "admin" }), method(object({
20579
+ }), method(object({}), NcClipRetentionPlanSchema, { auth: "admin" }), method(object({}), object({ mutedDeviceIds: array(number().int()).readonly() }), { auth: "admin" }), method(object({
20538
20580
  deviceId: number().int(),
20539
20581
  muted: boolean()
20540
20582
  }), object({ success: literal(true) }), {
@@ -21863,13 +21905,26 @@ var TrackAudioLabelSchema = object({
21863
21905
  * - `audio` — an audio event on the camera itself that was anomalous for
21864
21906
  * THAT camera, loud, and heard while nothing visual was happening (D62).
21865
21907
  *
21908
+ * - `onboard` — the CAMERA's own firmware, paired with a decoded frame in
21909
+ * that frame's pixel space. A real root detector and a SPATIAL one: its
21910
+ * boxes are the same kind of fact `pipeline`'s are, produced by a different
21911
+ * detector.
21912
+ *
21913
+ * `onboard` was missing here while `DetectionSourceSchema` already had it, so
21914
+ * a persisted onboard track failed `safeParse` on read and came back with NO
21915
+ * source at all — which `isSpatialTrack` then admitted by accident, through the
21916
+ * `undefined` arm rather than by anybody's decision, and which `excludeSources`
21917
+ * could not name.
21918
+ *
21866
21919
  * The spatial subsystems (tracker association, occupancy count, re-id /
21867
21920
  * embedding, resurrection) MUST skip every synthetic source. Test for that
21868
- * with `isSpatialTrack`, which allow-lists `pipeline` — a `!== 'sensor'`
21869
- * check silently readmits every source added after it was written.
21921
+ * with `isSpatialTrack`, which allow-lists the spatial sources explicitly — a
21922
+ * `!== 'sensor'` check silently readmits every source added after it was
21923
+ * written.
21870
21924
  */
21871
21925
  var TrackSourceSchema = _enum([
21872
21926
  "pipeline",
21927
+ "onboard",
21873
21928
  "sensor",
21874
21929
  "audio"
21875
21930
  ]);
@@ -23951,13 +24006,39 @@ var MotionSourceEnum = _enum([
23951
24006
  */
23952
24007
  var MotionSourcesSchema = array(MotionSourceEnum);
23953
24008
  /**
23954
- * Which root detectors a camera runs. Deliberately the SAME vocabulary
23955
- * post-analysis already tags every detection with (`DetectionSource`) rather
23956
- * than a second spelling of the same two ideas — the value an operator picks
23957
- * here is the value that comes back on the track, the overlay and the debug
23958
- * row.
24009
+ * Which root detector a camera runs — EXACTLY ONE.
24010
+ *
24011
+ * Deliberately the SAME vocabulary post-analysis already tags every detection
24012
+ * with (`DetectionSource`) rather than a second spelling of the same two
24013
+ * ideas: the value an operator picks here is the value that comes back on the
24014
+ * track, the overlay and the debug row.
24015
+ *
24016
+ * ## Why one, and why it is still an array
24017
+ *
24018
+ * Two roots on one camera is a capability nobody asked for and the operator has
24019
+ * since ruled out. It was never free: both planes feed the SAME per-device
24020
+ * stationary registry, both can promote the same parked object, and the two
24021
+ * detectors disagree about the same box by construction — which is the
24022
+ * disagreement D505 had to arbitrate. Removing the case removes the arbitration.
24023
+ *
24024
+ * The ARRAY shape survives because the stored settings and the attach payload
24025
+ * already speak it on every camera of every fleet, and a cap input that
24026
+ * suddenly refuses a stored value makes the camera un-attachable — a fail-closed
24027
+ * in the one direction that costs an operator their cameras. So the wire stays
24028
+ * tolerant and the TYPE is exact: a longer list is truncated to its first
24029
+ * element rather than refused, and `max(1)` is what every consumer can then
24030
+ * rely on.
24031
+ *
24032
+ * AT MOST one, not exactly one. The EMPTY list is a legal, deliberate pick —
24033
+ * a camera an operator left with no root detector — and `planDetectionSources`
24034
+ * has always said so: inventing a root for them is how a default acts without
24035
+ * anybody choosing it. Tightening this to `length(1)` broke that, and the
24036
+ * suite caught it.
24037
+ *
24038
+ * Measured before tightening (2026-09-15, this fleet, 6 h of attaches): 3327
24039
+ * `["pipeline"]` and 2 `["onboard"]`. Not one camera had two.
23959
24040
  */
23960
- var DetectionSourcesSchema = array(DetectionSourceSchema);
24041
+ var DetectionSourcesSchema = preprocess((value) => Array.isArray(value) && value.length > 1 ? value.slice(0, 1) : value, array(DetectionSourceSchema).max(1));
23961
24042
  /**
23962
24043
  * Input shape for `pipeline-runner.reportMotion` cap method. Exported
23963
24044
  * so cap-side consumers (the orchestrator forward, the runner addon's
@@ -37755,6 +37836,12 @@ Object.freeze({
37755
37836
  addonId: null,
37756
37837
  access: "view"
37757
37838
  },
37839
+ "notificationRules.getClipRetentionAsks": {
37840
+ capName: "notification-rules",
37841
+ capScope: "system",
37842
+ addonId: null,
37843
+ access: "view"
37844
+ },
37758
37845
  "notificationRules.getConditionCatalog": {
37759
37846
  capName: "notification-rules",
37760
37847
  capScope: "system",
@@ -5360,7 +5360,7 @@ var ZodIssueCode = {
5360
5360
  var ZodFirstPartyTypeKind;
5361
5361
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5362
5362
  //#endregion
5363
- //#region ../types/dist/sleep-e0RweZzn.mjs
5363
+ //#region ../types/dist/sleep-BDR76Ykr.mjs
5364
5364
  /**
5365
5365
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5366
5366
  * window to float samples (D455).
@@ -20514,6 +20514,48 @@ var NcAlarmConfigSchema = object({
20514
20514
  settings: NcAlarmSettingsSchema,
20515
20515
  coverage: array(NcAlarmModeCoverageSchema)
20516
20516
  });
20517
+ /**
20518
+ * ONE rule's demand on ONE camera's clip ring.
20519
+ *
20520
+ * A rule, not a camera: the broker takes the MAX over the asks that reach a
20521
+ * camera, so the answer stays a faithful description of the rules and the
20522
+ * bounding (the byte budget, the broker's own ceiling) stays where the cost
20523
+ * lives. A camera that appears in no ask is being told **nothing** — which is
20524
+ * a different thing from never having been told, and only the envelope
20525
+ * (`rulesLoaded`) can tell those apart.
20526
+ */
20527
+ var NcClipRetentionAskSchema = object({
20528
+ /**
20529
+ * The camera this ask is about. **Absent = every camera**, which is what a
20530
+ * rule with no `conditions.devices` means: it can fire anywhere, so it is
20531
+ * asking everywhere.
20532
+ */
20533
+ deviceId: number().int().nonnegative().optional(),
20534
+ /** Seconds of history the rule needs held for it. Never zero — a rule that
20535
+ * needs nothing produces no ask at all. */
20536
+ seconds: number().min(0).max(60),
20537
+ /** The profile the rule cuts from, when it named one. Absent = the cheapest
20538
+ * assigned, which is what the cut defaults to. */
20539
+ profile: CamProfileSchema.optional(),
20540
+ /** Who is asking — so a retention the operator did not expect names a rule. */
20541
+ ruleId: string(),
20542
+ ruleName: string(),
20543
+ /** Why this many seconds: the rule's own window, or the occupancy ceiling. */
20544
+ reason: _enum(["window", "occupancy"])
20545
+ });
20546
+ /**
20547
+ * The whole answer, with the one bit that keeps absence from reading as zero.
20548
+ *
20549
+ * `rulesLoaded` is false until the rule ledger has completed a load at least
20550
+ * once. A centre that is up but has not read its rules yet answers with an
20551
+ * empty ask list that means nothing at all — applying it would drop every
20552
+ * camera's ring to zero for the first events after a restart, which is the
20553
+ * footage this mechanism exists to keep.
20554
+ */
20555
+ var NcClipRetentionPlanSchema = object({
20556
+ rulesLoaded: boolean(),
20557
+ asks: array(NcClipRetentionAskSchema).readonly()
20558
+ });
20517
20559
  method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), method(object({ ruleId: string() }), object({ rule: NcRuleSchema.nullable() }), { auth: "admin" }), method(object({ rule: NcRuleInputSchema }), object({ rule: NcRuleSchema }), {
20518
20560
  kind: "mutation",
20519
20561
  auth: "admin",
@@ -20534,7 +20576,7 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
20534
20576
  }), object({ success: literal(true) }), {
20535
20577
  kind: "mutation",
20536
20578
  auth: "admin"
20537
- }), method(object({}), object({ mutedDeviceIds: array(number().int()).readonly() }), { auth: "admin" }), method(object({
20579
+ }), method(object({}), NcClipRetentionPlanSchema, { auth: "admin" }), method(object({}), object({ mutedDeviceIds: array(number().int()).readonly() }), { auth: "admin" }), method(object({
20538
20580
  deviceId: number().int(),
20539
20581
  muted: boolean()
20540
20582
  }), object({ success: literal(true) }), {
@@ -21863,13 +21905,26 @@ var TrackAudioLabelSchema = object({
21863
21905
  * - `audio` — an audio event on the camera itself that was anomalous for
21864
21906
  * THAT camera, loud, and heard while nothing visual was happening (D62).
21865
21907
  *
21908
+ * - `onboard` — the CAMERA's own firmware, paired with a decoded frame in
21909
+ * that frame's pixel space. A real root detector and a SPATIAL one: its
21910
+ * boxes are the same kind of fact `pipeline`'s are, produced by a different
21911
+ * detector.
21912
+ *
21913
+ * `onboard` was missing here while `DetectionSourceSchema` already had it, so
21914
+ * a persisted onboard track failed `safeParse` on read and came back with NO
21915
+ * source at all — which `isSpatialTrack` then admitted by accident, through the
21916
+ * `undefined` arm rather than by anybody's decision, and which `excludeSources`
21917
+ * could not name.
21918
+ *
21866
21919
  * The spatial subsystems (tracker association, occupancy count, re-id /
21867
21920
  * embedding, resurrection) MUST skip every synthetic source. Test for that
21868
- * with `isSpatialTrack`, which allow-lists `pipeline` — a `!== 'sensor'`
21869
- * check silently readmits every source added after it was written.
21921
+ * with `isSpatialTrack`, which allow-lists the spatial sources explicitly — a
21922
+ * `!== 'sensor'` check silently readmits every source added after it was
21923
+ * written.
21870
21924
  */
21871
21925
  var TrackSourceSchema = _enum([
21872
21926
  "pipeline",
21927
+ "onboard",
21873
21928
  "sensor",
21874
21929
  "audio"
21875
21930
  ]);
@@ -23951,13 +24006,39 @@ var MotionSourceEnum = _enum([
23951
24006
  */
23952
24007
  var MotionSourcesSchema = array(MotionSourceEnum);
23953
24008
  /**
23954
- * Which root detectors a camera runs. Deliberately the SAME vocabulary
23955
- * post-analysis already tags every detection with (`DetectionSource`) rather
23956
- * than a second spelling of the same two ideas — the value an operator picks
23957
- * here is the value that comes back on the track, the overlay and the debug
23958
- * row.
24009
+ * Which root detector a camera runs — EXACTLY ONE.
24010
+ *
24011
+ * Deliberately the SAME vocabulary post-analysis already tags every detection
24012
+ * with (`DetectionSource`) rather than a second spelling of the same two
24013
+ * ideas: the value an operator picks here is the value that comes back on the
24014
+ * track, the overlay and the debug row.
24015
+ *
24016
+ * ## Why one, and why it is still an array
24017
+ *
24018
+ * Two roots on one camera is a capability nobody asked for and the operator has
24019
+ * since ruled out. It was never free: both planes feed the SAME per-device
24020
+ * stationary registry, both can promote the same parked object, and the two
24021
+ * detectors disagree about the same box by construction — which is the
24022
+ * disagreement D505 had to arbitrate. Removing the case removes the arbitration.
24023
+ *
24024
+ * The ARRAY shape survives because the stored settings and the attach payload
24025
+ * already speak it on every camera of every fleet, and a cap input that
24026
+ * suddenly refuses a stored value makes the camera un-attachable — a fail-closed
24027
+ * in the one direction that costs an operator their cameras. So the wire stays
24028
+ * tolerant and the TYPE is exact: a longer list is truncated to its first
24029
+ * element rather than refused, and `max(1)` is what every consumer can then
24030
+ * rely on.
24031
+ *
24032
+ * AT MOST one, not exactly one. The EMPTY list is a legal, deliberate pick —
24033
+ * a camera an operator left with no root detector — and `planDetectionSources`
24034
+ * has always said so: inventing a root for them is how a default acts without
24035
+ * anybody choosing it. Tightening this to `length(1)` broke that, and the
24036
+ * suite caught it.
24037
+ *
24038
+ * Measured before tightening (2026-09-15, this fleet, 6 h of attaches): 3327
24039
+ * `["pipeline"]` and 2 `["onboard"]`. Not one camera had two.
23959
24040
  */
23960
- var DetectionSourcesSchema = array(DetectionSourceSchema);
24041
+ var DetectionSourcesSchema = preprocess((value) => Array.isArray(value) && value.length > 1 ? value.slice(0, 1) : value, array(DetectionSourceSchema).max(1));
23961
24042
  /**
23962
24043
  * Input shape for `pipeline-runner.reportMotion` cap method. Exported
23963
24044
  * so cap-side consumers (the orchestrator forward, the runner addon's
@@ -37755,6 +37836,12 @@ Object.freeze({
37755
37836
  addonId: null,
37756
37837
  access: "view"
37757
37838
  },
37839
+ "notificationRules.getClipRetentionAsks": {
37840
+ capName: "notification-rules",
37841
+ capScope: "system",
37842
+ addonId: null,
37843
+ access: "view"
37844
+ },
37758
37845
  "notificationRules.getConditionCatalog": {
37759
37846
  capName: "notification-rules",
37760
37847
  capScope: "system",
@@ -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-C1PeUaZn.js");
5
+ const require_dist = require("../dist-FF-KPXS7.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, Wt as BaseAddon, X as evaluateZoneRules, ft as motionDetectionCapability, qt as DeviceType } from "../dist-D5j2hIVU.mjs";
1
+ import { $t as hydrateSchema, Wt as BaseAddon, X as evaluateZoneRules, ft as motionDetectionCapability, qt as DeviceType } from "../dist-XAp9FVoN.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,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-C1PeUaZn.js");
2
+ const require_dist = require("./dist-FF-KPXS7.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);
@@ -1,4 +1,4 @@
1
- import { Bt as buildFfmpegArgs, Ht as isSoftwareDecode, Lt as errMsg, zt as Fmp4BoxSplitter } from "./dist-D5j2hIVU.mjs";
1
+ import { Bt as buildFfmpegArgs, Ht as isSoftwareDecode, Lt as errMsg, zt as Fmp4BoxSplitter } from "./dist-XAp9FVoN.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { realpathSync } from "node:fs";
4
4
  import path from "node:path";