@camstack/addon-pipeline 1.2.252 → 1.2.254

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 (30) 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-CaOyxW54.mjs → default-detection-model-BegEf29d.mjs} +1 -1
  4. package/dist/{default-detection-model-C3QhNmlf.js → default-detection-model-DQj3yiG8.js} +1 -1
  5. package/dist/detection-pipeline/index.js +4 -4
  6. package/dist/detection-pipeline/index.mjs +4 -4
  7. package/dist/{dist-UDv0mi6-.mjs → dist-CkGvx3Fy.mjs} +1 -1
  8. package/dist/{dist-G5Uib9Bn.js → dist-DQsOgAJp.js} +1 -1
  9. package/dist/motion-wasm/index.js +1 -1
  10. package/dist/motion-wasm/index.mjs +1 -1
  11. package/dist/{node-ByNljnzV.js → node-Bg7LGOQ3.js} +1 -1
  12. package/dist/{node-5P6235Qa.mjs → node-Dwlty0jj.mjs} +1 -1
  13. package/dist/pipeline-runner/index.js +4 -4
  14. package/dist/pipeline-runner/index.mjs +4 -4
  15. package/dist/{process-memory-3HWRtZgr.js → process-memory-COrQw_pf.js} +1 -1
  16. package/dist/{process-memory-DBzJCO-_.mjs → process-memory-CzjYHqAz.mjs} +1 -1
  17. package/dist/recorder/index.js +3 -3
  18. package/dist/recorder/index.mjs +3 -3
  19. package/dist/{restream-intent-MeJhGCK9.mjs → restream-intent-D2VT97-U.mjs} +3 -3
  20. package/dist/{restream-intent-C4adO0P8.js → restream-intent-VVJiUAkh.js} +3 -3
  21. package/dist/{segment-demux-js-CUFnkl3n.mjs → segment-demux-js-BAoEDsxT.mjs} +1 -1
  22. package/dist/{segment-demux-js-CtQrIvn7.js → segment-demux-js-BIrnzZiP.js} +1 -1
  23. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DpxY0D_G.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-rumvXmC-.mjs} +3 -3
  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-B6AhXDBP.mjs → hostInit-CFFft0gC.mjs} +3 -3
  27. package/dist/stream-broker/index.js +162 -158
  28. package/dist/stream-broker/index.mjs +162 -158
  29. package/dist/stream-broker/remoteEntry.js +1 -1
  30. package/package.json +1 -1
@@ -1,10 +1,10 @@
1
1
  import { r as __toESM } from "../chunk-DnnnRqeS.mjs";
2
- import { A as RingBuffer, B as declareLogChannel, Bt as buildFfmpegArgs$1, E as RATE_CONTROL_TIGHT, Et as resolveEgressDecodeHwAccel, Gt as CAM_PROFILE_ORDER, H as deriveBatteryPresence, Ht as isSoftwareDecode, I as batteryCapability, It as webrtcSessionCapability, K as egressTranscodeSharingKey, Kt as DeviceFeature, L as cameraStreamsCapability, Lt as errMsg, M as addonWidgetsSourceCapability, Nt as streamBrokerCapability, Qt as expandAudioChunkToF32le, R as createHwAccelCache, Rt as AUDIO_PRESETS, T as RATE_CONTROL_RELAXED, Ut as BOOT_RECOVERY_BACKOFF_MS, Vt as invocationFromEncodeProfile, Wt as BaseAddon, Yt as createEvent, _n as record, an as parseProfileBrokerId, at as logChannelsCapability, bn as EventCategory, cn as _enum, dn as discriminatedUnion, en as isEvent, h as EncodeProfileSchema, hn as object, i as BatteryStatusSchema, it as loadContributionCapability, ln as array, mn as number, nn as makeSourceBrokerId, pn as literal, q as egressTransportFromRequest, qt as DeviceType, rn as nodePin, st as maskUrlCredentials, tn as makeProfileBrokerId, un as boolean, v as G711_SCALE_CORRECTION_DB, vn as string, xt as rankStreams, yn as union, z as createLogChannelsProvider } from "../dist-UDv0mi6-.mjs";
3
- import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-5P6235Qa.mjs";
4
- import { c as PREBUFFER_MAX_MS, d as resolvePrebuffer, i as parseRestreamPath, l as capPreRollRequestMs, n as NO_DECLARATION, u as prebufferRetentionMs } from "../restream-intent-MeJhGCK9.mjs";
2
+ import { A as RingBuffer, B as declareLogChannel, Bt as buildFfmpegArgs$1, E as RATE_CONTROL_TIGHT, Et as resolveEgressDecodeHwAccel, Gt as CAM_PROFILE_ORDER, H as deriveBatteryPresence, Ht as isSoftwareDecode, I as batteryCapability, It as webrtcSessionCapability, K as egressTranscodeSharingKey, Kt as DeviceFeature, L as cameraStreamsCapability, Lt as errMsg, M as addonWidgetsSourceCapability, Nt as streamBrokerCapability, Qt as expandAudioChunkToF32le, R as createHwAccelCache, Rt as AUDIO_PRESETS, T as RATE_CONTROL_RELAXED, Ut as BOOT_RECOVERY_BACKOFF_MS, Vt as invocationFromEncodeProfile, Wt as BaseAddon, Yt as createEvent, _n as record, an as parseProfileBrokerId, at as logChannelsCapability, bn as EventCategory, cn as _enum, dn as discriminatedUnion, en as isEvent, h as EncodeProfileSchema, hn as object, i as BatteryStatusSchema, it as loadContributionCapability, ln as array, mn as number, nn as makeSourceBrokerId, pn as literal, q as egressTransportFromRequest, qt as DeviceType, rn as nodePin, st as maskUrlCredentials, tn as makeProfileBrokerId, un as boolean, v as G711_SCALE_CORRECTION_DB, vn as string, xt as rankStreams, yn as union, z as createLogChannelsProvider } from "../dist-CkGvx3Fy.mjs";
3
+ import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-Dwlty0jj.mjs";
4
+ import { c as PREBUFFER_MAX_MS, d as resolvePrebuffer, i as parseRestreamPath, l as capPreRollRequestMs, n as NO_DECLARATION, u as prebufferRetentionMs } from "../restream-intent-D2VT97-U.mjs";
5
5
  import { n as profileForStreamId } from "../remote-restream-BeHi78PZ.mjs";
6
6
  import { n as RowMapStore, t as retireRootKeys } from "../retire-root-keys-DZvlso2l.mjs";
7
- import { i as require_mp4box_all, n as demuxSegmentPreferJs, r as runFfmpegOnce, t as demuxSegmentFullJs } from "../segment-demux-js-CUFnkl3n.mjs";
7
+ import { i as require_mp4box_all, n as demuxSegmentPreferJs, r as runFfmpegOnce, t as demuxSegmentFullJs } from "../segment-demux-js-BAoEDsxT.mjs";
8
8
  import { createRequire } from "node:module";
9
9
  import * as os from "node:os";
10
10
  import { networkInterfaces, tmpdir } from "node:os";
@@ -650,8 +650,8 @@ function healthEventIsOperatorFacing(camStreamId) {
650
650
  return !PRIVATE_STREAM_PREFIXES.some((prefix) => camStreamId.startsWith(prefix));
651
651
  }
652
652
  //#endregion
