@camstack/addon-pipeline 1.2.196 → 1.2.198

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 (38) 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-CJdc8j83.js → default-detection-model-B5v8qEI0.js} +1 -1
  4. package/dist/{default-detection-model-BGBAmtEp.mjs → default-detection-model-CASpAESz.mjs} +1 -1
  5. package/dist/detection-pipeline/index.js +5 -5
  6. package/dist/detection-pipeline/index.mjs +4 -4
  7. package/dist/{dist-HG5geL9t.js → dist-BxP0SvPz.js} +215 -58
  8. package/dist/{dist-mYDK58Jp.mjs → dist-oFIHnD88.mjs} +198 -59
  9. package/dist/{lazy-sharp-DmAwZ0s9.js → lazy-sharp-VKOG3WW4.js} +1 -1
  10. package/dist/motion-wasm/index.js +2 -2
  11. package/dist/motion-wasm/index.mjs +1 -1
  12. package/dist/{node-xRsaPwBa.mjs → node-B4zETsJ9.mjs} +1 -1
  13. package/dist/{node--my8JTOW.js → node-BIKrNEtS.js} +1 -1
  14. package/dist/pipeline-runner/index.js +363 -6
  15. package/dist/pipeline-runner/index.mjs +362 -5
  16. package/dist/{retire-root-keys-KE6D6Xh_.js → prebuffer-DmBYRQWg.mjs} +83 -12
  17. package/dist/{retire-root-keys-DMolfhsP.mjs → prebuffer-DqdeLSsk.js} +118 -1
  18. package/dist/{process-memory-CoCSce63.js → process-memory-CMHOmj75.js} +1 -1
  19. package/dist/{process-memory-BDHR3lxe.mjs → process-memory-D9xYwm6L.mjs} +1 -1
  20. package/dist/recorder/index.js +152 -31
  21. package/dist/recorder/index.mjs +148 -27
  22. package/dist/{segment-demux-js-CBynn9Gh.js → segment-demux-js-DLwL1vmq.js} +1 -1
  23. package/dist/{segment-demux-js-CXvgKfsn.mjs → segment-demux-js-DZysrgdC.mjs} +1 -1
  24. package/dist/session-decode/decode-worker-child.js +2 -2
  25. package/dist/session-decode/decode-worker-child.mjs +1 -1
  26. package/dist/stream-broker/_stub.js +29 -32
  27. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BMsB2MVD.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C2eTdxvd.mjs} +3 -3
  28. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B_NVJXAy.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BcjLrxhF.mjs} +1 -1
  29. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CBxobiZW.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Dj_qoc1e.mjs} +1 -1
  30. package/dist/stream-broker/demux-worker-child.js +1 -1
  31. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  32. package/dist/stream-broker/{hostInit-CZig_taJ.mjs → hostInit-C8tu7NS4.mjs} +3 -3
  33. package/dist/stream-broker/index.js +452 -541
  34. package/dist/stream-broker/index.mjs +448 -537
  35. package/dist/stream-broker/remoteEntry.js +1 -1
  36. package/dist/{worker-protocol-DCsi4YS1.js → worker-protocol-D2mMjUXv.js} +1 -1
  37. package/dist/{worker-protocol-C0R1DDC0.mjs → worker-protocol-DFlZm_wr.mjs} +1 -1
  38. package/package.json +1 -1
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-HG5geL9t.js");
6
- const require_process_memory = require("../process-memory-CoCSce63.js");
5
+ const require_dist = require("../dist-BxP0SvPz.js");
6
+ const require_process_memory = require("../process-memory-CMHOmj75.js");
7
7
  let node_fs = require("node:fs");
8
8
  node_fs = require_dist.__toESM(node_fs);
9
9
  let node_path = require("node:path");
