@camstack/addon-pipeline 1.2.253 → 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-Bg9efO4H.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-DYYAMbPi.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
@@ -3,12 +3,12 @@ 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-G5Uib9Bn.js");
7
- const require_node = require("../node-ByNljnzV.js");
8
- const require_restream_intent = require("../restream-intent-C4adO0P8.js");
6
+ const require_dist = require("../dist-DQsOgAJp.js");
7
+ const require_node = require("../node-Bg7LGOQ3.js");
8
+ const require_restream_intent = require("../restream-intent-VVJiUAkh.js");
9
9
  const require_remote_restream = require("../remote-restream-CO36Sr30.js");
10
10
  const require_retire_root_keys = require("../retire-root-keys-Csb8z2f3.js");
11
- const require_segment_demux_js = require("../segment-demux-js-CtQrIvn7.js");
11
+ const require_segment_demux_js = require("../segment-demux-js-BIrnzZiP.js");
12
12
  let node_os = require("node:os");
13
13
  node_os = require_chunk.__toESM(node_os);
14
14
  let node_crypto = require("node:crypto");
@@ -654,8 +654,8 @@ function healthEventIsOperatorFacing(camStreamId) {
654
654
  return !PRIVATE_STREAM_PREFIXES.some((prefix) => camStreamId.startsWith(prefix));
655
655
  }
656
656
  //#endregion
