@camstack/addon-pipeline 1.2.614 → 1.2.616

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/THIRD_PARTY_MODELS.md +2 -2
  2. package/dist/audio-analyzer/index.js +3 -3
  3. package/dist/audio-analyzer/index.mjs +3 -3
  4. package/dist/{custom-model-catalog-D_mgggfr.js → custom-model-catalog-D0EZW4Xb.js} +3 -3
  5. package/dist/{custom-model-catalog-CLhfiG1p.mjs → custom-model-catalog-D3NopOC9.mjs} +3 -3
  6. package/dist/detection-pipeline/index.js +114 -6
  7. package/dist/detection-pipeline/index.mjs +114 -6
  8. package/dist/{dist-BGq_y1xM.mjs → dist-BWPVIuD_.mjs} +237 -61
  9. package/dist/{dist-F6F_xjNj.js → dist-D2aJhYm7.js} +237 -61
  10. package/dist/{model-catalogs-DrUv77wD.js → model-catalogs-BDJEmiKm.js} +14 -4
  11. package/dist/{model-catalogs-CF3WVSy_.mjs → model-catalogs-CYoIeMo4.mjs} +14 -4
  12. package/dist/motion-wasm/index.js +1 -1
  13. package/dist/motion-wasm/index.mjs +1 -1
  14. package/dist/{node-D_K-84ig.js → node-BKs5_GlD.js} +1 -1
  15. package/dist/{node-DwTqHnch.mjs → node-D48F38hW.mjs} +1 -1
  16. package/dist/pipeline-runner/index.js +3 -3
  17. package/dist/pipeline-runner/index.mjs +3 -3
  18. package/dist/{process-memory-k316CseF.mjs → process-memory-58pkBnTk.mjs} +1 -1
  19. package/dist/{process-memory-BN3N6YZh.js → process-memory-BY-1p6rF.js} +1 -1
  20. package/dist/recorder/index.js +114 -11
  21. package/dist/recorder/index.mjs +114 -11
  22. package/dist/{segment-demux-js-C4-eYvhD.js → segment-demux-js-DbM8w1dc.js} +1 -1
  23. package/dist/{segment-demux-js-CWJseQHd.mjs → segment-demux-js-VeHvPIJe.mjs} +1 -1
  24. package/dist/stream-broker/_stub.js +2 -2
  25. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DrWysXZj.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-B6vm1OlX.mjs} +3 -3
  26. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-qcb2Czgh.mjs +26 -0
  27. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BvJiBUdN.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-TnEvW5tZ.mjs} +1 -1
  28. package/dist/stream-broker/demux-worker-child.js +1 -1
  29. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  30. package/dist/stream-broker/{hostInit-D5F0gL07.mjs → hostInit-BnK9Yje5.mjs} +3 -3
  31. package/dist/stream-broker/index.js +38 -5
  32. package/dist/stream-broker/index.mjs +38 -5
  33. package/dist/stream-broker/remoteEntry.js +1 -1
  34. package/package.json +1 -1
  35. package/python/inference_pool.py +33 -0
  36. package/python/openvino_compile_probe.py +245 -0
  37. package/python/test_openvino_compile_probe.py +298 -0
  38. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-QzO03I5h.mjs +0 -26
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-F6F_xjNj.js");
7
- const require_node = require("../node-D_K-84ig.js");
6
+ const require_dist = require("../dist-D2aJhYm7.js");
7
+ const require_node = require("../node-BKs5_GlD.js");
8
8
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
9
9
  const require_restream_intent = require("../restream-intent-7uDNqMKs.js");
10
10
  let node_crypto = require("node:crypto");