@@ -1,6 +1,6 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { Et as errMsg, M as audioAnalyzerCapability, Nt as BaseAddon, Rt as hydrateSchema, S as PoolMemoryWatchdog, j as audioAnalysisCapability, n as AUDIO_BACKEND_CHOICES, rt as mapAudioLabelToMacro, s as DEFAULT_AUDIO_ANALYZER_CONFIG, v as HF_BASE_URL, yt as resolvePoolMemoryPolicy } from "../dist-mYDK58Jp.mjs";
3
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BDHR3lxe.mjs";
2
+ import { Bt as hydrateSchema, Ft as BaseAddon, M as audioAnalyzerCapability, Ot as errMsg, S as PoolMemoryWatchdog, bt as resolvePoolMemoryPolicy, j as audioAnalysisCapability, n as AUDIO_BACKEND_CHOICES, rt as mapAudioLabelToMacro, s as DEFAULT_AUDIO_ANALYZER_CONFIG, v as HF_BASE_URL } from "../dist-oFIHnD88.mjs";
3
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-D9xYwm6L.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-HG5geL9t.js");
1
+ const require_dist = require("./dist-BxP0SvPz.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -1,4 +1,4 @@
1
- import { N as audioKindId, Q as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-mYDK58Jp.mjs";
1
+ import { N as audioKindId, Q as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-oFIHnD88.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -2,12 +2,12 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-HG5geL9t.js");
6
- const require_node = require("../node--my8JTOW.js");
7
- const require_default_detection_model = require("../default-detection-model-CJdc8j83.js");
8
- const require_lazy_sharp = require("../lazy-sharp-DmAwZ0s9.js");
5
+ const require_dist = require("../dist-BxP0SvPz.js");
6
+ const require_node = require("../node-BIKrNEtS.js");
7
+ const require_default_detection_model = require("../default-detection-model-B5v8qEI0.js");
8
+ const require_lazy_sharp = require("../lazy-sharp-VKOG3WW4.js");
9
9
  const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DaUBcb13.js");
10
- const require_process_memory = require("../process-memory-CoCSce63.js");
10
+ const require_process_memory = require("../process-memory-CMHOmj75.js");
11
11
  let node_os = require("node:os");
12
12
  node_os = require_dist.__toESM(node_os);
13
13
  let node_fs = require("node:fs");
@@ -1,10 +1,10 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $ as inferModelProvider, B as defaultDeviceFor$1, Et as errMsg, G as detectionPipelineCapability, Ht as nodePin, J as enumerateInferenceDevices, Jt as array, Kt as sleep, Lt as createEvent, Nt as BaseAddon, Rt as hydrateSchema, S as PoolMemoryWatchdog, Ut as parseJsonUnknown, X as evaluateZoneRules, _t as resolveClusterStepModelId, c as DEFAULT_CLUSTER_STEP_MODELS, ct as pickClusterStepModels, en as object, ft as pipelineExecutorCapability, in as EventCategory, k as YAMNET_TO_MACRO, l as DEFAULT_CLUSTER_STEP_SETTINGS, lt as pickClusterStepSettings, m as DEVICE_BACKEND_TO_FORMAT, nn as string, ot as overlayClusterStepSettings, rn as union, t as APPLE_SA_TO_MACRO, tt as loadContributionCapability, wt as supportedRuntimes$1, xt as runtimeDevices$1, yt as resolvePoolMemoryPolicy } from "../dist-mYDK58Jp.mjs";
3
- import { a as readProcessCost } from "../node-xRsaPwBa.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-BGBAmtEp.mjs";
2
+ import { $ as inferModelProvider, B as defaultDeviceFor$1, Bt as hydrateSchema, Et as supportedRuntimes$1, Ft as BaseAddon, G as detectionPipelineCapability, Gt as parseJsonUnknown, J as enumerateInferenceDevices, Jt as sleep, Ot as errMsg, S as PoolMemoryWatchdog, St as runtimeDevices$1, Wt as nodePin, X as evaluateZoneRules, Xt as array, an as string, bt as resolvePoolMemoryPolicy, c as DEFAULT_CLUSTER_STEP_MODELS, k as YAMNET_TO_MACRO, l as DEFAULT_CLUSTER_STEP_SETTINGS, lt as pickClusterStepModels, m as DEVICE_BACKEND_TO_FORMAT, nn as object, on as union, pt as pipelineExecutorCapability, sn as EventCategory, st as overlayClusterStepSettings, t as APPLE_SA_TO_MACRO, tt as loadContributionCapability, ut as pickClusterStepSettings, vt as resolveClusterStepModelId, zt as createEvent } from "../dist-oFIHnD88.mjs";
3
+ import { a as readProcessCost } from "../node-B4zETsJ9.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-CASpAESz.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
6
  import { n as startEventLoopStallMonitor } from "../event-loop-stall-monitor-DXLNBMkY.mjs";
7
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BDHR3lxe.mjs";
7
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-D9xYwm6L.mjs";
8
8
  import * as os from "node:os";
9
9
  import * as fs from "node:fs";
10
10
  import * as path$1 from "node:path";
@@ -9110,17 +9110,29 @@ var HHMM = /^([01]\d|2[0-3]):[0-5]\d$/;
9110
9110
  /**
9111
9111
  * DERIVED per-camera storage summary — the single field cheap consumers read
9112
9112
  * (the viewer's status dot, the camera list) instead of walking `bands`:
9113
- * - `off` — no band covers the camera (or it is disabled).
9114
- * - `events` — every band records around triggers only.
9115
- * - `continuous` — at least one band records continuously.
9116
- *
9117
- * NEVER authored: the recorder stamps it from the authoritative `bands` on
9118
- * every save (`activeModeForConfig`). Writing it has no effect.
9113
+ * - `off` — no band covers the camera (or it is disabled).
9114
+ * - `events` — every band records around triggers only.
9115
+ * - `continuous` — at least one band records continuously.
9116
+ * - `on-device-decision`— the DEVICE decides: recording runs for as long as the
9117
+ * camera raises its own `recording-signal` level (a robot that cleans). There
9118
+ * is no schedule to author, because there is no hour to program — see
9119
+ * {@link RecordingConfigSchema}`.deviceDecision`.
9120
+ *
9121
+ * NEVER authored: the recorder stamps it from the authoritative intent
9122
+ * (`bands` + `deviceDecision`) on every save (`activeModeForConfig`). Writing it
9123
+ * has no effect.
9124
+ *
9125
+ * `on-device-decision` is named for WHO decides, not for how the recording is
9126
+ * requested. `on-demand` was rejected: in this repo's vocabulary a "demand" is
9127
+ * something the operator makes (the live gate is the recorder's own "demand
9128
+ * window"), and a knob whose name suggests the operator starts it while the
9129
+ * device actually does is the D62 shape — a control nobody can predict.
9119
9130
  */
9120
9131
  var RecordingStorageModeSchema = _enum([
9121
9132
  "off",
9122
9133
  "events",
9123
- "continuous"
9134
+ "continuous",
9135
+ "on-device-decision"
9124
9136
  ]);
9125
9137
  /**
9126
9138
  * Le macro classi che possono aprire una finestra di registrazione — le stesse
@@ -9170,22 +9182,7 @@ var RecordingTriggersSchema = object({
9170
9182
  * il livello: un contatto trovato già aperto al riavvio del runner non fa
9171
9183
  * registrare.
9172
9184
  */
9173
- sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional(),
9174
- /**
9175
- * La camera registra per tutta la durata del SEGNALE che lei stessa
9176
- * pubblica — la cap `recording-signal` (`active: true` mentre il device è in
9177
- * funzione: un robot che pulisce). È un LIVELLO, non un fronte: la finestra
9178
- * resta aperta finché il segnale è alto e si chiude `postBufferSec` dopo la
9179
- * caduta, così una pulizia di quaranta minuti è UNA clip.
9180
- *
9181
- * Non nomina un device: il segnale è della camera stessa, tenuto fresco dal
9182
- * suo provider (D224); il recorder lo ascolta su `DeviceStateChanged` e lo
9183
- * riconcilia leggendo la slice via RPC, con un tetto oltre il quale un
9184
- * segnale mai abbassato (un evento perso) non può tenere aperta una
9185
- * registrazione (D11). Vedi `recorder/addon/band-decision.ts`
9186
- * (`holdTrigger` / `releaseTrigger`).
9187
- */
9188
- deviceSignal: boolean().optional()
9185
+ sensorDeviceIds: array(number().int().positive()).min(1).max(16).refine(noDuplicates, { message: "sensorDeviceIds must not repeat a device" }).optional()
9189
9186
  });