657
- //#region src/stream-broker/stream-broker/prestream-eligibility.ts
658
- function prestreamEligible(input) {
657
+ //#region src/stream-broker/stream-broker/sentry-eligibility.ts
658
+ function sentryEligible(input) {
659
659
  if (input.batteryOperated === null || input.declaresSignals === null) return {
660
660
  eligible: false,
661
661
  reason: "unknown"
@@ -671,7 +671,7 @@ function prestreamEligible(input) {
671
671
  return { eligible: true };
672
672
  }
673
673
  //#endregion
674
- //#region src/stream-broker/stream-broker/prestream-signal-selection.ts
674
+ //#region src/stream-broker/stream-broker/sentry-signal-selection.ts
675
675
  function nextEnabledSignals(input) {
676
676
  const base = input.stored ?? input.declared;
677
677
  const set = new Set(base);
@@ -689,7 +689,7 @@ function nextEnabledSignals(input) {
689
689
  * A stream a consumer merely watches is not a reason to wake a battery camera —
690
690
  * a Frigate-style puller holds a session open for ever, and treating that as
691
691
  * demand keeps the camera awake for ever, which is the whole point of the
692
- * battery (D173). So a prestream consumer is FED without being INTENT, and the
692
+ * battery (D173). So a sentry consumer is FED without being INTENT, and the
693
693
  * only thing that dials is a signal the camera reported about itself.
694
694
  *
695
695
  * This module is the timing half of that, and it is pure so the arithmetic can
@@ -3130,11 +3130,11 @@ var RtspRestreamer = class {
3130
3130
  return this.sessions.size;
3131
3131
  }
3132
3132
  /**
3133
- * Sessions that count as LIVE INTENT — everything except a prestream dial.
3133
+ * Sessions that count as LIVE INTENT — everything except a sentry dial.
3134
3134
  *
3135
3135
  * The split exists so a Frigate-style puller can hold a session open for ever
3136
3136
  * against a battery camera without keeping it awake (D173). For a broker with
3137
- * no prestream session this equals {@link getSessionCount} exactly, which is
3137
+ * no sentry session this equals {@link getSessionCount} exactly, which is
3138
3138
  * why nothing else changed behaviour.
3139
3139
  */
3140
3140
  getLiveIntentSessionCount() {
@@ -3142,7 +3142,7 @@ var RtspRestreamer = class {
3142
3142
  for (const session of this.sessions.values()) if (!session.isPrestreamIntent()) n += 1;
3143
3143
  return n;
3144
3144
  }
3145
- /** Sessions asking only for the picture. Drives the prestream pump, nothing
3145
+ /** Sessions asking only for the picture. Drives the sentry pump, nothing
3146
3146
  * else — it must never reach a dial decision. */
3147
3147
  getPrestreamSessionCount() {
3148
3148
  let n = 0;
@@ -3903,12 +3903,12 @@ var RtspSession = class {
3903
3903
  /**
3904
3904
  * Whether this dial asked for the STREAM without asking for the CAMERA.
3905
3905
  *
3906
- * The one question the demand split turns on: a prestream session is FED but
3906
+ * The one question the demand split turns on: a sentry session is FED but
3907
3907
  * is not INTENT, so it never dials a sleeping camera. See
3908
- * `PRESTREAM_PATH_SUFFIX`.
3908
+ * `SENTRY_PATH_SUFFIX`.
3909
3909
  */
3910
3910
  isPrestreamIntent() {
3911
- return this.declaration.intent === "prestream";
3911
+ return this.declaration.intent === "sentry";
3912
3912
  }
3913
3913
  /**
3914
3914
  * Ms of retained history this session ASKED for on its dial. `0` = none.
@@ -4207,7 +4207,7 @@ var RtspListenServer = class RtspListenServer {
4207
4207
  brokerEnabled = /* @__PURE__ */ new Map();
4208
4208
  /** brokerId → warm-up closure registered alongside the restreamer */
4209
4209
  brokerWarmUps = /* @__PURE__ */ new Map();
4210
- /** brokerId → prestream picture-window opener */
4210
+ /** brokerId → sentry picture-window opener */
4211
4211
  brokerPrestreamOpeners = /* @__PURE__ */ new Map();
4212
4212
  /** Generate a random token for a stream path */
4213
4213
  static generateToken() {
@@ -4219,7 +4219,7 @@ var RtspListenServer = class RtspListenServer {
4219
4219
  * If not, generate a new one.
4220
4220
  * Returns the token used.
4221
4221
  */
4222
- registerRestreamer(brokerId, restreamer, warmUp, existingToken, prestreamOpener) {
4222
+ registerRestreamer(brokerId, restreamer, warmUp, existingToken, sentryOpener) {
4223
4223
  const oldToken = this.brokerTokens.get(brokerId);
4224
4224
  if (oldToken) {
4225
4225
  this.restreamers.delete(oldToken);
@@ -4230,7 +4230,7 @@ var RtspListenServer = class RtspListenServer {
4230
4230
  this.brokerTokens.set(brokerId, token);
4231
4231
  this.tokenBrokers.set(token, brokerId);
4232
4232
  if (warmUp) this.brokerWarmUps.set(brokerId, warmUp);
4233
- if (prestreamOpener) this.brokerPrestreamOpeners.set(brokerId, prestreamOpener);
4233
+ if (sentryOpener) this.brokerPrestreamOpeners.set(brokerId, sentryOpener);
4234
4234
  return token;
4235
4235
  }
4236
4236
  unregisterRestreamer(brokerId) {
@@ -4342,9 +4342,9 @@ var RtspListenServer = class RtspListenServer {
4342
4342
  socket.destroy();
4343
4343
  return;
4344
4344
  }
4345
- const prestreamDial = declaration.intent === "prestream";
4346
- const warmUp = brokerId && !prestreamDial ? this.brokerWarmUps.get(brokerId) : void 0;
4347
- const opener = brokerId && prestreamDial ? this.brokerPrestreamOpeners.get(brokerId) : void 0;
4345
+ const sentryDial = declaration.intent === "sentry";
4346
+ const warmUp = brokerId && !sentryDial ? this.brokerWarmUps.get(brokerId) : void 0;
4347
+ const opener = brokerId && sentryDial ? this.brokerPrestreamOpeners.get(brokerId) : void 0;
4348
4348
  const releaseWarmUp = warmUp ? warmUp() : opener?.() ?? null;
4349
4349
  let released = false;
4350
4350
  const releaseOnce = () => {
@@ -7648,16 +7648,16 @@ function runGif(input, args) {
7648
7648
  });
7649
7649
  }
7650
7650
  //#endregion
7651
- //#region src/stream-broker/stream-broker/prestream-encode.ts
7651
+ //#region src/stream-broker/stream-broker/sentry-encode.ts
7652
7652
  /**
7653
- * ONE short-lived ffmpeg turns the prestream's picture into ONE Annex-B IDR.
7653
+ * ONE short-lived ffmpeg turns the sentry's picture into ONE Annex-B IDR.
7654
7654
  *
7655
7655
  * ── Why one encode and not a continuous child ─────────────────────────────
7656
7656
  * The obvious shape is `-loop 1 -framerate 1` and let ffmpeg emit the picture
7657
7657
  * for as long as the camera is waking. That is a resident child per sleeping
7658
7658
  * camera, for the whole wake, to redraw a picture that changes at most hourly.
7659
7659
  * So the child encodes exactly ONE frame (`-frames:v 1`) and exits, the caller
7660
- * caches the bytes, and {@link PrestreamPump} re-emits them. A new encode
7660
+ * caches the bytes, and {@link SentryPump} re-emits them. A new encode
7661
7661
  * happens only when the picture changes.
7662
7662
  *
7663
7663
  * ── Why every frame carries its own parameter sets ────────────────────────
@@ -7682,10 +7682,10 @@ function runGif(input, args) {
7682
7682
  */
7683
7683
  /**
7684
7684
  * Bound on the encode. A single 4 MP still on `ultrafast` is milliseconds; a
7685
- * child that has not answered in this long is hung, and the prestream would
7685
+ * child that has not answered in this long is hung, and the sentry would
7686
7686
  * otherwise hold a promise open for the rest of the process's life.
7687
7687
  */
7688
- var PRESTREAM_ENCODE_TIMEOUT_MS = 1e4;
7688
+ var SENTRY_ENCODE_TIMEOUT_MS = 1e4;
7689
7689
  /** Grace before escalating SIGTERM → SIGKILL on a child that will not go. */
7690
7690
  var KILL_GRACE_MS = 500;
7691
7691
  /** x264/x265 params shared by both codecs: one-frame GOP, headers on it. */
@@ -7740,7 +7740,7 @@ function buildPrestreamEncodeArgs(plan) {
7740
7740
  }
7741
7741
  /**
7742
7742
  * Run the encode. Resolves with the Annex-B bytes, rejects with a named reason
7743
- * — the caller turns a rejection into a refusal log and no prestream, which is
7743
+ * — the caller turns a rejection into a refusal log and no sentry, which is
7744
7744
  * the same outcome as a black screen and never worse than one.
7745
7745
  */
7746
7746
  function encodePrestreamIdr(options) {
@@ -7752,7 +7752,7 @@ function encodePrestreamIdr(options) {
7752
7752
  try {
7753
7753
  child = spawnFn(options.ffmpegPath, args);
7754
7754
  } catch (err) {
7755
- reject(/* @__PURE__ */ new Error(`prestream encode could not spawn ffmpeg: ${require_dist.errMsg(err)}`));
7755
+ reject(/* @__PURE__ */ new Error(`sentry encode could not spawn ffmpeg: ${require_dist.errMsg(err)}`));
7756
7756
  return;
7757
7757
  }
7758
7758
  const chunks = [];
@@ -7767,8 +7767,8 @@ function encodePrestreamIdr(options) {
7767
7767
  };
7768
7768
  const timer = setTimeout(() => {
7769
7769
  killChild(child);
7770
- finish({ error: /* @__PURE__ */ new Error(`prestream encode timed out after ${String(PRESTREAM_ENCODE_TIMEOUT_MS)} ms`) });
7771
- }, PRESTREAM_ENCODE_TIMEOUT_MS);
7770
+ finish({ error: /* @__PURE__ */ new Error(`sentry encode timed out after ${String(SENTRY_ENCODE_TIMEOUT_MS)} ms`) });
7771
+ }, SENTRY_ENCODE_TIMEOUT_MS);
7772
7772
  timer.unref?.();
7773
7773
  child.stdout?.on("data", (chunk) => chunks.push(chunk));
7774
7774
  child.stderr?.on("data", (chunk) => {
@@ -7776,19 +7776,19 @@ function encodePrestreamIdr(options) {
7776
7776
  });
7777
7777
  child.stdin?.on("error", () => {});
7778
7778
  child.on("error", (err) => {
7779
- finish({ error: /* @__PURE__ */ new Error(`prestream encode failed: ${err.message}`) });
7779
+ finish({ error: /* @__PURE__ */ new Error(`sentry encode failed: ${err.message}`) });
7780
7780
  });
7781
7781
  child.on("exit", (code, signal) => {
7782
7782
  if (code !== 0) {
7783
- finish({ error: /* @__PURE__ */ new Error(`prestream encode exited ${String(code ?? signal)}: ${stderrTail.trim() || "no stderr"}`) });
7783
+ finish({ error: /* @__PURE__ */ new Error(`sentry encode exited ${String(code ?? signal)}: ${stderrTail.trim() || "no stderr"}`) });
7784
7784
  return;
7785
7785
  }
7786
7786
  const bytes = Buffer.concat(chunks);
7787
7787
  if (bytes.length === 0) {
7788
- finish({ error: /* @__PURE__ */ new Error("prestream encode produced no bytes") });
7788
+ finish({ error: /* @__PURE__ */ new Error("sentry encode produced no bytes") });
7789
7789
  return;
7790
7790
  }
7791
- options.logger?.debug("prestream: picture encoded", {
7791
+ options.logger?.debug("sentry: picture encoded", {
7792
7792
  ...tags,
7793
7793
  meta: {
7794
7794
  codec: options.plan.codec,
@@ -7810,9 +7810,9 @@ function killChild(child) {
7810
7810
  }, KILL_GRACE_MS).unref?.();
7811
7811
  }
7812
7812
  //#endregion
7813
- //#region src/stream-broker/stream-broker/prestream-picture.ts
7813
+ //#region src/stream-broker/stream-broker/sentry-picture.ts
7814
7814
  /**
7815
- * The PICTURE the prestream shows: the camera's own last frame under a "Waking"
7815
+ * The PICTURE the sentry shows: the camera's own last frame under a "Waking"
7816
7816
  * treatment, or — when there is none — a generated card carrying its name.
7817
7817
  *
7818
7818
  * ── Why a fallback exists at all ──────────────────────────────────────────
@@ -7843,16 +7843,18 @@ function killChild(child) {
7843
7843
  */
7844
7844
  async function composePrestreamPicture(input) {
7845
7845
  const tags = input.deviceId === void 0 ? {} : { tags: { deviceId: input.deviceId } };
7846
+ const reason = "sleeping";
7846
7847
  if (input.cachedJpeg !== null && input.cachedJpeg.length > 0) try {
7847
7848
  return {
7848
7849
  jpeg: await (0, _camstack_system_addon_utils.renderCourtesyOverlayJpeg)(input.cachedJpeg, {
7849
7850
  deviceName: input.deviceName,
7850
- reason: "waking"
7851
+ reason
7851
7852
  }),
7852
- source: "cached-snapshot"
7853
+ source: "cached-snapshot",
7854
+ reason
7853
7855
  };
7854
7856
  } catch (err) {
7855
- input.logger?.warn("prestream: cached frame could not be treated — using the card", {
7857
+ input.logger?.warn("sentry: cached frame could not be treated — using the card", {
7856
7858
  ...tags,
7857
7859
  meta: { error: require_dist.errMsg(err) }
7858
7860
  });
@@ -7860,11 +7862,12 @@ async function composePrestreamPicture(input) {
7860
7862
  return {
7861
7863
  jpeg: await (0, _camstack_system_addon_utils.renderCourtesyJpeg)({
7862
7864
  deviceName: input.deviceName,
7863
- reason: "waking",
7865
+ reason,
7864
7866
  width: input.width,
7865
7867
  height: input.height
7866
7868
  }),
7867
- source: "generated-card"
7869
+ source: "generated-card",
7870
+ reason
7868
7871
  };
7869
7872
  }
7870
7873
  function planPrestream(input) {
@@ -7879,7 +7882,7 @@ function planPrestream(input) {
7879
7882
  } };
7880
7883
  }
7881
7884
  /**
7882
- * `null` for a codec nobody has read. NOT a default of h264: a prestream in the
7885
+ * `null` for a codec nobody has read. NOT a default of h264: a sentry in the
7883
7886
  * wrong codec is a stream the consumer cannot decode at all, which is worse
7884
7887
  * than the black screen it replaces.
7885
7888
  */
@@ -11981,11 +11984,11 @@ var OPUS_SILENCE_FRAME_SAMPLES = 960;
11981
11984
  var OPUS_SILENCE_PRIME_FRAMES = 6;
11982
11985
  /**
11983
11986
  * Produce ONE canonical 20 ms Opus silence packet by encoding PCM zeros through
11984
- * the audio-codec cap, for the WebRTC session's prestream A/V-sync padding
11987
+ * the audio-codec cap, for the WebRTC session's sentry A/V-sync padding
11985
11988
  * (Opus has no fixed "silence byte" like PCMU's 0xFF — silence must be encoded).
11986
11989
  * A short-lived encode session is created, primed with a few zero frames, and
11987
11990
  * flushed; the LAST steady-state frame is returned. Returns `null` when the cap
11988
- * is unavailable or yields nothing so the caller can skip prestream padding.
11991
+ * is unavailable or yields nothing so the caller can skip sentry padding.
11989
11992
  */
11990
11993
  async function encodeOpusSilenceFrame(api, cfg) {
11991
11994
  let sessionId = null;
@@ -12068,9 +12071,9 @@ function getPlaceholderFrame(kind, codec) {
12068
12071
  return buf;
12069
12072
  }
12070
12073
  //#endregion
12071
- //#region src/stream-broker/stream-broker/prestream-pump.ts
12074
+ //#region src/stream-broker/stream-broker/sentry-pump.ts
12072
12075
  /**
12073
- * The prestream pump: ONE encode, then a 1 fps re-emit until real media lands.
12076
+ * The sentry pump: ONE encode, then a 1 fps re-emit until real media lands.
12074
12077
  *
12075
12078
  * ── What it is for ────────────────────────────────────────────────────────
12076
12079
  * A lazy source is BUILT on demand, and on this hub that build costs 2.2 to
@@ -12092,12 +12095,12 @@ function getPlaceholderFrame(kind, codec) {
12092
12095
  * 3. **It never dials.** The pump has no source, no socket and no demand. It
12093
12096
  * is started alongside the publisher request, never instead of it.
12094
12097
  *
12095
- * Emission is the caller's: {@link PrestreamPumpOptions.emit} is where the
12098
+ * Emission is the caller's: {@link SentryPumpOptions.emit} is where the
12096
12099
  * `isPlaceholder: true` packet is built, because that flag belongs to the
12097
12100
  * broker's packet contract and the containment that reads it lives there.
12098
12101
  */
12099
- var DEFAULT_PRESTREAM_INTERVAL_MS = 1e3;
12100
- var PrestreamPump = class {
12102
+ var DEFAULT_SENTRY_INTERVAL_MS = 1e3;
12103
+ var SentryPump = class {
12101
12104
  options;
12102
12105
  intervalMs;
12103
12106
  tags;
@@ -12109,7 +12112,7 @@ var PrestreamPump = class {
12109
12112
  emitted = 0;
12110
12113
  constructor(options) {
12111
12114
  this.options = options;
12112
- this.intervalMs = options.intervalMs ?? DEFAULT_PRESTREAM_INTERVAL_MS;
12115
+ this.intervalMs = options.intervalMs ?? DEFAULT_SENTRY_INTERVAL_MS;
12113
12116
  this.tags = options.deviceId === void 0 ? {} : { tags: { deviceId: options.deviceId } };
12114
12117
  }
12115
12118
  /** Whether the window is currently being filled (or about to be). */
@@ -12128,16 +12131,16 @@ var PrestreamPump = class {
12128
12131
  this.emitted = 0;
12129
12132
  this.options.prepare({ sourceUrl }).then((frame) => {
12130
12133
  if (!this.active) {
12131
- this.options.logger?.debug("prestream: preparation landed after the window closed", { ...this.tags });
12134
+ this.options.logger?.debug("sentry: preparation landed after the window closed", { ...this.tags });
12132
12135
  return;
12133
12136
  }
12134
12137
  if (frame === null) {
12135
- this.options.logger?.info("prestream: refused — the window goes unfilled", { ...this.tags });
12138
+ this.options.logger?.info("sentry: refused — the window goes unfilled", { ...this.tags });
12136
12139
  this.active = false;
12137
12140
  return;
12138
12141
  }
12139
12142
  this.frame = frame;
12140
- this.options.logger?.info("prestream: filling the wake window", {
12143
+ this.options.logger?.info("sentry: filling the wake window", {
12141
12144
  ...this.tags,
12142
12145
  meta: {
12143
12146
  codec: frame.codec,
@@ -12149,7 +12152,7 @@ var PrestreamPump = class {
12149
12152
  this.tick();
12150
12153
  this.timer = setInterval(() => this.tick(), this.intervalMs);
12151
12154
  }).catch((err) => {
12152
- this.options.logger?.warn("prestream: preparation failed — the window goes unfilled", {
12155
+ this.options.logger?.warn("sentry: preparation failed — the window goes unfilled", {
12153
12156
  ...this.tags,
12154
12157
  meta: { error: require_dist.errMsg(err) }
12155
12158
  });
@@ -12158,7 +12161,7 @@ var PrestreamPump = class {
12158
12161
  }
12159
12162
  /**
12160
12163
  * Close the window. Called on the first NON-placeholder packet — the one edge
12161
- * the prestream is defined by — and on the broker's own teardown paths so a
12164
+ * the sentry is defined by — and on the broker's own teardown paths so a
12162
12165
  * stopped broker leaves no timer behind.
12163
12166
  */
12164
12167
  stop(reason) {
@@ -12168,7 +12171,7 @@ var PrestreamPump = class {
12168
12171
  clearInterval(this.timer);
12169
12172
  this.timer = void 0;
12170
12173
  }
12171
- this.options.logger?.info("prestream: window closed", {
12174
+ this.options.logger?.info("sentry: window closed", {
12172
12175
  ...this.tags,
12173
12176
  meta: {
12174
12177
  reason,
@@ -12479,12 +12482,12 @@ var StreamBroker = class StreamBroker {
12479
12482
  reconnectTimer;
12480
12483
  placeholderTimer;
12481
12484
  /**
12482
- * The prestream pump, armed by the manager via `setPrestreamProvider`.
12483
- * `undefined` on a broker whose manager supplied none — the pre-prestream
12485
+ * The sentry pump, armed by the manager via `setPrestreamProvider`.
12486
+ * `undefined` on a broker whose manager supplied none — the pre-sentry
12484
12487
  * behaviour, unchanged.
12485
12488
  */
12486
- prestreamPump;
12487
- /** The manager's hook for "real media started" — see `PrestreamProvider`. */
12489
+ sentryPump;
12490
+ /** The manager's hook for "real media started" — see `SentryProvider`. */
12488
12491
  onRealMediaStarted;
12489
12492
  /**
12490
12493
  * Latched once real media has been seen on this session.
@@ -12494,9 +12497,9 @@ var StreamBroker = class StreamBroker {
12494
12497
  * window that real bytes have already closed, and the consumer would get a
12495
12498
  * still picture painted over live video every second. Reset exactly where
12496
12499
  * `firstKeyframeReceived` is — broker stop and suspend — so a battery camera
12497
- * that goes back to sleep gets its prestream again on the next wake.
12500
+ * that goes back to sleep gets its sentry again on the next wake.
12498
12501
  */
12499
- prestreamWindowClosed = false;
12502
+ sentryWindowClosed = false;
12500
12503
  reconnectDelayMs = INITIAL_RECONNECT_DELAY_MS;
12501
12504
  /**
12502
12505
  * Dial rate-limiter (2026-07-23 storm fix): the earliest wall-clock at
@@ -12772,7 +12775,7 @@ var StreamBroker = class StreamBroker {
12772
12775
  * that socket down. In that window `resolveCurrentSource()` truthfully
12773
12776
  * answers with a socket nobody can dial.
12774
12777
  *
12775
- * That cost device 640 its prestream on 2026-09-16: the window re-opened
12778
+ * That cost device 640 its sentry on 2026-09-16: the window re-opened
12776
12779
  * (which `suspend()` does deliberately, for a consumer that never left) with
12777
12780
  * the real url, `planPrestream` refused it `not-lazy`, and the refusal is
12778
12781
  * terminal — the operator's client sat dark for ten seconds and gave up six
@@ -12781,8 +12784,8 @@ var StreamBroker = class StreamBroker {
12781
12784
  * NOT cleared when `start()` is later called with a materialized url: that
12782
12785
  * happens on every wake, and clearing it there is the bug again. A broker
12783
12786
  * genuinely reconfigured onto a permanent mains source keeps a stale value,
12784
- * which costs nothing — `prestreamEligible` (battery + declared signals) is
12785
- * the authority on whether a camera gets a prestream at all, and it is asked
12787
+ * which costs nothing — `sentryEligible` (battery + declared signals) is
12788
+ * the authority on whether a camera gets a sentry at all, and it is asked
12786
12789
  * first, in the manager.
12787
12790
  */
12788
12791
  lazySourceUrl;
@@ -13045,7 +13048,7 @@ var StreamBroker = class StreamBroker {
13045
13048
  this.requestSourceRefresh = notify;
13046
13049
  }
13047
13050
  /**
13048
- * Arm the PRESTREAM — the fill for the window between "someone asked for this
13051
+ * Arm the SENTRY — the fill for the window between "someone asked for this
13049
13052
  * camera" and "the camera is awake".
13050
13053
  *
13051
13054
  * Manager-owned, because everything the fill needs is the manager's: the
@@ -13053,13 +13056,13 @@ var StreamBroker = class StreamBroker {
13053
13056
  * snapshot, its name, and the ffmpeg binary. The broker contributes the one
13054
13057
  * thing it owns — WHEN the window is open — and nothing else.
13055
13058
  *
13056
- * A broker with no provider behaves exactly as it did before the prestream
13059
+ * A broker with no provider behaves exactly as it did before the sentry
13057
13060
  * existed: the lazy branch asks the publisher to materialize and the consumer
13058
13061
  * sees black, which is the outcome every refusal falls back to.
13059
13062
  */
13060
13063
  setPrestreamProvider(provider) {
13061
13064
  this.onRealMediaStarted = provider.onRealMediaStarted;
13062
- this.prestreamPump = new PrestreamPump({
13065
+ this.sentryPump = new SentryPump({
13063
13066
  prepare: provider.prepare,
13064
13067
  emit: (frame) => {
13065
13068
  const now = Date.now();
@@ -13179,7 +13182,7 @@ var StreamBroker = class StreamBroker {
13179
13182
  *
13180
13183
  * Here and not only in `start()` because a broker that has never dialled is a
13181
13184
  * real and common state: a battery camera nobody has asked for yet, with a
13182
- * prestream consumer attached, has a recipe and no socket. Learning it from
13185
+ * sentry consumer attached, has a recipe and no socket. Learning it from
13183
13186
  * the dial alone would leave exactly that broker unable to describe itself.
13184
13187
  */
13185
13188
  noteLazyUrl(url) {
@@ -13256,8 +13259,8 @@ var StreamBroker = class StreamBroker {
13256
13259
  clearInterval(this.placeholderTimer);
13257
13260
  this.placeholderTimer = void 0;
13258
13261
  }
13259
- this.prestreamPump?.stop("broker stopped");
13260
- this.prestreamWindowClosed = false;
13262
+ this.sentryPump?.stop("broker stopped");
13263
+ this.sentryWindowClosed = false;
13261
13264
  if (this.reconnectTimer) {
13262
13265
  clearTimeout(this.reconnectTimer);
13263
13266
  this.reconnectTimer = void 0;
@@ -13427,7 +13430,7 @@ var StreamBroker = class StreamBroker {
13427
13430
  *
13428
13431
  * - the caller has already checked the signal is ENABLED for this camera
13429
13432
  * (the broker manager owns that setting), and
13430
- * - somebody is actually waiting on the prestream. Waking a camera nobody is
13433
+ * - somebody is actually waiting on the sentry. Waking a camera nobody is
13431
13434
  * watching is the one thing a battery camera must never do, and a signal
13432
13435
  * arriving with no consumer is exactly that.
13433
13436
  *
@@ -13470,7 +13473,7 @@ var StreamBroker = class StreamBroker {
13470
13473
  if (delay <= 0) return;
13471
13474
  this.wakeHoldTimer = setTimeout(() => {
13472
13475
  this.wakeHoldTimer = void 0;
13473
- this.logger?.info("wake hold lapsed — back to the prestream picture", {
13476
+ this.logger?.info("wake hold lapsed — back to the sentry picture", {
13474
13477
  tags: { deviceId: this.numericDeviceId },
13475
13478
  meta: {
13476
13479
  brokerId: this.deviceId,
@@ -13483,20 +13486,20 @@ var StreamBroker = class StreamBroker {
13483
13486
  this.wakeHoldTimer.unref?.();
13484
13487
  }
13485
13488
  /**
13486
- * Anything that must be FED, prestream sessions included.
13489
+ * Anything that must be FED, sentry sessions included.
13487
13490
  *
13488
- * The only consumer of this is the prestream pump: it says "somebody is
13491
+ * The only consumer of this is the sentry pump: it says "somebody is
13489
13492
  * watching, keep the picture going", and says nothing about whether the
13490
13493
  * camera may be dialled. {@link hasLiveIntent} answers that, and it is the
13491
13494
  * one every dial path asks.
13492
13495
  */
13493
13496
  hasAnyConsumer() {
13494
13497
  if (this.hasLiveIntent()) return true;
13495
- if (this.prestreamHolds > 0) return true;
13498
+ if (this.sentryHolds > 0) return true;
13496
13499
  return this.rtspRestreamer.getPrestreamSessionCount() > 0;
13497
13500
  }
13498
13501
  /**
13499
- * Somebody is DESCRIBING a prestream and has no session yet.
13502
+ * Somebody is DESCRIBING a sentry and has no session yet.
13500
13503
  *
13501
13504
  * The RTSP dispatch reads the SDP before `addSession` runs, so a window that
13502
13505
  * waits for the session is too late: the consumer is handed an empty SDP and
@@ -13504,28 +13507,28 @@ var StreamBroker = class StreamBroker {
13504
13507
  * on the attach and closed 42 ms later having emitted zero frames, because
13505
13508
  * ffmpeg had already given up.
13506
13509
  *
13507
- * This is the prestream counterpart of `BrokerWarmUp` and its exact opposite
13510
+ * This is the sentry counterpart of `BrokerWarmUp` and its exact opposite
13508
13511
  * in effect: the warm-up subscribes demand, which DIALS; this opens the
13509
13512
  * picture, which never does. A battery camera is not touched.
13510
13513
  */
13511
13514
  openPrestreamWindow() {
13512
- this.prestreamHolds += 1;
13515
+ this.sentryHolds += 1;
13513
13516
  this.checkDemand();
13514
13517
  let released = false;
13515
13518
  return () => {
13516
13519
  if (released) return;
13517
13520
  released = true;
13518
- this.prestreamHolds = Math.max(0, this.prestreamHolds - 1);
13521
+ this.sentryHolds = Math.max(0, this.sentryHolds - 1);
13519
13522
  this.checkDemand();
13520
13523
  };
13521
13524
  }
13522
- /** DESCRIBE-window prestream holds: sessions that do not exist yet. */
13523
- prestreamHolds = 0;
13525
+ /** DESCRIBE-window sentry holds: sessions that do not exist yet. */
13526
+ sentryHolds = 0;
13524
13527
  /**
13525
13528
  * Consumers that may DIAL. Every term of the former `hasDemand`, with the
13526
- * RTSP session count filtered to exclude prestream dials, plus the wake hold.
13529
+ * RTSP session count filtered to exclude sentry dials, plus the wake hold.
13527
13530
  *
13528
- * For a broker with no prestream session attached this is term-for-term what
13531
+ * For a broker with no sentry session attached this is term-for-term what
13529
13532
  * `hasDemand` was, which is why every existing camera, consumer and test
13530
13533
  * behaves identically.
13531
13534
  */
@@ -13570,7 +13573,7 @@ var StreamBroker = class StreamBroker {
13570
13573
  });
13571
13574
  }
13572
13575
  /**
13573
- * Encode ONE canonical 20 ms Opus silence packet for a session's prestream
13576
+ * Encode ONE canonical 20 ms Opus silence packet for a session's sentry
13574
13577
  * A/V-sync padding (Opus has no fixed silence byte). Returns `null` when the
13575
13578
  * audio-codec cap is unavailable. See {@link encodeOpusSilenceFrame}.
13576
13579
  */
@@ -13680,16 +13683,16 @@ var StreamBroker = class StreamBroker {
13680
13683
  if (!this.hasLiveIntent() && !this.manualStop && !this.stopping) this.suspend();
13681
13684
  }, SUSPEND_GRACE_MS);
13682
13685
  }
13683
- this.prestreamWanted = this.hasAnyConsumer() && !this.hasLiveIntent();
13686
+ this.sentryWanted = this.hasAnyConsumer() && !this.hasLiveIntent();
13684
13687
  this.reconcilePrestreamWindow();
13685
13688
  }
13686
13689
  /**
13687
- * Open or close the prestream window to match {@link prestreamWanted}.
13690
+ * Open or close the sentry window to match {@link sentryWanted}.
13688
13691
  *
13689
- * This is the half that was missing. `prestreamWanted` has been computed
13692
+ * This is the half that was missing. `sentryWanted` has been computed
13690
13693
  * correctly since the feature shipped, but the only thing that ever STARTED
13691
13694
  * the pump was the lazy branch of `start()` — a DIAL, which needs live
13692
- * intent, which a prestream session does not have by construction. So the
13695
+ * intent, which a sentry session does not have by construction. So the
13693
13696
  * window opened only when something else had already woken the camera, and
13694
13697
  * `suspend()` closed it for good.
13695
13698
  *
@@ -13699,22 +13702,22 @@ var StreamBroker = class StreamBroker {
13699
13702
  * demand check costs one encode per window and no more.
13700
13703
  */
13701
13704
  reconcilePrestreamWindow() {
13702
- if (!this.prestreamPump) return;
13703
- if (this.prestreamWanted && !this.prestreamWindowClosed) {
13705
+ if (!this.sentryPump) return;
13706
+ if (this.sentryWanted && !this.sentryWindowClosed) {
13704
13707
  const url = this.lazySourceUrl ?? this.resolveCurrentSource()?.url ?? this.source?.url;
13705
- if (url !== void 0) this.prestreamPump.start(url);
13708
+ if (url !== void 0) this.sentryPump.start(url);
13706
13709
  return;
13707
13710
  }
13708
- if (!this.prestreamWanted) this.prestreamPump.stop("no prestream consumer");
13711
+ if (!this.sentryWanted) this.sentryPump.stop("no sentry consumer");
13709
13712
  }
13710
13713
  /**
13711
- * Whether a prestream picture should be flowing right now: somebody is
13714
+ * Whether a sentry picture should be flowing right now: somebody is
13712
13715
  * watching and the camera is not up. Read by the pump.
13713
13716
  */
13714
- prestreamWanted = false;
13717
+ sentryWanted = false;
13715
13718
  /** Whether the picture should be flowing — the pump's one question. */
13716
13719
  wantsPrestream() {
13717
- return this.prestreamWanted;
13720
+ return this.sentryWanted;
13718
13721
  }
13719
13722
  /** Suspend the stream: kill ffmpeg/native client, clear buffers, go idle. Source is preserved for resume. */
13720
13723
  suspend() {
@@ -13739,8 +13742,8 @@ var StreamBroker = class StreamBroker {
13739
13742
  clearInterval(this.placeholderTimer);
13740
13743
  this.placeholderTimer = void 0;
13741
13744
  }
13742
- this.prestreamPump?.stop("broker suspended");
13743
- this.prestreamWindowClosed = false;
13745
+ this.sentryPump?.stop("broker suspended");
13746
+ this.sentryWindowClosed = false;
13744
13747
  this.reconcilePrestreamWindow();
13745
13748
  this.preBuffer.clear();
13746
13749
  this.decoderSeedBuffer.clear();
@@ -13825,13 +13828,13 @@ var StreamBroker = class StreamBroker {
13825
13828
  }
13826
13829
  pushEncodedPacket(packet) {
13827
13830
  if (this.stopping) return;
13828
- if (packet.isPlaceholder !== true && !this.prestreamWindowClosed) {
13829
- this.prestreamWindowClosed = true;
13830
- this.prestreamPump?.stop("first real packet");
13831
+ if (packet.isPlaceholder !== true && !this.sentryWindowClosed) {
13832
+ this.sentryWindowClosed = true;
13833
+ this.sentryPump?.stop("first real packet");
13831
13834
  try {
13832
13835
  this.onRealMediaStarted?.();
13833
13836
  } catch (err) {
13834
- this.logger?.debug("prestream: real-media hook threw", {
13837
+ this.logger?.debug("sentry: real-media hook threw", {
13835
13838
  tags: { deviceId: this.numericDeviceId ?? 0 },
13836
13839
  meta: { error: String(err) }
13837
13840
  });
@@ -15580,7 +15583,7 @@ var StreamBroker = class StreamBroker {
15580
15583
  });
15581
15584
  this._status = "error";
15582
15585
  this.notifySourceRefresh();
15583
- if (!this.prestreamWindowClosed) this.prestreamPump?.start(source.url);
15586
+ if (!this.sentryWindowClosed) this.sentryPump?.start(source.url);
15584
15587
  this.scheduleReconnect();
15585
15588
  return;
15586
15589
  }
@@ -16312,16 +16315,16 @@ var DeviceOverrideSchema = require_dist.object({
16312
16315
  sourceParser: require_dist.record(require_dist.string(), SourceParserSettingSchema).optional(),
16313
16316
  sourceParserArgs: require_dist.record(require_dist.string(), SourceParserArgsEntrySchema).optional(),
16314
16317
  /**
16315
- * The on-demand PRESTREAM, per camera.
16318
+ * The on-demand SENTRY, per camera.
16316
16319
  *
16317
16320
  * Absent means the operator has never touched it, which is NOT the same as
16318
16321
  * off: `enabledSignals` absent means "every signal this camera recommends",
16319
- * so a Reolink works the moment a prestream URL is dialled without an
16322
+ * so a Reolink works the moment a sentry URL is dialled without an
16320
16323
  * operator hunting for a checkbox. An empty ARRAY is a deliberate "none" and
16321
16324
  * is honoured — the two are different answers and the shape keeps them
16322
16325
  * apart.
16323
16326
  */
16324
- prestream: require_dist.object({
16327
+ sentry: require_dist.object({
16325
16328
  /** Signal codes allowed to wake this camera. Absent ⇒ the recommended set. */
16326
16329
  enabledSignals: require_dist.array(require_dist.string()).optional(),
16327
16330
  /** How long the camera stays up after the LAST signal. Absent ⇒ default. */
@@ -16515,13 +16518,13 @@ var StreamBrokerManager = class StreamBrokerManager {
16515
16518
  /** Per-device published cam-stream registry. */
16516
16519
  cameraStreams = /* @__PURE__ */ new Map();
16517
16520
  /**
16518
- * The encoded prestream frame per broker, with the digest of the picture it
16521
+ * The encoded sentry frame per broker, with the digest of the picture it
16519
16522
  * was made from. One entry is one still image — kilobytes — and it is
16520
16523
  * dropped with the broker in `releaseBroker`.
16521
16524
  */
16522
- /** Brokers with a background prestream re-encode in flight (single-flight). */
16523
- prestreamRefreshing = /* @__PURE__ */ new Set();
16524
- prestreamFrames = /* @__PURE__ */ new Map();
16525
+ /** Brokers with a background sentry re-encode in flight (single-flight). */
16526
+ sentryRefreshing = /* @__PURE__ */ new Set();
16527
+ sentryFrames = /* @__PURE__ */ new Map();
16525
16528
  /** Monotonic insertion counter per device — feeds `CameraStreamInternal.order`. */
16526
16529
  streamOrderSeq = /* @__PURE__ */ new Map();
16527
16530
  /** Persisted operator intent: which cam stream serves which profile. */
@@ -17413,7 +17416,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17413
17416
  * client-side and we get a typed payload.
17414
17417
  */
17415
17418
  /**
17416
- * Build the per-broker PRESTREAM provider — the fill for the window between
17419
+ * Build the per-broker SENTRY provider — the fill for the window between
17417
17420
  * "someone asked for this camera" and "the camera is awake".
17418
17421
  *
17419
17422
  * On this hub that window is 2.2-12.4 s for a lazy source, and it is not
@@ -17426,19 +17429,19 @@ var StreamBrokerManager = class StreamBrokerManager {
17426
17429
  * cached snapshot, its name, and the ffmpeg binary path.
17427
17430
  *
17428
17431
  * `null` is a REFUSAL, named in the log. Refusing is cheap — the consumer
17429
- * gets the black screen it got before the prestream existed — and the
17432
+ * gets the black screen it got before the sentry existed — and the
17430
17433
  * alternative for an unknown geometry is the decoder freeze the whole
17431
17434
  * synthetic-frame path is shaped around.
17432
17435
  */
17433
17436
  buildPrestreamProvider(deviceId, camStreamId, brokerId, logger) {
17434
17437
  return {
17435
17438
  prepare: async ({ sourceUrl }) => {
17436
- const gate = prestreamEligible({
17439
+ const gate = sentryEligible({
17437
17440
  batteryOperated: await this.isBatteryOperated(deviceId),
17438
17441
  declaresSignals: (await this.declaredSignalCodes(deviceId)).length > 0
17439
17442
  });
17440
17443
  if (!gate.eligible) {
17441
- logger.info("prestream: not offered for this camera", {
17444
+ logger.info("sentry: not offered for this camera", {
17442
17445
  tags: { deviceId },
17443
17446
  meta: {
17444
17447
  brokerId,
@@ -17456,7 +17459,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17456
17459
  codec
17457
17460
  });
17458
17461
  if ("refusal" in planned) {
17459
- logger.info("prestream: no fill for this camera", {
17462
+ logger.info("sentry: no fill for this camera", {
17460
17463
  tags: { deviceId },
17461
17464
  meta: {
17462
17465
  refusal: planned.refusal,
@@ -17476,7 +17479,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17476
17479
  * The window shows the camera's last snapshot, and nothing was
17477
17480
  * refreshing it: a battery camera refuses a capture while it believes
17478
17481
  * itself asleep, and that belief lags the wake by seconds — so the only
17479
- * attempts ever made were the prestream's own, while composing, which is
17482
+ * attempts ever made were the sentry's own, while composing, which is
17480
17483
  * BEFORE any media exists. Measured on device 640 (2026-09-16): four
17481
17484
  * wakes in forty minutes, the encoded picture `bytes=23912` every time,
17482
17485
  * and between first packet and suspend not one capture was even
@@ -17499,12 +17502,12 @@ var StreamBrokerManager = class StreamBrokerManager {
17499
17502
  const api = this.api;
17500
17503
  if (!api) return;
17501
17504
  api.snapshot.getSnapshot.query({ deviceId }).then(() => {
17502
- logger.debug("prestream: picture refreshed from the live window", {
17505
+ logger.debug("sentry: picture refreshed from the live window", {
17503
17506
  tags: { deviceId },
17504
17507
  meta: { brokerId }
17505
17508
  });
17506
17509
  }).catch((err) => {
17507
- logger.debug("prestream: live-window refresh failed — keeping the older picture", {
17510
+ logger.debug("sentry: live-window refresh failed — keeping the older picture", {
17508
17511
  tags: { deviceId },
17509
17512
  meta: {
17510
17513
  brokerId,
@@ -17525,7 +17528,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17525
17528
  */
17526
17529
  async preparePrestreamFrame(deviceId, brokerId, plan, logger) {
17527
17530
  if (!this.api) {
17528
- logger.info("prestream: no api access — the window goes unfilled", { tags: { deviceId } });
17531
+ logger.info("sentry: no api access — the window goes unfilled", { tags: { deviceId } });
17529
17532
  return null;
17530
17533
  }
17531
17534
  const api = this.api;
@@ -17534,7 +17537,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17534
17537
  const image = await api.snapshot.getSnapshot.query({ deviceId });
17535
17538
  if (image) cachedJpeg = Buffer.from(image.base64, "base64");
17536
17539
  } catch (err) {
17537
- logger.debug("prestream: cached snapshot read failed — falling back to the card", {
17540
+ logger.debug("sentry: cached snapshot read failed — falling back to the card", {
17538
17541
  tags: { deviceId },
17539
17542
  meta: { error: require_dist.errMsg(err) }
17540
17543
  });
@@ -17544,15 +17547,15 @@ var StreamBrokerManager = class StreamBrokerManager {
17544
17547
  const device = await api.deviceManager.getDevice.query({ deviceId });
17545
17548
  if (device?.name) deviceName = device.name;
17546
17549
  } catch (err) {
17547
- logger.debug("prestream: device name read failed — using the numeric id", {
17550
+ logger.debug("sentry: device name read failed — using the numeric id", {
17548
17551
  tags: { deviceId },
17549
17552
  meta: { error: require_dist.errMsg(err) }
17550
17553
  });
17551
17554
  }
17552
17555
  const key = `${(0, node_crypto.createHash)("sha1").update(cachedJpeg ?? Buffer.alloc(0)).update(deviceName).digest("hex")}:${String(plan.width)}x${String(plan.height)}:${plan.codec}`;
17553
- const cached = this.prestreamFrames.get(brokerId);
17556
+ const cached = this.sentryFrames.get(brokerId);
17554
17557
  if (cached && cached.key === key) {
17555
- logger.debug("prestream: re-using the encoded frame", {
17558
+ logger.debug("sentry: re-using the encoded frame", {
17556
17559
  tags: { deviceId },
17557
17560
  meta: { bytes: cached.frame.annexB.length }
17558
17561
  });
@@ -17561,7 +17564,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17561
17564
  const cachedGeometry = cached ? cached.key.slice(cached.key.indexOf(":")) : null;
17562
17565
  const wantedGeometry = key.slice(key.indexOf(":"));
17563
17566
  if (cached && cachedGeometry === wantedGeometry) {
17564
- logger.info("prestream: serving the previous picture while the new one encodes", {
17567
+ logger.info("sentry: serving the previous picture while the new one encodes", {
17565
17568
  tags: { deviceId },
17566
17569
  meta: { bytes: cached.frame.annexB.length }
17567
17570
  });
@@ -17586,10 +17589,11 @@ var StreamBrokerManager = class StreamBrokerManager {
17586
17589
  logger,
17587
17590
  deviceId
17588
17591
  });
17589
- logger.info("prestream: picture composed", {
17592
+ logger.info("sentry: picture composed", {
17590
17593
  tags: { deviceId },
17591
17594
  meta: {
17592
17595
  source: picture.source,
17596
+ reason: picture.reason,
17593
17597
  width: plan.width,
17594
17598
  height: plan.height,
17595
17599
  codec: plan.codec
@@ -17605,7 +17609,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17605
17609
  deviceId
17606
17610
  });
17607
17611
  } catch (err) {
17608
- logger.warn("prestream: encode failed — the window goes unfilled", {
17612
+ logger.warn("sentry: encode failed — the window goes unfilled", {
17609
17613
  tags: { deviceId },
17610
17614
  meta: { error: require_dist.errMsg(err) }
17611
17615
  });
@@ -17615,7 +17619,7 @@ var StreamBrokerManager = class StreamBrokerManager {
17615
17619
  annexB,
17616
17620
  codec: plan.codec
17617
17621
  };
17618
- this.prestreamFrames.set(brokerId, {
17622
+ this.sentryFrames.set(brokerId, {
17619
17623
  key,
17620
17624
  frame
17621
17625
  });
@@ -17629,10 +17633,10 @@ var StreamBrokerManager = class StreamBrokerManager {
17629
17633
  * operator is actually waiting for.
17630
17634
  */
17631
17635
  encodePrestreamInBackground(deviceId, brokerId, plan, key, cachedJpeg, deviceName, logger) {
17632
- if (this.prestreamRefreshing.has(brokerId)) return;
17633
- this.prestreamRefreshing.add(brokerId);
17636
+ if (this.sentryRefreshing.has(brokerId)) return;
17637
+ this.sentryRefreshing.add(brokerId);
17634
17638
  this.composeAndEncodePrestream(deviceId, brokerId, plan, key, cachedJpeg, deviceName, logger).catch(() => {}).finally(() => {
17635
- this.prestreamRefreshing.delete(brokerId);
17639
+ this.sentryRefreshing.delete(brokerId);
17636
17640
  });
17637
17641
  }
17638
17642
  subscribePlaceholderStateSources(bus) {
@@ -19639,7 +19643,7 @@ var StreamBrokerManager = class StreamBrokerManager {
19639
19643
  reason: "unknown-code"
19640
19644
  };
19641
19645
  }
19642
- const settings = this.deviceOverrides.get(input.deviceId)?.prestream;
19646
+ const settings = this.deviceOverrides.get(input.deviceId)?.sentry;
19643
19647
  if (!(settings?.enabledSignals ?? declared).includes(input.code)) return {
19644
19648
  accepted: false,
19645
19649
  reason: "not-enabled"
@@ -19821,11 +19825,11 @@ var StreamBrokerManager = class StreamBrokerManager {
19821
19825
  label: hwAccelOptionLabel(setting)
19822
19826
  }));
19823
19827
  const declaredSignals = await this.declaredSignalList(deviceId);
19824
- const prestreamGate = prestreamEligible({
19828
+ const sentryGate = sentryEligible({
19825
19829
  batteryOperated: await this.isBatteryOperated(deviceId),
19826
19830
  declaresSignals: declaredSignals.length > 0
19827
19831
  });
19828
- const prestreamOffered = prestreamGate.eligible;
19832
+ const sentryOffered = sentryGate.eligible;
19829
19833
  const streamTabs = streams.filter((s) => !s.camStreamId.startsWith("derived:")).map((stream) => {
19830
19834
  const camStreamId = stream.camStreamId;
19831
19835
  const brokerId = brokerIdFor(deviceId, camStreamId);
@@ -19925,18 +19929,18 @@ var StreamBrokerManager = class StreamBrokerManager {
19925
19929
  tooltip: "Copy muted URL to clipboard"
19926
19930
  }]
19927
19931
  },
19928
- ...prestreamOffered ? [{
19932
+ ...sentryOffered ? [{
19929
19933
  type: "text",
19930
19934
  key: `rtspPrestreamUrl:${camStreamId}`,
19931
- label: "RTSP URL (prestream)",
19935
+ label: "RTSP URL (sentry)",
19932
19936
  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.",
19933
19937
  readonlyField: true,
19934
19938
  span: 2,
19935
- value: rtspEntry?.url ? `${rtspEntry.url}/prestream` : "inactive",
19939
+ value: rtspEntry?.url ? `${rtspEntry.url}/sentry` : "inactive",
19936
19940
  actions: [{
19937
19941
  action: "copy-value",
19938
19942
  icon: "copy",
19939
- tooltip: "Copy prestream URL to clipboard"
19943
+ tooltip: "Copy sentry URL to clipboard"
19940
19944
  }]
19941
19945
  }] : [],
19942
19946
  {
@@ -20124,25 +20128,25 @@ var StreamBrokerManager = class StreamBrokerManager {
20124
20128
  ]
20125
20129
  }]
20126
20130
  };
20127
- const prestreamCfg = override?.prestream;
20128
- const prestreamSections = prestreamGate.eligible ? [{
20129
- id: "stream-broker-prestream",
20131
+ const sentryCfg = override?.sentry;
20132
+ const sentrySections = sentryGate.eligible ? [{
20133
+ id: "stream-broker-sentry",
20130
20134
  title: "Wake signals",
20131
20135
  tab: "stream-broker",
20132
20136
  location: "top-tab",
20133
20137
  order: 50,
20134
- 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.",
20138
+ 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.",
20135
20139
  fields: [...declaredSignals.map((signal) => ({
20136
20140
  type: "boolean",
20137
20141
  style: "switch",
20138
- key: `prestreamSignal:${signal.code}`,
20142
+ key: `sentrySignal:${signal.code}`,
20139
20143
  label: signal.label,
20140
20144
  description: signal.recommended ? "Recommended by this camera’s driver." : "Offered by this camera’s driver.",
20141
20145
  default: signal.recommended,
20142
- value: prestreamCfg?.enabledSignals === void 0 ? true : prestreamCfg.enabledSignals.includes(signal.code)
20146
+ value: sentryCfg?.enabledSignals === void 0 ? true : sentryCfg.enabledSignals.includes(signal.code)
20143
20147
  })), {
20144
20148
  type: "number",
20145
- key: "prestreamHoldMs",
20149
+ key: "sentryHoldMs",
20146
20150
  label: "Stay awake after the last signal",
20147
20151
  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.",
20148
20152
  min: 1e3,
@@ -20150,7 +20154,7 @@ var StreamBrokerManager = class StreamBrokerManager {
20150
20154
  step: 1e3,
20151
20155
  unit: "ms",
20152
20156
  default: DEFAULT_WAKE_HOLD_MS,
20153
- value: prestreamCfg?.holdMs ?? 15e3
20157
+ value: sentryCfg?.holdMs ?? 15e3
20154
20158
  }]
20155
20159
  }] : [];
20156
20160
  const diagnosticsSection = {
@@ -20179,7 +20183,7 @@ var StreamBrokerManager = class StreamBrokerManager {
20179
20183
  };
20180
20184
  return { sections: [
20181
20185
  streamBrokerSection,
20182
- ...prestreamSections,
20186
+ ...sentrySections,
20183
20187
  diagnosticsSection
20184
20188
  ] };
20185
20189
  }
@@ -20293,27 +20297,27 @@ var StreamBrokerManager = class StreamBrokerManager {
20293
20297
  nextOverride.sourceParserArgs = spa;
20294
20298
  continue;
20295
20299
  }
20296
- if (fieldKey.startsWith("prestreamSignal:")) {
20300
+ if (fieldKey.startsWith("sentrySignal:")) {
20297
20301
  overrideDirty = true;
20298
20302
  const next = nextEnabledSignals({
20299
20303
  declared: await this.declaredSignalCodes(deviceId),
20300
- stored: nextOverride.prestream?.enabledSignals,
20301
- code: fieldKey.slice(16),
20304
+ stored: nextOverride.sentry?.enabledSignals,
20305
+ code: fieldKey.slice(13),
20302
20306
  enabled: value === null || value === void 0 ? true : Boolean(value)
20303
20307
  });
20304
- nextOverride.prestream = {
20305
- ...nextOverride.prestream,
20308
+ nextOverride.sentry = {
20309
+ ...nextOverride.sentry,
20306
20310
  enabledSignals: [...next]
20307
20311
  };
20308
20312
  continue;
20309
20313
  }
20310
- if (fieldKey === "prestreamHoldMs") {
20314
+ if (fieldKey === "sentryHoldMs") {
20311
20315
  overrideDirty = true;
20312
20316
  const raw = typeof value === "number" ? value : Number(value);
20313
20317
  if (!Number.isFinite(raw)) continue;
20314
20318
  const clamped = Math.min(3e5, Math.max(1e3, Math.round(raw)));
20315
- nextOverride.prestream = {
20316
- ...nextOverride.prestream,
20319
+ nextOverride.sentry = {
20320
+ ...nextOverride.sentry,
20317
20321
  holdMs: clamped
20318
20322
  };
20319
20323
  continue;
@@ -21156,7 +21160,7 @@ var StreamBrokerManager = class StreamBrokerManager {
21156
21160
  this.streamOfflineReasonByBroker.delete(brokerId);
21157
21161
  await broker.stop();
21158
21162
  this.brokers.delete(brokerId);
21159
- this.prestreamFrames.delete(brokerId);
21163
+ this.sentryFrames.delete(brokerId);
21160
21164
  this.sweepFrameSubscriptions(brokerId);
21161
21165
  this.rtspProvider.persistTokens();
21162
21166
  this.syncProfileRestreamers(deviceId);
@@ -24724,7 +24728,7 @@ var AdaptiveSession = class AdaptiveSession {
24724
24728
  * silence packets (0xFF bytes, 160 samples each = 20 ms) so the audio
24725
24729
  * sender's first wall-clock instant aligns with the video sender's first
24726
24730
  * wall-clock instant, then the real packet continues seamlessly. See
24727
- * `prestreamAudioSilenceIfNeeded` + `computeAudioSilencePadPackets`.
24731
+ * `sentryAudioSilenceIfNeeded` + `computeAudioSilencePadPackets`.
24728
24732
  */
24729
24733
  firstAudioFramePadded = false;
24730
24734
  /** PCMU frame size in samples per packet — 160 = 20 ms at 8 kHz. */
@@ -25120,7 +25124,7 @@ var AdaptiveSession = class AdaptiveSession {
25120
25124
  return this.audioClock().codec === "opus";
25121
25125
  }
25122
25126
  /**
25123
- * Inject the canonical 20 ms Opus silence packet used for prestream A/V-sync
25127
+ * Inject the canonical 20 ms Opus silence packet used for sentry A/V-sync
25124
25128
  * padding. Broker-provided (encoded via the audio-codec cap) because Opus has
25125
25129
  * no fixed silence byte the way PCMU does (0xFF).
25126
25130
  */
@@ -25134,7 +25138,7 @@ var AdaptiveSession = class AdaptiveSession {
25134
25138
  const senderCodec = this.audioSender.codec;
25135
25139
  const fallbackPt = codec === "Pcmu" || codec === "Pcma" ? 0 : 111;
25136
25140
  const pt = senderCodec?.payloadType ?? fallbackPt;
25137
- this.prestreamAudioSilenceIfNeeded(rtpTs >>> 0, pt);
25141
+ this.sentryAudioSilenceIfNeeded(rtpTs >>> 0, pt);
25138
25142
  try {
25139
25143
  const header = new werift.RtpHeader();
25140
25144
  header.payloadType = pt;
@@ -25173,7 +25177,7 @@ var AdaptiveSession = class AdaptiveSession {
25173
25177
  * diag reads ~0). Any failure on a single `sendRtp` is logged and the loop
25174
25178
  * continues — partial alignment is better than aborting.
25175
25179
  */
25176
- prestreamAudioSilenceIfNeeded(realRtpTs, payloadType) {
25180
+ sentryAudioSilenceIfNeeded(realRtpTs, payloadType) {
25177
25181
  if (this.firstAudioFramePadded) return;
25178
25182
  this.firstAudioFramePadded = true;
25179
25183
  if (!this.audioSender || !_werift) return;