@@ -2991,9 +2991,25 @@ function encodeDirectory(payload) {
2991
2991
  var MIN_INDEXABLE_SEGMENT_BYTES = 64;
2992
2992
  var SegmentStore = class SegmentStore {
2993
2993
  deps;
2994
+ stubCount = 0;
2995
+ stubBytes = 0;
2994
2996
  constructor(deps) {
2995
2997
  this.deps = deps;
2996
2998
  }
2999
+ /**
3000
+ * The stubs cleared since the last call, then reset. A recovery pass calls it
3001
+ * once and logs ONE line: ~530 stubs used to re-log at every boot because
3002
+ * each was warned about and left in staging forever.
3003
+ */
3004
+ takeStubReport() {
3005
+ const report = {
3006
+ count: this.stubCount,
3007
+ bytes: this.stubBytes
3008
+ };
3009
+ this.stubCount = 0;
3010
+ this.stubBytes = 0;
3011
+ return report;
3012
+ }
2997
3013
  async hydrate(deviceId, location) {
2998
3014
  const paths = await this.deps.list({
2999
3015
  location,
@@ -3013,13 +3029,30 @@ var SegmentStore = class SegmentStore {
3013
3029
  return null;
3014
3030
  }
3015
3031
  if (bytes < MIN_INDEXABLE_SEGMENT_BYTES) {
3016
- this.deps.logger.warn("segment too small to index — left in staging", {
3032
+ this.deps.logger.debug?.("segment too small to index — clearing stub from staging", {
3017
3033
  tags: { deviceId: input.deviceId },
3018
3034
  meta: {
3019
3035
  bytes,
3020
3036
  path: input.flatAbsPath
3021
3037
  }
3022
3038
  });
3039
+ if (this.deps.removeStaged !== void 0) {
3040
+ try {
3041
+ await this.deps.removeStaged(input.flatAbsPath);
3042
+ } catch (err) {
3043
+ this.deps.logger.warn("segment stub could not be cleared from staging", {
3044
+ tags: { deviceId: input.deviceId },
3045
+ error: err,
3046
+ meta: {
3047
+ bytes,
3048
+ path: input.flatAbsPath
3049
+ }
3050
+ });
3051
+ return null;
3052
+ }
3053
+ this.stubCount++;
3054
+ this.stubBytes += bytes;
3055
+ }
3023
3056
  return null;
3024
3057
  }
3025
3058
  const relPath = segmentRelPath(input.deviceId, input.profile, input.startMs, input.durMs, bytes);
@@ -6849,6 +6882,18 @@ Object.freeze({
6849
6882
  "empty"
6850
6883
  ]
6851
6884
  },
6885
+ {
6886
+ "path": "filterCleaningDue",
6887
+ "valueType": "boolean"
6888
+ },
6889
+ {
6890
+ "path": "machineCareDue",
6891
+ "valueType": "boolean"
6892
+ },
6893
+ {
6894
+ "path": "machineCareRemainingRuns",
6895
+ "valueType": "number"
6896
+ },
6852
6897
  {
6853
6898
  "path": "halfLoad",
6854
6899
  "valueType": "boolean"
@@ -11780,6 +11825,9 @@ var DurableLegacyKindHandle = class {
11780
11825
  aggregate = () => notImpl("aggregate");
11781
11826
  deleteWhere = () => notImpl("deleteWhere");
11782
11827
  allocateId = () => notImpl("allocateId");
11828
+ txPut = () => notImpl("txPut");
11829
+ txPatch = () => notImpl("txPatch");
11830
+ txDelete = () => notImpl("txDelete");
11783
11831
  pkColumn() {
11784
11832
  return this.spec.columns.find((c) => c.primaryKey === true)?.name ?? "id";
11785
11833
  }
@@ -18052,6 +18100,15 @@ var METHOD_FAILED = /\bmethod ([A-Z_]+) failed: (\d{3})\b/;
18052
18100
  function isHandshakeMethod(method) {
18053
18101
  return method === "OPTIONS" || method === "DESCRIBE" || method === "SETUP" || method === "PLAY";
18054
18102
  }
18103
+ /**
18104
+ * ffmpeg's account of a restream that answered DESCRIBE `200` with no SDP at
18105
+ * all (a hub that predates the 503 refusal): it opens the url and finds nothing
18106
+ * to parse — `Error opening input file rtsp://… ` + `Invalid data found when
18107
+ * processing input`, exit 183 (AVERROR_INVALIDDATA & 0xff). Same fact as a
18108
+ * refused DESCRIBE: the source is not serving right now, nothing ran.
18109
+ */
18110
+ var OPEN_FAILED = /Error opening input file rtsp:\/\//;
18111
+ var INVALID_DATA = /Invalid data found when processing input/;
18055
18112
  /** The refusal named in this generation's stderr tail, or `null` when there is none. */
18056
18113
  function readDialRefusal(stderrTail) {
18057
18114
  for (let i = stderrTail.length - 1; i >= 0; i--) {
@@ -18064,6 +18121,11 @@ function readDialRefusal(stderrTail) {
18064
18121
  status: Number(match[2])
18065
18122
  };
18066
18123
  }
18124
+ const text = stderrTail.join("\n");
18125
+ if (OPEN_FAILED.test(text) && INVALID_DATA.test(text)) return {
18126
+ method: "DESCRIBE",
18127
+ status: 503
18128
+ };
18067
18129
  return null;
18068
18130
  }
18069
18131
  //#endregion
@@ -18465,10 +18527,11 @@ var RecordingStallMonitor = class {
18465
18527
  });
18466
18528
  return;
18467
18529
  }
18530
+ const edge = prev?.expected !== true;
18468
18531
  this.state.set(deviceId, {
18469
18532
  expected: true,
18470
- lastSegmentAt: prev?.lastSegmentAt ?? now,
18471
- stalledReported: prev?.stalledReported ?? false,
18533
+ lastSegmentAt: edge ? now : prev?.lastSegmentAt ?? now,
18534
+ stalledReported: edge ? false : prev?.stalledReported ?? false,
18472
18535
  lastDegradedAt: prev?.lastDegradedAt ?? null
18473
18536
  });
18474
18537
  }
@@ -18836,6 +18899,15 @@ var RecordingController = class {
18836
18899
  */
18837
18900
  lastSegmentAt = /* @__PURE__ */ new Map();
18838
18901
  /**
18902
+ * Per `deviceId:profile`, when a segment was last FINALIZED — never seeded at
18903
+ * the pin. {@link lastSegmentAt} answers "is this writer still in its grace
18904
+ * window"; this answers "has it actually produced anything recently", which is
18905
+ * what a give-up may claim about the siblings it keeps (2026-10-22, camera
18906
+ * 618: both writers dead, each give-up said the other "keeps recording").
18907
+ * Cleared with {@link lastSegmentAt}.
18908
+ */
18909
+ lastProducedAt = /* @__PURE__ */ new Map();
18910
+ /**
18839
18911
  * Per `deviceId:profile`, the `attachedAtMs` of the attach that has retained
18840
18912
  * at least one `events` segment. Read only to LEVEL the discard log: an
18841
18913
  * attach that kept nothing is a wasted pull (warn), a later discard from one
@@ -19376,11 +19448,21 @@ var RecordingController = class {
19376
19448
  const stalled = profile === void 0 ? current : current.filter((r) => r.profile === profile);
19377
19449
  if (stalled.length === 0) return;
19378
19450
  const keep = profile === void 0 ? [] : current.filter((r) => r.profile !== profile);
19379
- if (keep.length === 0) {
19380
- this.deps.logger.warn("recorder: writer gave up — detaching + re-evaluating device", {
19381
- tags: { deviceId },
19382
- ...profile !== void 0 ? { meta: { profile } } : {}
19383
- });
19451
+ const now = this.now();
19452
+ const producing = keep.filter((r) => this.producedRecently(deviceId, r, now));
19453
+ const silentSiblings = keep.filter((r) => !producing.includes(r)).map((r) => r.profile);
19454
+ if (keep.length > 0 && producing.length === 0) this.deps.logger.warn("recorder: writer gave up — no profile produced a segment recently (all stalled) — detaching + re-evaluating device", {
19455
+ tags: { deviceId },
19456
+ meta: {
19457
+ profile,
19458
+ stalledSiblings: silentSiblings
19459
+ }
19460
+ });
19461
+ else if (keep.length === 0) this.deps.logger.warn("recorder: writer gave up — detaching + re-evaluating device", {
19462
+ tags: { deviceId },
19463
+ ...profile !== void 0 ? { meta: { profile } } : {}
19464
+ });
19465
+ if (producing.length === 0) {
19384
19466
  try {
19385
19467
  await this.detachDevice(deviceId);
19386
19468
  await this.evaluateDevice(deviceId);
@@ -19397,7 +19479,8 @@ var RecordingController = class {
19397
19479
  tags: { deviceId },
19398
19480
  meta: {
19399
19481
  profile: stalled.map((r) => r.profile),
19400
- keeping: keep.map((r) => r.profile)
19482
+ keeping: producing.map((r) => r.profile),
19483
+ ...silentSiblings.length > 0 ? { pinnedWithoutSegment: silentSiblings } : {}
19401
19484
  }
19402
19485
  });
19403
19486
  try {
@@ -19413,6 +19496,11 @@ var RecordingController = class {
19413
19496
  });
19414
19497
  }
19415
19498
  }
19499
+ /** Did this writer finalize a segment within its idle bound? Seeding at the pin does not count. */
19500
+ producedRecently(deviceId, r, now) {
19501
+ const at = this.lastProducedAt.get(idleKey(deviceId, r.profile));
19502
+ return at !== void 0 && now - at <= writerIdleBoundMs(r.segmentSeconds);
19503
+ }
19416
19504
  /**
19417
19505
  * Tear down only the stalled writers, keep the rest pinned, and retry the
19418
19506
  * missing profiles through {@link fillMissingProfiles}.
@@ -19420,6 +19508,7 @@ var RecordingController = class {
19420
19508
  async recoverStalledProfiles(deviceId, stalled, keep) {
19421
19509
  for (const r of stalled) {
19422
19510
  this.lastSegmentAt.delete(idleKey(deviceId, r.profile));
19511
+ this.lastProducedAt.delete(idleKey(deviceId, r.profile));
19423
19512
  this.attachRetained.delete(idleKey(deviceId, r.profile));
19424
19513
  }
19425
19514
  this.active.set(deviceId, [...keep]);
@@ -20161,6 +20250,7 @@ var RecordingController = class {
20161
20250
  onFinalized: async (startMs, durMs, flatAbsPath) => {
20162
20251
  const segmentAt = this.now();
20163
20252
  this.lastSegmentAt.set(idleKey(deviceId, profile), segmentAt);
20253
+ this.lastProducedAt.set(idleKey(deviceId, profile), segmentAt);
20164
20254
  const recovered = this.stallMonitor.noteSegment(deviceId, segmentAt);
20165
20255
  if (recovered !== null) this.deps.emitRecordingHealth?.(require_dist.EventCategory.RecordingHealthOk, { deviceId: recovered.deviceId });
20166
20256
  if (startMs >= writerStartedMs - 1e3 && !firstSegmentSeen) {
@@ -20340,6 +20430,7 @@ var RecordingController = class {
20340
20430
  this.skippedProfiles.delete(deviceId);
20341
20431
  for (const r of recordings) {
20342
20432
  this.lastSegmentAt.delete(idleKey(deviceId, r.profile));
20433
+ this.lastProducedAt.delete(idleKey(deviceId, r.profile));
20343
20434
  this.attachRetained.delete(idleKey(deviceId, r.profile));
20344
20435
  }
20345
20436
  await Promise.all(recordings.map((r) => this.teardownProfile(deviceId, r)));
@@ -23807,6 +23898,7 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
23807
23898
  list: (input) => this.ctx.api.storage.list.query(input),
23808
23899
  deletePath: (input) => this.ctx.api.storage.delete.mutate(input),
23809
23900
  statBytes: async (absPath) => (await node_fs.promises.stat(absPath)).size,
23901
+ removeStaged: (absPath) => node_fs.promises.rm(absPath, { force: true }),
23810
23902
  moveFile: async (fromAbs, toAbs) => {
23811
23903
  await node_fs.promises.mkdir(node_path.default.dirname(toAbs), { recursive: true });
23812
23904
  try {
@@ -23873,6 +23965,12 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
23873
23965
  },
23874
23966
  info: (message, extras) => {
23875
23967
  this.ctx.logger.info(message, { meta: extras.meta });
23968
+ },
23969
+ debug: (message, extras) => {
23970
+ this.ctx.logger.debug(message, {
23971
+ tags: extras.tags,
23972
+ meta: extras.meta
23973
+ });
23876
23974
  }
23877
23975
  }
23878
23976
  };
@@ -25433,6 +25531,11 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
25433
25531
  defaultSegmentSeconds: this.config.segmentSeconds,
25434
25532
  shouldStop: () => this.segmentStore === null
25435
25533
  });
25534
+ const stubs = this.segmentStore?.takeStubReport();
25535
+ if (stubs !== void 0 && stubs.count > 0) this.ctx.logger.info("recorder: staging recovery cleared stub segments", { meta: {
25536
+ count: stubs.count,
25537
+ bytes: stubs.bytes
25538
+ } });
25436
25539
  } catch (err) {
25437
25540
  this.ctx.logger.warn("recorder: staging boot reconcile failed", { meta: { error: require_dist.errMsg(err) } });
25438
25541
  }
@@ -1,5 +1,5 @@
1
- import { An as DeviceFeature, B as RECORDING_SOURCE_CAMSTACK_ADDON, Bt as mayWriteToLocation, C as EVENT_PAD_MS, Dn as evaluateSensorEdge, Et as exportSubjectOf, G as VIDEOCLIPS_MAX_OFFER_BYTES, H as RecordingConfigSchema, Hn as defineCustomActions, Ht as migrateLegacyDeviceSignalConfig, It as loadContributionCapability, K as VISIT_MERGE_GAP_MS, Kn as hydrateSchema, Mn as errMsg$1, N as OpsLogEntrySchema, Nt as isFirstLevelMacroClass, Pn as BaseAddon, Qn as nodePin, R as RECORDING_EXPORT_MAX_READ_BYTES, S as EVENT_OWNER_TYPES, T as ExportRecordSchema, Tt as evictionPolicyOfLocation, U as RecordingSignalStatusSchema, Un as defineRecordKinds, Ut as modeMayWrite, Vn as customAction, Vt as memoizePinnedFfmpeg, Z as armRemovalReconcile, _n as storageOccupancyCapability, an as resolveCreateExportSubject, ar as boolean, at as clipExportFailure, dr as preprocess, en as recordingArchiveCapability, er as selectAssignedProfileSlots, fr as record, gn as storageEvictableCapability, hr as EventCategory, ht as deriveRecordingMode, ir as array, jn as DeviceType, kt as gbToBytes, lr as number, mn as startMoverUnderClearance, nn as recordingExportCapability, nr as userError, o as BatteryStatusSchema, ot as clipExportFailureOf, pr as string, pt as deriveBatteryPresence, rn as recordingSignalCapability, rr as _enum, s as CLIP_BROKER_PACED_RATES, sn as resolveLocationMode, tn as recordingCapability, tr as sleep$1, tt as batteryCapability, un as resolveRecordingProfiles, ur as object, v as DEFAULT_EVENTS_BAND_BUFFER_SEC, vt as deviceRemovalHookCapability, wt as evictionPolicyForMode, xn as videoclipsCapability, yn as stripRetiredBandPreBufferSec, z as RECORDING_SOURCE_CAMSTACK, zt as mayReadLocation } from "../dist-BGq_y1xM.mjs";
2
- import { i as NO_COST_CLAIM, o as physicalRootOf, t as ChildCostRegistry } from "../node-DwTqHnch.mjs";
1
+ import { An as DeviceFeature, B as RECORDING_SOURCE_CAMSTACK_ADDON, Bt as mayWriteToLocation, C as EVENT_PAD_MS, Dn as evaluateSensorEdge, Et as exportSubjectOf, G as VIDEOCLIPS_MAX_OFFER_BYTES, H as RecordingConfigSchema, Hn as defineCustomActions, Ht as migrateLegacyDeviceSignalConfig, It as loadContributionCapability, K as VISIT_MERGE_GAP_MS, Kn as hydrateSchema, Mn as errMsg$1, N as OpsLogEntrySchema, Nt as isFirstLevelMacroClass, Pn as BaseAddon, Qn as nodePin, R as RECORDING_EXPORT_MAX_READ_BYTES, S as EVENT_OWNER_TYPES, T as ExportRecordSchema, Tt as evictionPolicyOfLocation, U as RecordingSignalStatusSchema, Un as defineRecordKinds, Ut as modeMayWrite, Vn as customAction, Vt as memoizePinnedFfmpeg, Z as armRemovalReconcile, _n as storageOccupancyCapability, an as resolveCreateExportSubject, ar as boolean, at as clipExportFailure, dr as preprocess, en as recordingArchiveCapability, er as selectAssignedProfileSlots, fr as record, gn as storageEvictableCapability, hr as EventCategory, ht as deriveRecordingMode, ir as array, jn as DeviceType, kt as gbToBytes, lr as number, mn as startMoverUnderClearance, nn as recordingExportCapability, nr as userError, o as BatteryStatusSchema, ot as clipExportFailureOf, pr as string, pt as deriveBatteryPresence, rn as recordingSignalCapability, rr as _enum, s as CLIP_BROKER_PACED_RATES, sn as resolveLocationMode, tn as recordingCapability, tr as sleep$1, tt as batteryCapability, un as resolveRecordingProfiles, ur as object, v as DEFAULT_EVENTS_BAND_BUFFER_SEC, vt as deviceRemovalHookCapability, wt as evictionPolicyForMode, xn as videoclipsCapability, yn as stripRetiredBandPreBufferSec, z as RECORDING_SOURCE_CAMSTACK, zt as mayReadLocation } from "../dist-BWPVIuD_.mjs";
2
+ import { i as NO_COST_CLAIM, o as physicalRootOf, t as ChildCostRegistry } from "../node-D48F38hW.mjs";
3
3
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
4
4
  import { d as PREBUFFER_MAX_MS, l as withRecordingIntent, r as RECORDING_PRE_ROLL_REQUEST_MS } from "../restream-intent-DyGmLAU9.mjs";
5
5
  import { randomUUID } from "node:crypto";
@@ -2984,9 +2984,25 @@ function encodeDirectory(payload) {
2984
2984
  var MIN_INDEXABLE_SEGMENT_BYTES = 64;
2985
2985
  var SegmentStore = class SegmentStore {
2986
2986
  deps;
2987
+ stubCount = 0;
2988
+ stubBytes = 0;
2987
2989
  constructor(deps) {
2988
2990
  this.deps = deps;
2989
2991
  }
2992
+ /**
2993
+ * The stubs cleared since the last call, then reset. A recovery pass calls it
2994
+ * once and logs ONE line: ~530 stubs used to re-log at every boot because
2995
+ * each was warned about and left in staging forever.
2996
+ */
2997
+ takeStubReport() {
2998
+ const report = {
2999
+ count: this.stubCount,
3000
+ bytes: this.stubBytes
3001
+ };
3002
+ this.stubCount = 0;
3003
+ this.stubBytes = 0;
3004
+ return report;
3005
+ }
2990
3006
  async hydrate(deviceId, location) {
2991
3007
  const paths = await this.deps.list({
2992
3008
  location,
@@ -3006,13 +3022,30 @@ var SegmentStore = class SegmentStore {
3006
3022
  return null;
3007
3023
  }
3008
3024
  if (bytes < MIN_INDEXABLE_SEGMENT_BYTES) {
3009
- this.deps.logger.warn("segment too small to index — left in staging", {
3025
+ this.deps.logger.debug?.("segment too small to index — clearing stub from staging", {
3010
3026
  tags: { deviceId: input.deviceId },
3011
3027
  meta: {
3012
3028
  bytes,
3013
3029
  path: input.flatAbsPath
3014
3030
  }
3015
3031
  });
3032
+ if (this.deps.removeStaged !== void 0) {
3033
+ try {
3034
+ await this.deps.removeStaged(input.flatAbsPath);
3035
+ } catch (err) {
3036
+ this.deps.logger.warn("segment stub could not be cleared from staging", {
3037
+ tags: { deviceId: input.deviceId },
3038
+ error: err,
3039
+ meta: {
3040
+ bytes,
3041
+ path: input.flatAbsPath
3042
+ }
3043
+ });
3044
+ return null;
3045
+ }
3046
+ this.stubCount++;
3047
+ this.stubBytes += bytes;
3048
+ }
3016
3049
  return null;
3017
3050
  }
3018
3051
  const relPath = segmentRelPath(input.deviceId, input.profile, input.startMs, input.durMs, bytes);
@@ -6841,6 +6874,18 @@ Object.freeze({
6841
6874
  "empty"
6842
6875
  ]
6843
6876
  },
6877
+ {
6878
+ "path": "filterCleaningDue",
6879
+ "valueType": "boolean"
6880
+ },
6881
+ {
6882
+ "path": "machineCareDue",
6883
+ "valueType": "boolean"
6884
+ },
6885
+ {
6886
+ "path": "machineCareRemainingRuns",
6887
+ "valueType": "number"
6888
+ },
6844
6889
  {
6845
6890
  "path": "halfLoad",
6846
6891
  "valueType": "boolean"
@@ -11772,6 +11817,9 @@ var DurableLegacyKindHandle = class {
11772
11817
  aggregate = () => notImpl("aggregate");
11773
11818
  deleteWhere = () => notImpl("deleteWhere");
11774
11819
  allocateId = () => notImpl("allocateId");
11820
+ txPut = () => notImpl("txPut");
11821
+ txPatch = () => notImpl("txPatch");
11822
+ txDelete = () => notImpl("txDelete");
11775
11823
  pkColumn() {
11776
11824
  return this.spec.columns.find((c) => c.primaryKey === true)?.name ?? "id";
11777
11825
  }
@@ -18044,6 +18092,15 @@ var METHOD_FAILED = /\bmethod ([A-Z_]+) failed: (\d{3})\b/;
18044
18092
  function isHandshakeMethod(method) {
18045
18093
  return method === "OPTIONS" || method === "DESCRIBE" || method === "SETUP" || method === "PLAY";
18046
18094
  }
18095
+ /**
18096
+ * ffmpeg's account of a restream that answered DESCRIBE `200` with no SDP at
18097
+ * all (a hub that predates the 503 refusal): it opens the url and finds nothing
18098
+ * to parse — `Error opening input file rtsp://… ` + `Invalid data found when
18099
+ * processing input`, exit 183 (AVERROR_INVALIDDATA & 0xff). Same fact as a
18100
+ * refused DESCRIBE: the source is not serving right now, nothing ran.
18101
+ */
18102
+ var OPEN_FAILED = /Error opening input file rtsp:\/\//;
18103
+ var INVALID_DATA = /Invalid data found when processing input/;
18047
18104
  /** The refusal named in this generation's stderr tail, or `null` when there is none. */
18048
18105
  function readDialRefusal(stderrTail) {
18049
18106
  for (let i = stderrTail.length - 1; i >= 0; i--) {
@@ -18056,6 +18113,11 @@ function readDialRefusal(stderrTail) {
18056
18113
  status: Number(match[2])
18057
18114
  };
18058
18115
  }
18116
+ const text = stderrTail.join("\n");
18117
+ if (OPEN_FAILED.test(text) && INVALID_DATA.test(text)) return {
18118
+ method: "DESCRIBE",
18119
+ status: 503
18120
+ };
18059
18121
  return null;
18060
18122
  }
18061
18123
  //#endregion
@@ -18457,10 +18519,11 @@ var RecordingStallMonitor = class {
18457
18519
  });
18458
18520
  return;
18459
18521
  }
18522
+ const edge = prev?.expected !== true;
18460
18523
  this.state.set(deviceId, {
18461
18524
  expected: true,
18462
- lastSegmentAt: prev?.lastSegmentAt ?? now,
18463
- stalledReported: prev?.stalledReported ?? false,
18525
+ lastSegmentAt: edge ? now : prev?.lastSegmentAt ?? now,
18526
+ stalledReported: edge ? false : prev?.stalledReported ?? false,
18464
18527
  lastDegradedAt: prev?.lastDegradedAt ?? null
18465
18528
  });
18466
18529
  }
@@ -18828,6 +18891,15 @@ var RecordingController = class {
18828
18891
  */
18829
18892
  lastSegmentAt = /* @__PURE__ */ new Map();
18830
18893
  /**
18894
+ * Per `deviceId:profile`, when a segment was last FINALIZED — never seeded at
18895
+ * the pin. {@link lastSegmentAt} answers "is this writer still in its grace
18896
+ * window"; this answers "has it actually produced anything recently", which is
18897
+ * what a give-up may claim about the siblings it keeps (2026-10-22, camera
18898
+ * 618: both writers dead, each give-up said the other "keeps recording").
18899
+ * Cleared with {@link lastSegmentAt}.
18900
+ */
18901
+ lastProducedAt = /* @__PURE__ */ new Map();
18902
+ /**
18831
18903
  * Per `deviceId:profile`, the `attachedAtMs` of the attach that has retained
18832
18904
  * at least one `events` segment. Read only to LEVEL the discard log: an
18833
18905
  * attach that kept nothing is a wasted pull (warn), a later discard from one
@@ -19368,11 +19440,21 @@ var RecordingController = class {
19368
19440
  const stalled = profile === void 0 ? current : current.filter((r) => r.profile === profile);
19369
19441
  if (stalled.length === 0) return;
19370
19442
  const keep = profile === void 0 ? [] : current.filter((r) => r.profile !== profile);
19371
- if (keep.length === 0) {
19372
- this.deps.logger.warn("recorder: writer gave up — detaching + re-evaluating device", {
19373
- tags: { deviceId },
19374
- ...profile !== void 0 ? { meta: { profile } } : {}
19375
- });
19443
+ const now = this.now();
19444
+ const producing = keep.filter((r) => this.producedRecently(deviceId, r, now));
19445
+ const silentSiblings = keep.filter((r) => !producing.includes(r)).map((r) => r.profile);
19446
+ if (keep.length > 0 && producing.length === 0) this.deps.logger.warn("recorder: writer gave up — no profile produced a segment recently (all stalled) — detaching + re-evaluating device", {
19447
+ tags: { deviceId },
19448
+ meta: {
19449
+ profile,
19450
+ stalledSiblings: silentSiblings
19451
+ }
19452
+ });
19453
+ else if (keep.length === 0) this.deps.logger.warn("recorder: writer gave up — detaching + re-evaluating device", {
19454
+ tags: { deviceId },
19455
+ ...profile !== void 0 ? { meta: { profile } } : {}
19456
+ });
19457
+ if (producing.length === 0) {
19376
19458
  try {
19377
19459
  await this.detachDevice(deviceId);
19378
19460
  await this.evaluateDevice(deviceId);
@@ -19389,7 +19471,8 @@ var RecordingController = class {
19389
19471
  tags: { deviceId },
19390
19472
  meta: {
19391
19473
  profile: stalled.map((r) => r.profile),
19392
- keeping: keep.map((r) => r.profile)
19474
+ keeping: producing.map((r) => r.profile),
19475
+ ...silentSiblings.length > 0 ? { pinnedWithoutSegment: silentSiblings } : {}
19393
19476
  }
19394
19477
  });
19395
19478
  try {
@@ -19405,6 +19488,11 @@ var RecordingController = class {
19405
19488
  });
19406
19489
  }
19407
19490
  }
19491
+ /** Did this writer finalize a segment within its idle bound? Seeding at the pin does not count. */
19492
+ producedRecently(deviceId, r, now) {
19493
+ const at = this.lastProducedAt.get(idleKey(deviceId, r.profile));
19494
+ return at !== void 0 && now - at <= writerIdleBoundMs(r.segmentSeconds);
19495
+ }
19408
19496
  /**
19409
19497
  * Tear down only the stalled writers, keep the rest pinned, and retry the
19410
19498
  * missing profiles through {@link fillMissingProfiles}.
@@ -19412,6 +19500,7 @@ var RecordingController = class {
19412
19500
  async recoverStalledProfiles(deviceId, stalled, keep) {
19413
19501
  for (const r of stalled) {
19414
19502
  this.lastSegmentAt.delete(idleKey(deviceId, r.profile));
19503
+ this.lastProducedAt.delete(idleKey(deviceId, r.profile));
19415
19504
  this.attachRetained.delete(idleKey(deviceId, r.profile));
19416
19505
  }
19417
19506
  this.active.set(deviceId, [...keep]);
@@ -20153,6 +20242,7 @@ var RecordingController = class {
20153
20242
  onFinalized: async (startMs, durMs, flatAbsPath) => {
20154
20243
  const segmentAt = this.now();
20155
20244
  this.lastSegmentAt.set(idleKey(deviceId, profile), segmentAt);
20245
+ this.lastProducedAt.set(idleKey(deviceId, profile), segmentAt);
20156
20246
  const recovered = this.stallMonitor.noteSegment(deviceId, segmentAt);
20157
20247
  if (recovered !== null) this.deps.emitRecordingHealth?.(EventCategory.RecordingHealthOk, { deviceId: recovered.deviceId });
20158
20248
  if (startMs >= writerStartedMs - 1e3 && !firstSegmentSeen) {
@@ -20332,6 +20422,7 @@ var RecordingController = class {
20332
20422
  this.skippedProfiles.delete(deviceId);
20333
20423
  for (const r of recordings) {
20334
20424
  this.lastSegmentAt.delete(idleKey(deviceId, r.profile));
20425
+ this.lastProducedAt.delete(idleKey(deviceId, r.profile));
20335
20426
  this.attachRetained.delete(idleKey(deviceId, r.profile));
20336
20427
  }
20337
20428
  await Promise.all(recordings.map((r) => this.teardownProfile(deviceId, r)));
@@ -23799,6 +23890,7 @@ var RecorderV2Addon = class extends BaseAddon {
23799
23890
  list: (input) => this.ctx.api.storage.list.query(input),
23800
23891
  deletePath: (input) => this.ctx.api.storage.delete.mutate(input),
23801
23892
  statBytes: async (absPath) => (await promises.stat(absPath)).size,
23893
+ removeStaged: (absPath) => promises.rm(absPath, { force: true }),
23802
23894
  moveFile: async (fromAbs, toAbs) => {
23803
23895
  await promises.mkdir(path.dirname(toAbs), { recursive: true });
23804
23896
  try {
@@ -23865,6 +23957,12 @@ var RecorderV2Addon = class extends BaseAddon {
23865
23957
  },
23866
23958
  info: (message, extras) => {
23867
23959
  this.ctx.logger.info(message, { meta: extras.meta });
23960
+ },
23961
+ debug: (message, extras) => {
23962
+ this.ctx.logger.debug(message, {
23963
+ tags: extras.tags,
23964
+ meta: extras.meta
23965
+ });
23868
23966
  }
23869
23967
  }
23870
23968
  };
@@ -25425,6 +25523,11 @@ var RecorderV2Addon = class extends BaseAddon {
25425
25523
  defaultSegmentSeconds: this.config.segmentSeconds,
25426
25524
  shouldStop: () => this.segmentStore === null
25427
25525
  });
25526
+ const stubs = this.segmentStore?.takeStubReport();
25527
+ if (stubs !== void 0 && stubs.count > 0) this.ctx.logger.info("recorder: staging recovery cleared stub segments", { meta: {
25528
+ count: stubs.count,
25529
+ bytes: stubs.bytes
25530
+ } });
25428
25531
  } catch (err) {
25429
25532
  this.ctx.logger.warn("recorder: staging boot reconcile failed", { meta: { error: errMsg$1(err) } });
25430
25533
  }
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-F6F_xjNj.js");
2
+ const require_dist = require("./dist-D2aJhYm7.js");
3
3
  let node_child_process = require("node:child_process");
4
4
  //#region src/stream-broker/recorded/avcc-annexb.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import { r as __toESM, t as __commonJSMin } from "./chunk-DnnnRqeS.mjs";
2
- import { Mn as errMsg } from "./dist-BGq_y1xM.mjs";
2
+ import { Mn as errMsg } from "./dist-BWPVIuD_.mjs";
3
3
  import { spawn } from "node:child_process";
4
4
  //#region src/stream-broker/recorded/avcc-annexb.ts
5
5
  /**
@@ -1,7 +1,7 @@
1
- import { a as e, c as t, d as n, f as r, i, l as a, m as o, n as s, o as c, p as l, r as u, s as d, t as f, u as p } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BvJiBUdN.mjs";
1
+ import { a as e, c as t, d as n, f as r, i, l as a, m as o, n as s, o as c, p as l, r as u, s as d, t as f, u as p } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-TnEvW5tZ.mjs";
2
2
  import { a as m, i as h, n as g, o as _, r as v, t as y } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.js-C9j-2lBe.mjs";
3
3
  import { n as b, r as x, t as S } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-XO0-Pyu6.mjs";
4
- import { t as C } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-QzO03I5h.mjs";
4
+ import { t as C } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-qcb2Czgh.mjs";
5
5
  import { n as w, t as T } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-BO7TIbJV.mjs";
6
6
  //#region ../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
7
7
  var E = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) === t).join(" ").trim(), D = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), O = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), k = (e) => {
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
3
3
  var e = {
4
4
  "@camstack/sdk": {
5
5
  name: "@camstack/sdk",
6
- version: "1.2.146",
6
+ version: "1.2.148",
7
7
  scope: ["default"],
8
8
  loaded: !1,
9
9
  from: "addon_stream_broker_widgets",
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.396",
21
+ version: "1.2.398",
22
22
  scope: ["default"],
23
23
  loaded: !1,
24
24
  from: "addon_stream_broker_widgets",
@@ -33,7 +33,7 @@ var e = {
33
33
  },
34
34
  "@camstack/ui-library": {
35
35
  name: "@camstack/ui-library",
36
- version: "1.2.313",
36
+ version: "1.2.315",
37
37
  scope: ["default"],
38
38
  loaded: !1,
39
39
  from: "addon_stream_broker_widgets",