9190
9187
  /**
9191
9188
  * Mode of a single recording band — the recorder per-band vocabulary.
@@ -9215,6 +9212,24 @@ var RecordingBandSchema = object({
9215
9212
  end: string().regex(HHMM),
9216
9213
  mode: RecordingBandModeSchema,
9217
9214
  triggers: RecordingBandTriggersSchema.optional(),
9215
+ /**
9216
+ * RETIRED (D381). A band no longer carries a pre-buffer of its own.
9217
+ *
9218
+ * It was the retroactive KEEP bound — which already-written segments survive
9219
+ * a trigger — and it had to be at least as wide as the widest pre-roll the
9220
+ * broker could serve, or the gate would delete the seconds the ring had just
9221
+ * handed the writer. That "at least as wide as" is the tell: it was a second
9222
+ * expression of the broker's retention, in different units, in a different
9223
+ * addon, with an invariant the operator had to maintain by hand. The keep
9224
+ * bound is now derived from the one prebuffer ceiling and there is nothing
9225
+ * left to configure here.
9226
+ *
9227
+ * The key survives in the SHAPE so a config written before that record still
9228
+ * parses and can be migrated deliberately — `RecordingBandSchema` is not
9229
+ * strict, so simply deleting it would strip an operator's value in silence on
9230
+ * the next save (the failure D380 came one commit from shipping). Nothing
9231
+ * reads it: {@link stripRetiredBandPreBufferSec} removes it on load.
9232
+ */
9218
9233
  preBufferSec: number().min(0).optional(),