653
- //#region src/stream-broker/stream-broker/prestream-eligibility.ts
654
- function prestreamEligible(input) {
653
+ //#region src/stream-broker/stream-broker/sentry-eligibility.ts
654
+ function sentryEligible(input) {
655
655
  if (input.batteryOperated === null || input.declaresSignals === null) return {
656
656
  eligible: false,
657
657
  reason: "unknown"
@@ -667,7 +667,7 @@ function prestreamEligible(input) {
667
667
  return { eligible: true };
668
668
  }
669
669
  //#endregion
670
- //#region src/stream-broker/stream-broker/prestream-signal-selection.ts
670
+ //#region src/stream-broker/stream-broker/sentry-signal-selection.ts
671
671
  function nextEnabledSignals(input) {
672
672
  const base = input.stored ?? input.declared;
673
673
  const set = new Set(base);
@@ -685,7 +685,7 @@ function nextEnabledSignals(input) {
685
685
  * A stream a consumer merely watches is not a reason to wake a battery camera —
686
686
  * a Frigate-style puller holds a session open for ever, and treating that as
687
687
  * demand keeps the camera awake for ever, which is the whole point of the
688
- * battery (D173). So a prestream consumer is FED without being INTENT, and the
688
+ * battery (D173). So a sentry consumer is FED without being INTENT, and the
689
689
  * only thing that dials is a signal the camera reported about itself.
690
690
  *
691
691
  * This module is the timing half of that, and it is pure so the arithmetic can
@@ -3126,11 +3126,11 @@ var RtspRestreamer = class {
3126
3126
  return this.sessions.size;
3127
3127
  }
3128
3128
  /**
3129
- * Sessions that count as LIVE INTENT — everything except a prestream dial.
3129
+ * Sessions that count as LIVE INTENT — everything except a sentry dial.
3130
3130
  *
3131
3131
  * The split exists so a Frigate-style puller can hold a session open for ever
3132
3132
  * against a battery camera without keeping it awake (D173). For a broker with
3133
- * no prestream session this equals {@link getSessionCount} exactly, which is
3133
+ * no sentry session this equals {@link getSessionCount} exactly, which is
3134
3134
  * why nothing else changed behaviour.
3135
3135
  */
3136
3136
  getLiveIntentSessionCount() {
@@ -3138,7 +3138,7 @@ var RtspRestreamer = class {
3138
3138
  for (const session of this.sessions.values()) if (!session.isPrestreamIntent()) n += 1;
3139
3139
  return n;
3140
3140
  }
3141
- /** Sessions asking only for the picture. Drives the prestream pump, nothing
3141
+ /** Sessions asking only for the picture. Drives the sentry pump, nothing
3142
3142
  * else — it must never reach a dial decision. */
3143
3143
  getPrestreamSessionCount() {
3144
3144
  let n = 0;
@@ -3899,12 +3899,12 @@ var RtspSession = class {
3899
3899
  /**
3900
3900
  * Whether this dial asked for the STREAM without asking for the CAMERA.
3901
3901
  *
3902
- * The one question the demand split turns on: a prestream session is FED but
3902
+ * The one question the demand split turns on: a sentry session is FED but
3903
3903
  * is not INTENT, so it never dials a sleeping camera. See
3904
- * `PRESTREAM_PATH_SUFFIX`.
3904
+ * `SENTRY_PATH_SUFFIX`.
3905
3905
  */
3906
3906
  isPrestreamIntent() {
3907
- return this.declaration.intent === "prestream";
3907
+ return this.declaration.intent === "sentry";
3908
3908
  }
3909
3909
  /**
3910
3910
  * Ms of retained history this session ASKED for on its dial. `0` = none.
@@ -4203,7 +4203,7 @@ var RtspListenServer = class RtspListenServer {
4203
4203
  brokerEnabled = /* @__PURE__ */ new Map();
4204
4204
  /** brokerId → warm-up closure registered alongside the restreamer */
4205
4205
  brokerWarmUps = /* @__PURE__ */ new Map();
4206
- /** brokerId → prestream picture-window opener */
4206
+ /** brokerId → sentry picture-window opener */
4207
4207
  brokerPrestreamOpeners = /* @__PURE__ */ new Map();
4208
4208
  /** Generate a random token for a stream path */
4209
4209
  static generateToken() {
@@ -4215,7 +4215,7 @@ var RtspListenServer = class RtspListenServer {
4215
4215
  * If not, generate a new one.
4216
4216
  * Returns the token used.
4217
4217
  */
4218
- registerRestreamer(brokerId, restreamer, warmUp, existingToken, prestreamOpener) {
4218
+ registerRestreamer(brokerId, restreamer, warmUp, existingToken, sentryOpener) {
4219
4219
  const oldToken = this.brokerTokens.get(brokerId);
4220
4220
  if (oldToken) {
4221
4221
  this.restreamers.delete(oldToken);
@@ -4226,7 +4226,7 @@ var RtspListenServer = class RtspListenServer {
4226
4226
  this.brokerTokens.set(brokerId, token);
4227
4227
  this.tokenBrokers.set(token, brokerId);
4228
4228
  if (warmUp) this.brokerWarmUps.set(brokerId, warmUp);
4229
- if (prestreamOpener) this.brokerPrestreamOpeners.set(brokerId, prestreamOpener);
4229
+ if (sentryOpener) this.brokerPrestreamOpeners.set(brokerId, sentryOpener);
4230
4230
  return token;
4231
4231
  }
4232
4232
  unregisterRestreamer(brokerId) {
@@ -4338,9 +4338,9 @@ var RtspListenServer = class RtspListenServer {
4338
4338
  socket.destroy();
4339
4339
  return;
4340
4340
  }
4341
- const prestreamDial = declaration.intent === "prestream";
4342
- const warmUp = brokerId && !prestreamDial ? this.brokerWarmUps.get(brokerId) : void 0;
4343
- const opener = brokerId && prestreamDial ? this.brokerPrestreamOpeners.get(brokerId) : void 0;
4341
+ const sentryDial = declaration.intent === "sentry";
4342
+ const warmUp = brokerId && !sentryDial ? this.brokerWarmUps.get(brokerId) : void 0;
4343
+ const opener = brokerId && sentryDial ? this.brokerPrestreamOpeners.get(brokerId) : void 0;
4344
4344
  const releaseWarmUp = warmUp ? warmUp() : opener?.() ?? null;
4345
4345
  let released = false;
4346
4346
  const releaseOnce = () => {
@@ -7644,16 +7644,16 @@ function runGif(input, args) {
7644
7644
  });
7645
7645
  }
7646
7646
  //#endregion
7647
- //#region src/stream-broker/stream-broker/prestream-encode.ts
7647
+ //#region src/stream-broker/stream-broker/sentry-encode.ts
7648
7648
  /**
7649
- * ONE short-lived ffmpeg turns the prestream's picture into ONE Annex-B IDR.
7649
+ * ONE short-lived ffmpeg turns the sentry's picture into ONE Annex-B IDR.
7650
7650
  *
7651
7651
  * ── Why one encode and not a continuous child ─────────────────────────────
7652
7652
  * The obvious shape is `-loop 1 -framerate 1` and let ffmpeg emit the picture
7653
7653
  * for as long as the camera is waking. That is a resident child per sleeping
7654
7654
  * camera, for the whole wake, to redraw a picture that changes at most hourly.
7655
7655
  * So the child encodes exactly ONE frame (`-frames:v 1`) and exits, the caller
7656
- * caches the bytes, and {@link PrestreamPump} re-emits them. A new encode
7656
+ * caches the bytes, and {@link SentryPump} re-emits them. A new encode
7657
7657
  * happens only when the picture changes.
7658
7658
  *
7659
7659
  * ── Why every frame carries its own parameter sets ────────────────────────
@@ -7678,10 +7678,10 @@ function runGif(input, args) {
7678
7678
  */
7679
7679
  /**
7680
7680
  * Bound on the encode. A single 4 MP still on `ultrafast` is milliseconds; a
7681
- * child that has not answered in this long is hung, and the prestream would
7681
+ * child that has not answered in this long is hung, and the sentry would
7682
7682
  * otherwise hold a promise open for the rest of the process's life.
7683
7683
  */
7684
- var PRESTREAM_ENCODE_TIMEOUT_MS = 1e4;
7684
+ var SENTRY_ENCODE_TIMEOUT_MS = 1e4;
7685
7685
  /** Grace before escalating SIGTERM → SIGKILL on a child that will not go. */
7686
7686
  var KILL_GRACE_MS = 500;
7687
7687
  /** x264/x265 params shared by both codecs: one-frame GOP, headers on it. */
@@ -7736,7 +7736,7 @@ function buildPrestreamEncodeArgs(plan) {
7736
7736
  }
7737
7737
  /**
7738
7738
  * Run the encode. Resolves with the Annex-B bytes, rejects with a named reason
7739
- * — the caller turns a rejection into a refusal log and no prestream, which is
7739
+ * — the caller turns a rejection into a refusal log and no sentry, which is
7740
7740
  * the same outcome as a black screen and never worse than one.
7741
7741
  */
7742
7742
  function encodePrestreamIdr(options) {
@@ -7748,7 +7748,7 @@ function encodePrestreamIdr(options) {
7748
7748
  try {
7749
7749
  child = spawnFn(options.ffmpegPath, args);
7750
7750
  } catch (err) {
7751
- reject(/* @__PURE__ */ new Error(`prestream encode could not spawn ffmpeg: ${errMsg(err)}`));
7751
+ reject(/* @__PURE__ */ new Error(`sentry encode could not spawn ffmpeg: ${errMsg(err)}`));
7752
7752
  return;
7753
7753
  }
7754
7754
  const chunks = [];
@@ -7763,8 +7763,8 @@ function encodePrestreamIdr(options) {
7763
7763
  };
7764
7764
  const timer = setTimeout(() => {
7765
7765
  killChild(child);
7766
- finish({ error: /* @__PURE__ */ new Error(`prestream encode timed out after ${String(PRESTREAM_ENCODE_TIMEOUT_MS)} ms`) });
7767
- }, PRESTREAM_ENCODE_TIMEOUT_MS);
7766
+ finish({ error: /* @__PURE__ */ new Error(`sentry encode timed out after ${String(SENTRY_ENCODE_TIMEOUT_MS)} ms`) });
7767
+ }, SENTRY_ENCODE_TIMEOUT_MS);
7768
7768
  timer.unref?.();
7769
7769
  child.stdout?.on("data", (chunk) => chunks.push(chunk));
7770
7770
  child.stderr?.on("data", (chunk) => {
@@ -7772,19 +7772,19 @@ function encodePrestreamIdr(options) {
7772
7772
  });
7773
7773
  child.stdin?.on("error", () => {});
7774
7774
  child.on("error", (err) => {
7775
- finish({ error: /* @__PURE__ */ new Error(`prestream encode failed: ${err.message}`) });
7775
+ finish({ error: /* @__PURE__ */ new Error(`sentry encode failed: ${err.message}`) });
7776
7776
  });
7777
7777
  child.on("exit", (code, signal) => {
7778
7778
  if (code !== 0) {
7779
- finish({ error: /* @__PURE__ */ new Error(`prestream encode exited ${String(code ?? signal)}: ${stderrTail.trim() || "no stderr"}`) });
7779
+ finish({ error: /* @__PURE__ */ new Error(`sentry encode exited ${String(code ?? signal)}: ${stderrTail.trim() || "no stderr"}`) });
7780
7780
  return;
7781
7781
  }
7782
7782
  const bytes = Buffer.concat(chunks);
7783
7783
  if (bytes.length === 0) {
7784
- finish({ error: /* @__PURE__ */ new Error("prestream encode produced no bytes") });
7784
+ finish({ error: /* @__PURE__ */ new Error("sentry encode produced no bytes") });
7785
7785
  return;
7786
7786
  }
7787
- options.logger?.debug("prestream: picture encoded", {
7787
+ options.logger?.debug("sentry: picture encoded", {
7788
7788
  ...tags,
7789
7789
  meta: {
7790
7790
  codec: options.plan.codec,
@@ -7806,9 +7806,9 @@ function killChild(child) {
7806
7806
  }, KILL_GRACE_MS).unref?.();
7807
7807
  }
7808
7808
  //#endregion
7809
- //#region src/stream-broker/stream-broker/prestream-picture.ts
7809
+ //#region src/stream-broker/stream-broker/sentry-picture.ts
7810
7810
  /**
7811
- * The PICTURE the prestream shows: the camera's own last frame under a "Waking"
7811
+ * The PICTURE the sentry shows: the camera's own last frame under a "Waking"
7812
7812
  * treatment, or — when there is none — a generated card carrying its name.
7813
7813
  *
7814
7814
  * ── Why a fallback exists at all ──────────────────────────────────────────
@@ -7839,16 +7839,18 @@ function killChild(child) {
7839
7839
  */
7840
7840
  async function composePrestreamPicture(input) {
7841
7841
  const tags = input.deviceId === void 0 ? {} : { tags: { deviceId: input.deviceId } };
7842
+ const reason = "sleeping";
7842
7843
  if (input.cachedJpeg !== null && input.cachedJpeg.length > 0) try {
7843
7844
  return {
7844
7845
  jpeg: await renderCourtesyOverlayJpeg(input.cachedJpeg, {
7845
7846
  deviceName: input.deviceName,
7846
- reason: "waking"
7847
+ reason
7847
7848
  }),
7848
- source: "cached-snapshot"
7849
+ source: "cached-snapshot",
7850
+ reason
7849
7851
  };
7850
7852
  } catch (err) {
7851
- input.logger?.warn("prestream: cached frame could not be treated — using the card", {
7853
+ input.logger?.warn("sentry: cached frame could not be treated — using the card", {
7852
7854
  ...tags,
7853
7855
  meta: { error: errMsg(err) }
7854
7856
  });
@@ -7856,11 +7858,12 @@ async function composePrestreamPicture(input) {
7856
7858
  return {
7857
7859
  jpeg: await renderCourtesyJpeg({
7858
7860
  deviceName: input.deviceName,
7859
- reason: "waking",
7861
+ reason,
7860
7862
  width: input.width,
7861
7863
  height: input.height
7862
7864
  }),
7863
- source: "generated-card"
7865
+ source: "generated-card",
7866
+ reason
7864
7867
  };
7865
7868
  }
7866
7869
  function planPrestream(input) {
@@ -7875,7 +7878,7 @@ function planPrestream(input) {
7875
7878
  } };
7876
7879
  }
7877
7880
  /**
7878
- * `null` for a codec nobody has read. NOT a default of h264: a prestream in the
7881
+ * `null` for a codec nobody has read. NOT a default of h264: a sentry in the
7879
7882
  * wrong codec is a stream the consumer cannot decode at all, which is worse
7880
7883
  * than the black screen it replaces.
7881
7884
  */
@@ -11977,11 +11980,11 @@ var OPUS_SILENCE_FRAME_SAMPLES = 960;
11977
11980
  var OPUS_SILENCE_PRIME_FRAMES = 6;
11978
11981
  /**
11979
11982
  * Produce ONE canonical 20 ms Opus silence packet by encoding PCM zeros through
11980
- * the audio-codec cap, for the WebRTC session's prestream A/V-sync padding
11983
+ * the audio-codec cap, for the WebRTC session's sentry A/V-sync padding
11981
11984
  * (Opus has no fixed "silence byte" like PCMU's 0xFF — silence must be encoded).
11982
11985
  * A short-lived encode session is created, primed with a few zero frames, and
11983
11986
  * flushed; the LAST steady-state frame is returned. Returns `null` when the cap
11984
- * is unavailable or yields nothing so the caller can skip prestream padding.
11987
+ * is unavailable or yields nothing so the caller can skip sentry padding.
11985
11988
  */
11986
11989
  async function encodeOpusSilenceFrame(api, cfg) {
11987
11990
  let sessionId = null;
@@ -12064,9 +12067,9 @@ function getPlaceholderFrame(kind, codec) {
12064
12067
  return buf;
12065
12068
  }
12066
12069
  //#endregion
12067
- //#region src/stream-broker/stream-broker/prestream-pump.ts
12070
+ //#region src/stream-broker/stream-broker/sentry-pump.ts
12068
12071
  /**
12069
- * The prestream pump: ONE encode, then a 1 fps re-emit until real media lands.
12072
+ * The sentry pump: ONE encode, then a 1 fps re-emit until real media lands.
12070
12073
  *
12071
12074
  * ── What it is for ────────────────────────────────────────────────────────
12072
12075
  * A lazy source is BUILT on demand, and on this hub that build costs 2.2 to
@@ -12088,12 +12091,12 @@ function getPlaceholderFrame(kind, codec) {
12088
12091
  * 3. **It never dials.** The pump has no source, no socket and no demand. It
12089
12092
  * is started alongside the publisher request, never instead of it.
12090
12093
  *
12091
- * Emission is the caller's: {@link PrestreamPumpOptions.emit} is where the
12094
+ * Emission is the caller's: {@link SentryPumpOptions.emit} is where the
12092
12095
  * `isPlaceholder: true` packet is built, because that flag belongs to the
12093
12096
  * broker's packet contract and the containment that reads it lives there.
12094
12097
  */
12095
- var DEFAULT_PRESTREAM_INTERVAL_MS = 1e3;
12096
- var PrestreamPump = class {
12098
+ var DEFAULT_SENTRY_INTERVAL_MS = 1e3;
12099
+ var SentryPump = class {
12097
12100
  options;
12098
12101
  intervalMs;
12099
12102
  tags;
@@ -12105,7 +12108,7 @@ var PrestreamPump = class {
12105
12108
  emitted = 0;
12106
12109
  constructor(options) {
12107
12110
  this.options = options;
12108
- this.intervalMs = options.intervalMs ?? DEFAULT_PRESTREAM_INTERVAL_MS;
12111
+ this.intervalMs = options.intervalMs ?? DEFAULT_SENTRY_INTERVAL_MS;
12109
12112
  this.tags = options.deviceId === void 0 ? {} : { tags: { deviceId: options.deviceId } };
12110
12113
  }
12111
12114
  /** Whether the window is currently being filled (or about to be). */
@@ -12124,16 +12127,16 @@ var PrestreamPump = class {
12124
12127
  this.emitted = 0;
12125
12128
  this.options.prepare({ sourceUrl }).then((frame) => {
12126
12129
  if (!this.active) {
12127
- this.options.logger?.debug("prestream: preparation landed after the window closed", { ...this.tags });
12130
+ this.options.logger?.debug("sentry: preparation landed after the window closed", { ...this.tags });
12128
12131
  return;
12129
12132
  }
12130
12133
  if (frame === null) {
12131
- this.options.logger?.info("prestream: refused — the window goes unfilled", { ...this.tags });
12134
+ this.options.logger?.info("sentry: refused — the window goes unfilled", { ...this.tags });
12132
12135
  this.active = false;
12133
12136
  return;
12134
12137
  }
12135
12138
  this.frame = frame;
12136
- this.options.logger?.info("prestream: filling the wake window", {
12139
+ this.options.logger?.info("sentry: filling the wake window", {
12137
12140
  ...this.tags,
12138
12141
  meta: {
12139
12142
  codec: frame.codec,
@@ -12145,7 +12148,7 @@ var PrestreamPump = class {
12145
12148
  this.tick();
12146
12149
  this.timer = setInterval(() => this.tick(), this.intervalMs);
12147
12150
  }).catch((err) => {
12148
- this.options.logger?.warn("prestream: preparation failed — the window goes unfilled", {
12151
+ this.options.logger?.warn("sentry: preparation failed — the window goes unfilled", {
12149
12152
  ...this.tags,
12150
12153
  meta: { error: errMsg(err) }
12151
12154
  });
@@ -12154,7 +12157,7 @@ var PrestreamPump = class {
12154
12157
  }
12155
12158
  /**
12156
12159
  * Close the window. Called on the first NON-placeholder packet — the one edge
12157
- * the prestream is defined by — and on the broker's own teardown paths so a
12160
+ * the sentry is defined by — and on the broker's own teardown paths so a
12158
12161
  * stopped broker leaves no timer behind.
12159
12162
  */
12160
12163
  stop(reason) {
@@ -12164,7 +12167,7 @@ var PrestreamPump = class {
12164
12167
  clearInterval(this.timer);
12165
12168
  this.timer = void 0;
12166
12169
  }
12167
- this.options.logger?.info("prestream: window closed", {
12170
+ this.options.logger?.info("sentry: window closed", {
12168
12171
  ...this.tags,
12169
12172
  meta: {
12170
12173
  reason,
@@ -12475,12 +12478,12 @@ var StreamBroker = class StreamBroker {
12475
12478
  reconnectTimer;
12476
12479
  placeholderTimer;
12477
12480
  /**
12478
- * The prestream pump, armed by the manager via `setPrestreamProvider`.
12479
- * `undefined` on a broker whose manager supplied none — the pre-prestream
12481
+ * The sentry pump, armed by the manager via `setPrestreamProvider`.
12482
+ * `undefined` on a broker whose manager supplied none — the pre-sentry
12480
12483
  * behaviour, unchanged.
12481
12484
  */
12482
- prestreamPump;
12483
- /** The manager's hook for "real media started" — see `PrestreamProvider`. */
12485
+ sentryPump;
12486
+ /** The manager's hook for "real media started" — see `SentryProvider`. */
12484
12487
  onRealMediaStarted;
12485
12488
  /**
12486
12489
  * Latched once real media has been seen on this session.
@@ -12490,9 +12493,9 @@ var StreamBroker = class StreamBroker {
12490
12493
  * window that real bytes have already closed, and the consumer would get a
12491
12494
  * still picture painted over live video every second. Reset exactly where
12492
12495
  * `firstKeyframeReceived` is — broker stop and suspend — so a battery camera
12493
- * that goes back to sleep gets its prestream again on the next wake.
12496
+ * that goes back to sleep gets its sentry again on the next wake.
12494
12497
  */
12495
- prestreamWindowClosed = false;
12498
+ sentryWindowClosed = false;
12496
12499
  reconnectDelayMs = INITIAL_RECONNECT_DELAY_MS;
12497
12500
  /**
12498
12501
  * Dial rate-limiter (2026-07-23 storm fix): the earliest wall-clock at
@@ -12768,7 +12771,7 @@ var StreamBroker = class StreamBroker {
12768
12771
  * that socket down. In that window `resolveCurrentSource()` truthfully
12769
12772
  * answers with a socket nobody can dial.
12770
12773
  *
12771
- * That cost device 640 its prestream on 2026-09-16: the window re-opened
12774
+ * That cost device 640 its sentry on 2026-09-16: the window re-opened
12772
12775
  * (which `suspend()` does deliberately, for a consumer that never left) with
12773
12776
  * the real url, `planPrestream` refused it `not-lazy`, and the refusal is
12774
12777
  * terminal — the operator's client sat dark for ten seconds and gave up six
@@ -12777,8 +12780,8 @@ var StreamBroker = class StreamBroker {
12777
12780
  * NOT cleared when `start()` is later called with a materialized url: that
12778
12781
  * happens on every wake, and clearing it there is the bug again. A broker
12779
12782
  * genuinely reconfigured onto a permanent mains source keeps a stale value,
12780
- * which costs nothing — `prestreamEligible` (battery + declared signals) is
12781
- * the authority on whether a camera gets a prestream at all, and it is asked
12783
+ * which costs nothing — `sentryEligible` (battery + declared signals) is
12784
+ * the authority on whether a camera gets a sentry at all, and it is asked
12782
12785
  * first, in the manager.
12783
12786
  */
12784
12787
  lazySourceUrl;
@@ -13041,7 +13044,7 @@ var StreamBroker = class StreamBroker {
13041
13044
  this.requestSourceRefresh = notify;
13042
13045
  }
13043
13046
  /**
13044
- * Arm the PRESTREAM — the fill for the window between "someone asked for this
13047
+ * Arm the SENTRY — the fill for the window between "someone asked for this
13045
13048
  * camera" and "the camera is awake".
13046
13049
  *
13047
13050
  * Manager-owned, because everything the fill needs is the manager's: the
@@ -13049,13 +13052,13 @@ var StreamBroker = class StreamBroker {
13049
13052
  * snapshot, its name, and the ffmpeg binary. The broker contributes the one
13050
13053
  * thing it owns — WHEN the window is open — and nothing else.
13051
13054
  *
13052
- * A broker with no provider behaves exactly as it did before the prestream
13055
+ * A broker with no provider behaves exactly as it did before the sentry
13053
13056
  * existed: the lazy branch asks the publisher to materialize and the consumer
13054
13057
  * sees black, which is the outcome every refusal falls back to.
13055
13058
  */
13056
13059
  setPrestreamProvider(provider) {
13057
13060
  this.onRealMediaStarted = provider.onRealMediaStarted;
13058
- this.prestreamPump = new PrestreamPump({
13061
+ this.sentryPump = new SentryPump({
13059
13062
  prepare: provider.prepare,
13060
13063
  emit: (frame) => {
13061
13064
  const now = Date.now();
@@ -13175,7 +13178,7 @@ var StreamBroker = class StreamBroker {
13175
13178
  *
13176
13179
  * Here and not only in `start()` because a broker that has never dialled is a
13177
13180
  * real and common state: a battery camera nobody has asked for yet, with a
13178
- * prestream consumer attached, has a recipe and no socket. Learning it from
13181
+ * sentry consumer attached, has a recipe and no socket. Learning it from
13179
13182
  * the dial alone would leave exactly that broker unable to describe itself.
13180
13183
  */
13181
13184
  noteLazyUrl(url) {
@@ -13252,8 +13255,8 @@ var StreamBroker = class StreamBroker {
13252
13255
  clearInterval(this.placeholderTimer);
13253
13256
  this.placeholderTimer = void 0;
13254
13257
  }
13255
- this.prestreamPump?.stop("broker stopped");
13256
- this.prestreamWindowClosed = false;
13258
+ this.sentryPump?.stop("broker stopped");
13259
+ this.sentryWindowClosed = false;
13257
13260
  if (this.reconnectTimer) {
13258
13261
  clearTimeout(this.reconnectTimer);
13259
13262
  this.reconnectTimer = void 0;
@@ -13423,7 +13426,7 @@ var StreamBroker = class StreamBroker {
13423
13426
  *
13424
13427
  * - the caller has already checked the signal is ENABLED for this camera
13425
13428
  * (the broker manager owns that setting), and
13426
- * - somebody is actually waiting on the prestream. Waking a camera nobody is
13429
+ * - somebody is actually waiting on the sentry. Waking a camera nobody is
13427
13430
  * watching is the one thing a battery camera must never do, and a signal
13428
13431
  * arriving with no consumer is exactly that.
13429
13432
  *
@@ -13466,7 +13469,7 @@ var StreamBroker = class StreamBroker {
13466
13469
  if (delay <= 0) return;
13467
13470
  this.wakeHoldTimer = setTimeout(() => {
13468
13471
  this.wakeHoldTimer = void 0;
13469
- this.logger?.info("wake hold lapsed — back to the prestream picture", {
13472
+ this.logger?.info("wake hold lapsed — back to the sentry picture", {
13470
13473
  tags: { deviceId: this.numericDeviceId },
13471
13474
  meta: {
13472
13475
  brokerId: this.deviceId,
@@ -13479,20 +13482,20 @@ var StreamBroker = class StreamBroker {
13479
13482
  this.wakeHoldTimer.unref?.();
13480
13483
  }
13481
13484
  /**
13482
- * Anything that must be FED, prestream sessions included.
13485
+ * Anything that must be FED, sentry sessions included.
13483
13486
  *
13484
- * The only consumer of this is the prestream pump: it says "somebody is
13487
+ * The only consumer of this is the sentry pump: it says "somebody is
13485
13488
  * watching, keep the picture going", and says nothing about whether the
13486
13489
  * camera may be dialled. {@link hasLiveIntent} answers that, and it is the
13487
13490
  * one every dial path asks.
13488
13491
  */
13489
13492
  hasAnyConsumer() {
13490
13493
  if (this.hasLiveIntent()) return true;
13491
- if (this.prestreamHolds > 0) return true;
13494
+ if (this.sentryHolds > 0) return true;
13492
13495
  return this.rtspRestreamer.getPrestreamSessionCount() > 0;
13493
13496
  }
13494
13497
  /**
13495
- * Somebody is DESCRIBING a prestream and has no session yet.
13498
+ * Somebody is DESCRIBING a sentry and has no session yet.
13496
13499
  *
13497
13500
  * The RTSP dispatch reads the SDP before `addSession` runs, so a window that
13498
13501
  * waits for the session is too late: the consumer is handed an empty SDP and
@@ -13500,28 +13503,28 @@ var StreamBroker = class StreamBroker {
13500
13503
  * on the attach and closed 42 ms later having emitted zero frames, because
13501
13504
  * ffmpeg had already given up.
13502
13505
  *
13503
- * This is the prestream counterpart of `BrokerWarmUp` and its exact opposite
13506
+ * This is the sentry counterpart of `BrokerWarmUp` and its exact opposite
13504
13507
  * in effect: the warm-up subscribes demand, which DIALS; this opens the
13505
13508
  * picture, which never does. A battery camera is not touched.
13506
13509
  */
13507
13510
  openPrestreamWindow() {
13508
- this.prestreamHolds += 1;
13511
+ this.sentryHolds += 1;
13509
13512
  this.checkDemand();
13510
13513
  let released = false;
13511
13514
  return () => {
13512
13515
  if (released) return;
13513
13516
  released = true;
13514
- this.prestreamHolds = Math.max(0, this.prestreamHolds - 1);
13517
+ this.sentryHolds = Math.max(0, this.sentryHolds - 1);
13515
13518
  this.checkDemand();
13516
13519
  };
13517
13520
  }
13518
- /** DESCRIBE-window prestream holds: sessions that do not exist yet. */
13519
- prestreamHolds = 0;
13521
+ /** DESCRIBE-window sentry holds: sessions that do not exist yet. */
13522
+ sentryHolds = 0;
13520
13523
  /**
13521
13524
  * Consumers that may DIAL. Every term of the former `hasDemand`, with the
13522
- * RTSP session count filtered to exclude prestream dials, plus the wake hold.
13525
+ * RTSP session count filtered to exclude sentry dials, plus the wake hold.
13523
13526
  *
13524
- * For a broker with no prestream session attached this is term-for-term what
13527
+ * For a broker with no sentry session attached this is term-for-term what
13525
13528
  * `hasDemand` was, which is why every existing camera, consumer and test
13526
13529
  * behaves identically.
13527
13530
  */
@@ -13566,7 +13569,7 @@ var StreamBroker = class StreamBroker {
13566
13569
  });
13567
13570
  }
13568
13571
  /**
13569
- * Encode ONE canonical 20 ms Opus silence packet for a session's prestream
13572
+ * Encode ONE canonical 20 ms Opus silence packet for a session's sentry
13570
13573
  * A/V-sync padding (Opus has no fixed silence byte). Returns `null` when the
13571
13574
  * audio-codec cap is unavailable. See {@link encodeOpusSilenceFrame}.
13572
13575
  */
@@ -13676,16 +13679,16 @@ var StreamBroker = class StreamBroker {
13676
13679
  if (!this.hasLiveIntent() && !this.manualStop && !this.stopping) this.suspend();
13677
13680
  }, SUSPEND_GRACE_MS);
13678
13681
  }
13679
- this.prestreamWanted = this.hasAnyConsumer() && !this.hasLiveIntent();
13682
+ this.sentryWanted = this.hasAnyConsumer() && !this.hasLiveIntent();
13680
13683
  this.reconcilePrestreamWindow();
13681
13684
  }
13682
13685
  /**
13683
- * Open or close the prestream window to match {@link prestreamWanted}.
13686
+ * Open or close the sentry window to match {@link sentryWanted}.
13684
13687
  *
13685
- * This is the half that was missing. `prestreamWanted` has been computed
13688
+ * This is the half that was missing. `sentryWanted` has been computed
13686
13689
  * correctly since the feature shipped, but the only thing that ever STARTED
13687
13690
  * the pump was the lazy branch of `start()` — a DIAL, which needs live
13688
- * intent, which a prestream session does not have by construction. So the
13691
+ * intent, which a sentry session does not have by construction. So the
13689
13692
  * window opened only when something else had already woken the camera, and
13690
13693
  * `suspend()` closed it for good.
13691
13694
  *
@@ -13695,22 +13698,22 @@ var StreamBroker = class StreamBroker {
13695
13698
  * demand check costs one encode per window and no more.
13696
13699
  */
13697
13700
  reconcilePrestreamWindow() {
13698
- if (!this.prestreamPump) return;
13699
- if (this.prestreamWanted && !this.prestreamWindowClosed) {
13701
+ if (!this.sentryPump) return;
13702
+ if (this.sentryWanted && !this.sentryWindowClosed) {
13700
13703
  const url = this.lazySourceUrl ?? this.resolveCurrentSource()?.url ?? this.source?.url;
13701
- if (url !== void 0) this.prestreamPump.start(url);
13704
+ if (url !== void 0) this.sentryPump.start(url);
13702
13705
  return;
13703
13706
  }
13704
- if (!this.prestreamWanted) this.prestreamPump.stop("no prestream consumer");
13707
+ if (!this.sentryWanted) this.sentryPump.stop("no sentry consumer");
13705
13708
  }
13706
13709
  /**
13707
- * Whether a prestream picture should be flowing right now: somebody is
13710
+ * Whether a sentry picture should be flowing right now: somebody is
13708
13711
  * watching and the camera is not up. Read by the pump.
13709
13712
  */
13710
- prestreamWanted = false;
13713
+ sentryWanted = false;
13711
13714
  /** Whether the picture should be flowing — the pump's one question. */
13712
13715
  wantsPrestream() {
13713
- return this.prestreamWanted;
13716
+ return this.sentryWanted;
13714
13717
  }
13715
13718
  /** Suspend the stream: kill ffmpeg/native client, clear buffers, go idle. Source is preserved for resume. */
13716
13719
  suspend() {
@@ -13735,8 +13738,8 @@ var StreamBroker = class StreamBroker {
13735
13738
  clearInterval(this.placeholderTimer);
13736
13739
  this.placeholderTimer = void 0;
13737
13740
  }
13738
- this.prestreamPump?.stop("broker suspended");
13739
- this.prestreamWindowClosed = false;
13741
+ this.sentryPump?.stop("broker suspended");
13742
+ this.sentryWindowClosed = false;
13740
13743
  this.reconcilePrestreamWindow();
13741
13744
  this.preBuffer.clear();
13742
13745
  this.decoderSeedBuffer.clear();
@@ -13821,13 +13824,13 @@ var StreamBroker = class StreamBroker {
13821
13824
  }
13822
13825
  pushEncodedPacket(packet) {
13823
13826
  if (this.stopping) return;
13824
- if (packet.isPlaceholder !== true && !this.prestreamWindowClosed) {
13825
- this.prestreamWindowClosed = true;
13826
- this.prestreamPump?.stop("first real packet");
13827
+ if (packet.isPlaceholder !== true && !this.sentryWindowClosed) {
13828
+ this.sentryWindowClosed = true;
13829
+ this.sentryPump?.stop("first real packet");
13827
13830
  try {
13828
13831
  this.onRealMediaStarted?.();
13829
13832
  } catch (err) {
13830
- this.logger?.debug("prestream: real-media hook threw", {
13833
+ this.logger?.debug("sentry: real-media hook threw", {
13831
13834
  tags: { deviceId: this.numericDeviceId ?? 0 },
13832
13835
  meta: { error: String(err) }
13833
13836
  });
@@ -15576,7 +15579,7 @@ var StreamBroker = class StreamBroker {
15576
15579
  });
15577
15580
  this._status = "error";
15578
15581
  this.notifySourceRefresh();
15579
- if (!this.prestreamWindowClosed) this.prestreamPump?.start(source.url);
15582
+ if (!this.sentryWindowClosed) this.sentryPump?.start(source.url);
15580
15583
  this.scheduleReconnect();
15581
15584
  return;
15582
15585
  }
@@ -16308,16 +16311,16 @@ var DeviceOverrideSchema = object({
16308
16311
  sourceParser: record(string(), SourceParserSettingSchema).optional(),
16309
16312
  sourceParserArgs: record(string(), SourceParserArgsEntrySchema).optional(),
16310
16313
  /**
16311
- * The on-demand PRESTREAM, per camera.
16314
+ * The on-demand SENTRY, per camera.
16312
16315
  *
16313
16316
  * Absent means the operator has never touched it, which is NOT the same as
16314
16317
  * off: `enabledSignals` absent means "every signal this camera recommends",
16315
- * so a Reolink works the moment a prestream URL is dialled without an
16318
+ * so a Reolink works the moment a sentry URL is dialled without an
16316
16319
  * operator hunting for a checkbox. An empty ARRAY is a deliberate "none" and
16317
16320
  * is honoured — the two are different answers and the shape keeps them
16318
16321
  * apart.
16319
16322
  */
16320
- prestream: object({
16323
+ sentry: object({
16321
16324
  /** Signal codes allowed to wake this camera. Absent ⇒ the recommended set. */
16322
16325
  enabledSignals: array(string()).optional(),
16323
16326
  /** How long the camera stays up after the LAST signal. Absent ⇒ default. */
@@ -16511,13 +16514,13 @@ var StreamBrokerManager = class StreamBrokerManager {
16511
16514
  /** Per-device published cam-stream registry. */
16512
16515
  cameraStreams = /* @__PURE__ */ new Map();
16513
16516
  /**
16514
- * The encoded prestream frame per broker, with the digest of the picture it
16517
+ * The encoded sentry frame per broker, with the digest of the picture it
16515
16518
  * was made from. One entry is one still image — kilobytes — and it is
16516
16519
  * dropped with the broker in `releaseBroker`.
16517
16520
  */
16518
- /** Brokers with a background prestream re-encode in flight (single-flight). */
16519
- prestreamRefreshing = /* @__PURE__ */ new Set();
16520
- prestreamFrames = /* @__PURE__ */ new Map();
16521
+ /** Brokers with a background sentry re-encode in flight (single-flight). */
16522
+ sentryRefreshing = /* @__PURE__ */ new Set();
16523
+ sentryFrames = /* @__PURE__ */ new Map();
16521
16524
  /** Monotonic insertion counter per device — feeds `CameraStreamInternal.order`. */
16522
16525
  streamOrderSeq = /* @__PURE__ */ new Map();
16523
16526
  /** Persisted operator intent: which cam stream serves which profile. */
@@ -17409,7 +17412,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17409
17412
  * client-side and we get a typed payload.
17410
17413
  */
17411
17414
  /**
17412
- * Build the per-broker PRESTREAM provider — the fill for the window between
17415
+ * Build the per-broker SENTRY provider — the fill for the window between
17413
17416
  * "someone asked for this camera" and "the camera is awake".
17414
17417
  *
17415
17418
  * On this hub that window is 2.2-12.4 s for a lazy source, and it is not
@@ -17422,19 +17425,19 @@ var StreamBrokerManager = class StreamBrokerManager {
17422
17425
  * cached snapshot, its name, and the ffmpeg binary path.
17423
17426
  *
17424
17427
  * `null` is a REFUSAL, named in the log. Refusing is cheap — the consumer
17425
- * gets the black screen it got before the prestream existed — and the
17428
+ * gets the black screen it got before the sentry existed — and the
17426
17429
  * alternative for an unknown geometry is the decoder freeze the whole
17427
17430
  * synthetic-frame path is shaped around.
17428
17431
  */
17429
17432
  buildPrestreamProvider(deviceId, camStreamId, brokerId, logger) {
17430
17433
  return {
17431
17434
  prepare: async ({ sourceUrl }) => {
17432
- const gate = prestreamEligible({
17435
+ const gate = sentryEligible({
17433
17436
  batteryOperated: await this.isBatteryOperated(deviceId),
17434
17437
  declaresSignals: (await this.declaredSignalCodes(deviceId)).length > 0
17435
17438
  });
17436
17439
  if (!gate.eligible) {
17437
- logger.info("prestream: not offered for this camera", {
17440
+ logger.info("sentry: not offered for this camera", {
17438
17441
  tags: { deviceId },
17439
17442
  meta: {
17440
17443
  brokerId,
@@ -17452,7 +17455,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17452
17455
  codec
17453
17456
  });
17454
17457
  if ("refusal" in planned) {
17455
- logger.info("prestream: no fill for this camera", {
17458
+ logger.info("sentry: no fill for this camera", {
17456
17459
  tags: { deviceId },
17457
17460
  meta: {
17458
17461
  refusal: planned.refusal,
@@ -17472,7 +17475,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17472
17475
  * The window shows the camera's last snapshot, and nothing was
17473
17476
  * refreshing it: a battery camera refuses a capture while it believes
17474
17477
  * itself asleep, and that belief lags the wake by seconds — so the only
17475
- * attempts ever made were the prestream's own, while composing, which is
17478
+ * attempts ever made were the sentry's own, while composing, which is
17476
17479
  * BEFORE any media exists. Measured on device 640 (2026-09-16): four
17477
17480
  * wakes in forty minutes, the encoded picture `bytes=23912` every time,
17478
17481
  * and between first packet and suspend not one capture was even
@@ -17495,12 +17498,12 @@ var StreamBrokerManager = class StreamBrokerManager {
17495
17498
  const api = this.api;
17496
17499
  if (!api) return;
17497
17500
  api.snapshot.getSnapshot.query({ deviceId }).then(() => {
17498
- logger.debug("prestream: picture refreshed from the live window", {
17501
+ logger.debug("sentry: picture refreshed from the live window", {
17499
17502
  tags: { deviceId },
17500
17503
  meta: { brokerId }
17501
17504
  });
17502
17505
  }).catch((err) => {
17503
- logger.debug("prestream: live-window refresh failed — keeping the older picture", {
17506
+ logger.debug("sentry: live-window refresh failed — keeping the older picture", {
17504
17507
  tags: { deviceId },
17505
17508
  meta: {
17506
17509
  brokerId,
@@ -17521,7 +17524,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17521
17524
  */
17522
17525
  async preparePrestreamFrame(deviceId, brokerId, plan, logger) {
17523
17526
  if (!this.api) {
17524
- logger.info("prestream: no api access — the window goes unfilled", { tags: { deviceId } });
17527
+ logger.info("sentry: no api access — the window goes unfilled", { tags: { deviceId } });
17525
17528
  return null;
17526
17529
  }
17527
17530
  const api = this.api;
@@ -17530,7 +17533,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17530
17533
  const image = await api.snapshot.getSnapshot.query({ deviceId });
17531
17534
  if (image) cachedJpeg = Buffer.from(image.base64, "base64");
17532
17535
  } catch (err) {
17533
- logger.debug("prestream: cached snapshot read failed — falling back to the card", {
17536
+ logger.debug("sentry: cached snapshot read failed — falling back to the card", {
17534
17537
  tags: { deviceId },
17535
17538
  meta: { error: errMsg(err) }
17536
17539
  });
@@ -17540,15 +17543,15 @@ var StreamBrokerManager = class StreamBrokerManager {
17540
17543
  const device = await api.deviceManager.getDevice.query({ deviceId });
17541
17544
  if (device?.name) deviceName = device.name;
17542
17545
  } catch (err) {
17543
- logger.debug("prestream: device name read failed — using the numeric id", {
17546
+ logger.debug("sentry: device name read failed — using the numeric id", {
17544
17547
  tags: { deviceId },
17545
17548
  meta: { error: errMsg(err) }
17546
17549
  });
17547
17550
  }
17548
17551
  const key = `${createHash("sha1").update(cachedJpeg ?? Buffer.alloc(0)).update(deviceName).digest("hex")}:${String(plan.width)}x${String(plan.height)}:${plan.codec}`;
17549
- const cached = this.prestreamFrames.get(brokerId);
17552
+ const cached = this.sentryFrames.get(brokerId);
17550
17553
  if (cached && cached.key === key) {
17551
- logger.debug("prestream: re-using the encoded frame", {
17554
+ logger.debug("sentry: re-using the encoded frame", {
17552
17555
  tags: { deviceId },
17553
17556
  meta: { bytes: cached.frame.annexB.length }
17554
17557
  });
@@ -17557,7 +17560,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17557
17560
  const cachedGeometry = cached ? cached.key.slice(cached.key.indexOf(":")) : null;
17558
17561
  const wantedGeometry = key.slice(key.indexOf(":"));
17559
17562
  if (cached && cachedGeometry === wantedGeometry) {
17560
- logger.info("prestream: serving the previous picture while the new one encodes", {
17563
+ logger.info("sentry: serving the previous picture while the new one encodes", {
17561
17564
  tags: { deviceId },
17562
17565
  meta: { bytes: cached.frame.annexB.length }
17563
17566
  });
@@ -17582,10 +17585,11 @@ var StreamBrokerManager = class StreamBrokerManager {
17582
17585
  logger,
17583
17586
  deviceId
17584
17587
  });
17585
- logger.info("prestream: picture composed", {
17588
+ logger.info("sentry: picture composed", {
17586
17589
  tags: { deviceId },
17587
17590
  meta: {
17588
17591
  source: picture.source,
17592
+ reason: picture.reason,
17589
17593
  width: plan.width,
17590
17594
  height: plan.height,
17591
17595
  codec: plan.codec
@@ -17601,7 +17605,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17601
17605
  deviceId
17602
17606
  });
17603
17607
  } catch (err) {
17604
- logger.warn("prestream: encode failed — the window goes unfilled", {
17608
+ logger.warn("sentry: encode failed — the window goes unfilled", {
17605
17609
  tags: { deviceId },
17606
17610
  meta: { error: errMsg(err) }
17607
17611
  });
@@ -17611,7 +17615,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17611
17615
  annexB,
17612
17616
  codec: plan.codec
17613
17617
  };
17614
- this.prestreamFrames.set(brokerId, {
17618
+ this.sentryFrames.set(brokerId, {
17615
17619
  key,
17616
17620
  frame
17617
17621
  });
@@ -17625,10 +17629,10 @@ var StreamBrokerManager = class StreamBrokerManager {
17625
17629
  * operator is actually waiting for.
17626
17630
  */
17627
17631
  encodePrestreamInBackground(deviceId, brokerId, plan, key, cachedJpeg, deviceName, logger) {
17628
- if (this.prestreamRefreshing.has(brokerId)) return;
17629
- this.prestreamRefreshing.add(brokerId);
17632
+ if (this.sentryRefreshing.has(brokerId)) return;
17633
+ this.sentryRefreshing.add(brokerId);
17630
17634
  this.composeAndEncodePrestream(deviceId, brokerId, plan, key, cachedJpeg, deviceName, logger).catch(() => {}).finally(() => {
17631
- this.prestreamRefreshing.delete(brokerId);
17635
+ this.sentryRefreshing.delete(brokerId);
17632
17636
  });
17633
17637
  }
17634
17638
  subscribePlaceholderStateSources(bus) {
@@ -19635,7 +19639,7 @@ var StreamBrokerManager = class StreamBrokerManager {
19635
19639
  reason: "unknown-code"
19636
19640
  };
19637
19641
  }
19638
- const settings = this.deviceOverrides.get(input.deviceId)?.prestream;
19642
+ const settings = this.deviceOverrides.get(input.deviceId)?.sentry;
19639
19643
  if (!(settings?.enabledSignals ?? declared).includes(input.code)) return {
19640
19644
  accepted: false,
19641
19645
  reason: "not-enabled"
@@ -19817,11 +19821,11 @@ var StreamBrokerManager = class StreamBrokerManager {
19817
19821
  label: hwAccelOptionLabel(setting)
19818
19822
  }));
19819
19823
  const declaredSignals = await this.declaredSignalList(deviceId);
19820
- const prestreamGate = prestreamEligible({
19824
+ const sentryGate = sentryEligible({
19821
19825
  batteryOperated: await this.isBatteryOperated(deviceId),
19822
19826
  declaresSignals: declaredSignals.length > 0
19823
19827
  });
19824
- const prestreamOffered = prestreamGate.eligible;
19828
+ const sentryOffered = sentryGate.eligible;
19825
19829
  const streamTabs = streams.filter((s) => !s.camStreamId.startsWith("derived:")).map((stream) => {
19826
19830
  const camStreamId = stream.camStreamId;
19827
19831
  const brokerId = brokerIdFor(deviceId, camStreamId);
@@ -19921,18 +19925,18 @@ var StreamBrokerManager = class StreamBrokerManager {
19921
19925
  tooltip: "Copy muted URL to clipboard"
19922
19926
  }]
19923
19927
  },
19924
- ...prestreamOffered ? [{
19928
+ ...sentryOffered ? [{
19925
19929
  type: "text",
19926
19930
  key: `rtspPrestreamUrl:${camStreamId}`,
19927
- label: "RTSP URL (prestream)",
19931
+ label: "RTSP URL (sentry)",
19928
19932
  description: "Video-only. Shows this camera’s last picture while it sleeps and cuts to live video when one of its wake signals fires — without a consumer on this URL ever keeping the camera awake.",
19929
19933
  readonlyField: true,
19930
19934
  span: 2,
19931
- value: rtspEntry?.url ? `${rtspEntry.url}/prestream` : "inactive",
19935
+ value: rtspEntry?.url ? `${rtspEntry.url}/sentry` : "inactive",
19932
19936
  actions: [{
19933
19937
  action: "copy-value",
19934
19938
  icon: "copy",
19935
- tooltip: "Copy prestream URL to clipboard"
19939
+ tooltip: "Copy sentry URL to clipboard"
19936
19940
  }]
19937
19941
  }] : [],
19938
19942
  {
@@ -20120,25 +20124,25 @@ var StreamBrokerManager = class StreamBrokerManager {
20120
20124
  ]
20121
20125
  }]
20122
20126
  };
20123
- const prestreamCfg = override?.prestream;
20124
- const prestreamSections = prestreamGate.eligible ? [{
20125
- id: "stream-broker-prestream",
20127
+ const sentryCfg = override?.sentry;
20128
+ const sentrySections = sentryGate.eligible ? [{
20129
+ id: "stream-broker-sentry",
20126
20130
  title: "Wake signals",
20127
20131
  tab: "stream-broker",
20128
20132
  location: "top-tab",
20129
20133
  order: 50,
20130
- description: "A consumer can dial this camera’s prestream URL (the profile URL with /prestream) and be shown the last picture while the camera sleeps. It is fed without keeping the camera awake: only the signals below wake it, and it goes back to sleep once they stop.",
20134
+ description: "A consumer can dial this camera’s sentry URL (the profile URL with /sentry) and be shown the last picture while the camera sleeps. It is fed without keeping the camera awake: only the signals below wake it, and it goes back to sleep once they stop.",
20131
20135
  fields: [...declaredSignals.map((signal) => ({
20132
20136
  type: "boolean",
20133
20137
  style: "switch",
20134
- key: `prestreamSignal:${signal.code}`,
20138
+ key: `sentrySignal:${signal.code}`,
20135
20139
  label: signal.label,
20136
20140
  description: signal.recommended ? "Recommended by this camera’s driver." : "Offered by this camera’s driver.",
20137
20141
  default: signal.recommended,
20138
- value: prestreamCfg?.enabledSignals === void 0 ? true : prestreamCfg.enabledSignals.includes(signal.code)
20142
+ value: sentryCfg?.enabledSignals === void 0 ? true : sentryCfg.enabledSignals.includes(signal.code)
20139
20143
  })), {
20140
20144
  type: "number",
20141
- key: "prestreamHoldMs",
20145
+ key: "sentryHoldMs",
20142
20146
  label: "Stay awake after the last signal",
20143
20147
  description: "How long the camera keeps streaming once its signals stop. Extended by each new signal, never stacked — continuous motion keeps it up and it sleeps this long after the last one. One run is capped at five minutes whatever this says, and a camera whose sensor never stops is left alone for ten minutes after that.",
20144
20148
  min: 1e3,
@@ -20146,7 +20150,7 @@ var StreamBrokerManager = class StreamBrokerManager {
20146
20150
  step: 1e3,
20147
20151
  unit: "ms",
20148
20152
  default: DEFAULT_WAKE_HOLD_MS,
20149
- value: prestreamCfg?.holdMs ?? 15e3
20153
+ value: sentryCfg?.holdMs ?? 15e3
20150
20154
  }]
20151
20155
  }] : [];
20152
20156
  const diagnosticsSection = {
@@ -20175,7 +20179,7 @@ var StreamBrokerManager = class StreamBrokerManager {
20175
20179
  };
20176
20180
  return { sections: [
20177
20181
  streamBrokerSection,
20178
- ...prestreamSections,
20182
+ ...sentrySections,
20179
20183
  diagnosticsSection
20180
20184
  ] };
20181
20185
  }
@@ -20289,27 +20293,27 @@ var StreamBrokerManager = class StreamBrokerManager {
20289
20293
  nextOverride.sourceParserArgs = spa;
20290
20294
  continue;
20291
20295
  }
20292
- if (fieldKey.startsWith("prestreamSignal:")) {
20296
+ if (fieldKey.startsWith("sentrySignal:")) {
20293
20297
  overrideDirty = true;
20294
20298
  const next = nextEnabledSignals({
20295
20299
  declared: await this.declaredSignalCodes(deviceId),
20296
- stored: nextOverride.prestream?.enabledSignals,
20297
- code: fieldKey.slice(16),
20300
+ stored: nextOverride.sentry?.enabledSignals,
20301
+ code: fieldKey.slice(13),
20298
20302
  enabled: value === null || value === void 0 ? true : Boolean(value)
20299
20303
  });
20300
- nextOverride.prestream = {
20301
- ...nextOverride.prestream,
20304
+ nextOverride.sentry = {
20305
+ ...nextOverride.sentry,
20302
20306
  enabledSignals: [...next]
20303
20307
  };
20304
20308
  continue;
20305
20309
  }
20306
- if (fieldKey === "prestreamHoldMs") {
20310
+ if (fieldKey === "sentryHoldMs") {
20307
20311
  overrideDirty = true;
20308
20312
  const raw = typeof value === "number" ? value : Number(value);
20309
20313
  if (!Number.isFinite(raw)) continue;
20310
20314
  const clamped = Math.min(3e5, Math.max(1e3, Math.round(raw)));
20311
- nextOverride.prestream = {
20312
- ...nextOverride.prestream,
20315
+ nextOverride.sentry = {
20316
+ ...nextOverride.sentry,
20313
20317
  holdMs: clamped
20314
20318
  };
20315
20319
  continue;
@@ -21152,7 +21156,7 @@ var StreamBrokerManager = class StreamBrokerManager {
21152
21156
  this.streamOfflineReasonByBroker.delete(brokerId);
21153
21157
  await broker.stop();
21154
21158
  this.brokers.delete(brokerId);
21155
- this.prestreamFrames.delete(brokerId);
21159
+ this.sentryFrames.delete(brokerId);
21156
21160
  this.sweepFrameSubscriptions(brokerId);
21157
21161
  this.rtspProvider.persistTokens();
21158
21162
  this.syncProfileRestreamers(deviceId);
@@ -24720,7 +24724,7 @@ var AdaptiveSession = class AdaptiveSession {
24720
24724
  * silence packets (0xFF bytes, 160 samples each = 20 ms) so the audio
24721
24725
  * sender's first wall-clock instant aligns with the video sender's first
24722
24726
  * wall-clock instant, then the real packet continues seamlessly. See
24723
- * `prestreamAudioSilenceIfNeeded` + `computeAudioSilencePadPackets`.
24727
+ * `sentryAudioSilenceIfNeeded` + `computeAudioSilencePadPackets`.
24724
24728
  */
24725
24729
  firstAudioFramePadded = false;
24726
24730
  /** PCMU frame size in samples per packet — 160 = 20 ms at 8 kHz. */
@@ -25116,7 +25120,7 @@ var AdaptiveSession = class AdaptiveSession {
25116
25120
  return this.audioClock().codec === "opus";
25117
25121
  }
25118
25122
  /**
25119
- * Inject the canonical 20 ms Opus silence packet used for prestream A/V-sync
25123
+ * Inject the canonical 20 ms Opus silence packet used for sentry A/V-sync
25120
25124
  * padding. Broker-provided (encoded via the audio-codec cap) because Opus has
25121
25125
  * no fixed silence byte the way PCMU does (0xFF).
25122
25126
  */
@@ -25130,7 +25134,7 @@ var AdaptiveSession = class AdaptiveSession {
25130
25134
  const senderCodec = this.audioSender.codec;
25131
25135
  const fallbackPt = codec === "Pcmu" || codec === "Pcma" ? 0 : 111;
25132
25136
  const pt = senderCodec?.payloadType ?? fallbackPt;
25133
- this.prestreamAudioSilenceIfNeeded(rtpTs >>> 0, pt);
25137
+ this.sentryAudioSilenceIfNeeded(rtpTs >>> 0, pt);
25134
25138
  try {
25135
25139
  const header = new werift.RtpHeader();
25136
25140
  header.payloadType = pt;
@@ -25169,7 +25173,7 @@ var AdaptiveSession = class AdaptiveSession {
25169
25173
  * diag reads ~0). Any failure on a single `sendRtp` is logged and the loop
25170
25174
  * continues — partial alignment is better than aborting.
25171
25175
  */
25172
- prestreamAudioSilenceIfNeeded(realRtpTs, payloadType) {
25176
+ sentryAudioSilenceIfNeeded(realRtpTs, payloadType) {
25173
25177
  if (this.firstAudioFramePadded) return;
25174
25178
  this.firstAudioFramePadded = true;
25175
25179
  if (!this.audioSender || !_werift) return;