9219
9234
  postBufferSec: number().min(0).optional()
9220
9235
  });
@@ -9232,29 +9247,56 @@ var RecordingBandSchema = object({
9232
9247
  * `postBufferSec` must therefore exceed one segment length plus the attach
9233
9248
  * latency (ffmpeg spawn + RTSP dial), or the window closes before the first
9234
9249
  * segment is ever finalized and the camera records nothing anyway. At the 10 s
9235
- * default segment length, 30 s leaves room for two full segments. `preBufferSec`
9236
- * is retroactive only — it costs nothing at record time, it merely keeps
9237
- * already-written segments.
9238
- *
9239
- * ## Why `preBufferSec` is 15 and not one segment length
9240
- *
9241
- * It has to cover the broker's RECORDING pre-roll, which is media handed to the
9242
- * writer from BEFORE the trigger (D192/D193). If this bound were narrower, the
9243
- * keep gate would delete the very seconds the ring just supplied — two
9244
- * authorities disagreeing about the same footage, which is the failure D191 was
9245
- * written against. It is therefore set to `RECORDING_PRE_ROLL_MAX_MS` (15 s),
9246
- * the widest window the broker can be configured to serve, so an operator
9247
- * raising the cluster pre-roll can never walk past the gate silently. The
9248
- * addon-side guard is
9249
- * `packages/addon-pipeline/src/recorder/addon/__tests__/band-decision.spec.ts`.
9250
- *
9251
- * An EXPLICIT `0` is left alone: that is an operator statement, not an omission,
9252
- * and it is excluded from that invariant by name.
9253
- */
9254
- var DEFAULT_EVENTS_BAND_BUFFER_SEC = {
9255
- preBufferSec: 15,
9256
- postBufferSec: 30
9257
- };
9250
+ * default segment length, 30 s leaves room for two full segments.
9251
+ *
9252
+ * ## There is no `preBufferSec` here any more (D381)
9253
+ *
9254
+ * There used to be, at 15 s, and its whole justification was that it had to
9255
+ * cover the widest pre-roll the broker could serve. A number whose only
9256
+ * correct value is another subsystem's ceiling is not a setting; it is that
9257
+ * ceiling, restated where it can drift. The keep bound is derived from the
9258
+ * prebuffer ceiling directly now, in `band-decision.ts`, so an operator
9259
+ * raising the prebuffer cannot walk past the gate at all rather than merely
9260
+ * being warned not to.
9261
+ */
9262
+ var DEFAULT_EVENTS_BAND_BUFFER_SEC = { postBufferSec: 30 };
9263
+ /**
9264
+ * Drop the RETIRED band `preBufferSec` from a persisted recording config.
9265
+ *
9266
+ * Explicit, and it reports what it removed, because the alternative is a
9267
+ * silent strip: `RecordingBandSchema` is a plain `z.object`, so the key
9268
+ * survives a parse and disappears on the next save with no line anywhere. An
9269
+ * operator who had typed a number would find it gone and nothing would say
9270
+ * when or why.
9271
+ *
9272
+ * Nothing is carried forward: the value it held was always required to be at
9273
+ * least the broker's widest pre-roll, and the gate is now derived from exactly
9274
+ * that ceiling. Every configuration that was legal therefore keeps a keep-gate
9275
+ * at least as wide as the one it had — including an explicit `0`, which widens.
9276
+ * That is deliberate and it is the only behaviour change: a band that kept
9277
+ * nothing before its trigger now keeps up to the prebuffer ceiling of
9278
+ * already-written footage, which is media that exists either way.
9279
+ */
9280
+ function stripRetiredBandPreBufferSec(config) {
9281
+ const strippedBands = [];
9282
+ const bands = config.bands.map((band, index) => {
9283
+ if (band.preBufferSec === void 0) return band;
9284
+ strippedBands.push(index);
9285
+ const { preBufferSec: _retired, ...rest } = band;
9286
+ return rest;
9287
+ });
9288
+ if (strippedBands.length === 0) return {
9289
+ config,
9290
+ strippedBands
9291
+ };
9292
+ return {
9293
+ config: {
9294
+ ...config,
9295
+ bands
9296
+ },
9297
+ strippedBands
9298
+ };
9299
+ }
9258
9300
  DEFAULT_EVENTS_BAND_BUFFER_SEC.postBufferSec * 1e3;
9259
9301
  /**
9260
9302
  * Per-device retention overrides. Every field is optional; an unset or `0`
@@ -9303,8 +9345,29 @@ var RecordingConfigSchema = object({
9303
9345
  * "off" is the absence of a covering band, never a band value.
9304
9346
  */
9305
9347
  bands: array(RecordingBandSchema).default([]),
9348
+ /**
9349
+ * THE device-decided intent: record for as long as the camera itself raises
9350
+ * `recording-signal` (`active: true` while the device is in function — a
9351
+ * robot that cleans). AUTHORED, unlike `mode`, and the only authored
9352
+ * recording intent that is not a band.
9353
+ *
9354
+ * It carries NO schedule on purpose. A band is an HOUR, and this feature has
9355
+ * no hour to program: the device decides. What it costs the operator is one
9356
+ * flag — "this camera can record on its own" — and what it buys is the same
9357
+ * hold/release the recorder already implements (D371, `holdTrigger` /
9358
+ * `releaseTrigger`): the window opens on the rise, stays open for the whole
9359
+ * job however long it is, and closes one pad after the fall.
9360
+ *
9361
+ * EXCLUSIVE with `bands` (below): two authorities deciding when the same
9362
+ * camera records is the D62 failure. `off` remains `enabled: false`, so an
9363
+ * operator switching this camera off is REPORTED off, never as broken.
9364
+ */
9365
+ deviceDecision: boolean().optional(),
9306
9366
  retention: RecordingRetentionSchema.optional()
9307
- }).strict();
9367
+ }).strict().refine((config) => config.deviceDecision !== true || config.bands.length === 0, {
9368
+ message: "deviceDecision is a whole-config mode and carries no schedule: it cannot be combined with bands",
9369
+ path: ["bands"]
9370
+ });
9308
9371
  /**
9309
9372
  * Derive the {@link RecordingStorageModeSchema} summary from the authoritative
9310
9373
  * bands: `continuous` when any band records continuously, `events` when a band
@@ -9317,7 +9380,9 @@ var RecordingConfigSchema = object({
9317
9380
  * bug this field was added to fix.
9318
9381
  */
9319
9382
  function deriveRecordingMode(config) {
9320
- if (!config.enabled || config.bands.length === 0) return "off";
9383
+ if (!config.enabled) return "off";
9384
+ if (config.deviceDecision === true) return "on-device-decision";
9385
+ if (config.bands.length === 0) return "off";
9321
9386
  if (config.bands.some((band) => band.mode === "continuous")) return "continuous";
9322
9387
  return "events";
9323
9388
  }
@@ -9345,6 +9410,85 @@ function resolveRecordingProfiles(assigned, override) {
9345
9410
  const preferred = assigned.filter((profile) => DEFAULT_RECORDING_PROFILES.includes(profile));
9346
9411
  return preferred.length > 0 ? preferred : [...assigned];
9347
9412
  }
9413
+ /** Trigger keys that survive D380 — a band carrying one of these is a real band. */
9414
+ var SURVIVING_TRIGGER_KEYS = [
9415
+ "motion",
9416
+ "audioThresholdDbfs",
9417
+ "objectClasses",
9418
+ "sensorDeviceIds"
9419
+ ];
9420
+ function isRecord$1(value) {
9421
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9422
+ }
9423
+ function listensToLegacySignal(band) {
9424
+ return isRecord$1(band) && isRecord$1(band.triggers) && band.triggers.deviceSignal === true;
9425
+ }
9426
+ function hasSurvivingTrigger(band) {
9427
+ const triggers = band.triggers;
9428
+ if (!isRecord$1(triggers)) return false;
9429
+ return SURVIVING_TRIGGER_KEYS.some((key) => triggers[key] !== void 0);
9430
+ }
9431
+ function withoutLegacySignal(band) {
9432
+ const triggers = band.triggers;
9433
+ if (!isRecord$1(triggers)) return band;
9434
+ const { deviceSignal: _retired, ...rest } = triggers;
9435
+ return {
9436
+ ...band,
9437
+ triggers: rest
9438
+ };
9439
+ }
9440
+ /**
9441
+ * Turn a config stored under D371 (`bands[].triggers.deviceSignal: true`) into
9442
+ * a D380 one (`deviceDecision: true`, no bands). Pure, total and IDEMPOTENT —
9443
+ * a row with no legacy key comes back as the SAME reference, `migrated: false`.
9444
+ *
9445
+ * ## Why the schema cannot be left to do this
9446
+ *
9447
+ * `RecordingTriggersSchema` is a non-strict `z.object`, so the retired key is
9448
+ * SILENTLY STRIPPED on read. The camera whose only trigger it was would parse
9449
+ * cleanly into an `events` band that lists nothing — "enabled, and records
9450
+ * nothing, forever", the exact shape `eventsBandCanEverDemand` exists to shout
9451
+ * about, reached without a single line in the log. On the reference hub that is
9452
+ * camera 4374, the one camera an operator had configured by hand.
9453
+ *
9454
+ * `enabled` is carried through untouched: a camera the operator had switched
9455
+ * OFF comes out of a migration still off (D62).
9456
+ */
9457
+ function migrateLegacyDeviceSignalConfig(raw) {
9458
+ const unchanged = {
9459
+ value: raw,
9460
+ migrated: false,
9461
+ strippedOnly: false
9462
+ };
9463
+ if (!isRecord$1(raw) || !Array.isArray(raw.bands)) return unchanged;
9464
+ if (!raw.bands.some(listensToLegacySignal)) return unchanged;
9465
+ const kept = [];
9466
+ for (const band of raw.bands) {
9467
+ if (!listensToLegacySignal(band) || !isRecord$1(band)) {
9468
+ kept.push(band);
9469
+ continue;
9470
+ }
9471
+ if (hasSurvivingTrigger(band)) kept.push(withoutLegacySignal(band));
9472
+ }
9473
+ if (kept.length > 0) return {
9474
+ value: {
9475
+ ...raw,
9476
+ bands: kept
9477
+ },
9478
+ migrated: false,
9479
+ strippedOnly: true
9480
+ };
9481
+ const { mode: _derived, ...rest } = raw;
9482
+ return {
9483
+ value: {
9484
+ ...rest,
9485
+ bands: [],
9486
+ deviceDecision: true
9487
+ },
9488
+ migrated: true,
9489
+ strippedOnly: false
9490
+ };
9491
+ }
9348
9492
  /**
9349
9493
  * Entity-relocation job state (storage entity-routing spec, Phase 4).
9350
9494
  *
@@ -23320,11 +23464,7 @@ var CameraAudioStatusSchema = object({
23320
23464
  });
23321
23465
  /** Recording block — null when no recording cap is active for this device. */
23322
23466
  var CameraRecordingStatusSchema = object({
23323
- mode: _enum([
23324
- "off",
23325
- "continuous",
23326
- "events"
23327
- ]),
23467
+ mode: RecordingStorageModeSchema,
23328
23468
  active: boolean(),
23329
23469
  storageBytes: number()
23330
23470
  });
@@ -29899,11 +30039,10 @@ DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceI
29899
30039
  var RecordingStatusSchema = object({
29900
30040
  deviceId: number(),
29901
30041
  enabled: boolean(),
29902
- activeMode: _enum([
29903
- "off",
29904
- "continuous",
29905
- "events"
29906
- ]),
30042
+ /** THE derived storage mode, from the one definition
30043
+ * (`deriveRecordingMode`) — never a second enum. A duplicated list is how
30044
+ * `on-device-decision` could have reached the recorder and not the status. */
30045
+ activeMode: RecordingStorageModeSchema,
29907
30046
  nodeId: string(),
29908
30047
  storageBytes: number()
29909
30048
  });
@@ -42740,6 +42879,12 @@ Object.defineProperty(exports, "maskUrlCredentials", {
42740
42879
  return maskUrlCredentials;
42741
42880
  }
42742
42881
  });
42882
+ Object.defineProperty(exports, "migrateLegacyDeviceSignalConfig", {
42883
+ enumerable: true,
42884
+ get: function() {
42885
+ return migrateLegacyDeviceSignalConfig;
42886
+ }
42887
+ });
42743
42888
  Object.defineProperty(exports, "motionDetectionCapability", {
42744
42889
  enumerable: true,
42745
42890
  get: function() {
@@ -42824,6 +42969,12 @@ Object.defineProperty(exports, "pipelineRunnerCapability", {
42824
42969
  return pipelineRunnerCapability;
42825
42970
  }
42826
42971
  });
42972
+ Object.defineProperty(exports, "preprocess", {
42973
+ enumerable: true,
42974
+ get: function() {
42975
+ return preprocess;
42976
+ }
42977
+ });
42827
42978
  Object.defineProperty(exports, "record", {
42828
42979
  enumerable: true,
42829
42980
  get: function() {
@@ -42908,6 +43059,12 @@ Object.defineProperty(exports, "string", {
42908
43059
  return string;
42909
43060
  }
42910
43061
  });
43062
+ Object.defineProperty(exports, "stripRetiredBandPreBufferSec", {
43063
+ enumerable: true,
43064
+ get: function() {
43065
+ return stripRetiredBandPreBufferSec;
43066
+ }
43067
+ });
42911
43068
  Object.defineProperty(exports, "supportedRuntimes", {
42912
43069
  enumerable: true,
42913
43070
  get: function() {