@camstack/addon-pipeline 1.2.356 → 1.2.358

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 +3 -3
  2. package/dist/audio-analyzer/index.mjs +3 -3
  3. package/dist/{custom-model-catalog-DmgH7i0_.js → custom-model-catalog-BplFsaKz.js} +2 -2
  4. package/dist/{custom-model-catalog-DQKIvNnb.mjs → custom-model-catalog-DctVXbQ1.mjs} +2 -2
  5. package/dist/detection-pipeline/index.js +4 -4
  6. package/dist/detection-pipeline/index.mjs +4 -4
  7. package/dist/{dist-DIvGLRdM.js → dist-Bdrk1nVH.js} +55 -3
  8. package/dist/{dist-BghVPOQJ.mjs → dist-DBp0sJSg.mjs} +55 -3
  9. package/dist/{model-catalogs-CF0mHUVB.js → model-catalogs-N2y8-Q01.js} +1 -1
  10. package/dist/{model-catalogs-Z-XWcl2N.mjs → model-catalogs-vaTuHPUc.mjs} +1 -1
  11. package/dist/motion-wasm/index.js +1 -1
  12. package/dist/motion-wasm/index.mjs +1 -1
  13. package/dist/{node-KGZFTDup.js → node-CRx-Wwok.js} +1 -1
  14. package/dist/{node-BEnsSyvU.mjs → node-IWKQZ5Xj.mjs} +1 -1
  15. package/dist/pipeline-runner/index.js +3 -3
  16. package/dist/pipeline-runner/index.mjs +3 -3
  17. package/dist/{process-memory-Cb2PecT1.js → process-memory-BVSmOEyu.js} +1 -1
  18. package/dist/{process-memory-BzQ7asa_.mjs → process-memory-CDfbnBGD.mjs} +1 -1
  19. package/dist/recorder/index.js +127 -3
  20. package/dist/recorder/index.mjs +127 -3
  21. package/dist/{segment-demux-js-ChKm1pOF.mjs → segment-demux-js-B1Mx4mJd.mjs} +1 -1
  22. package/dist/{segment-demux-js-CnaecM7W.js → segment-demux-js-BmpHWno-.js} +1 -1
  23. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BTzjBMRP.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Ccq5jxp-.mjs} +2 -2
  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-Ca4T0pWT.mjs → hostInit-C7zIjG_F.mjs} +2 -2
  27. package/dist/stream-broker/index.js +3 -3
  28. package/dist/stream-broker/index.mjs +3 -3
  29. package/dist/stream-broker/remoteEntry.js +1 -1
  30. package/package.json +1 -1
@@ -3,9 +3,9 @@ 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-DIvGLRdM.js");
7
- const require_model_catalogs = require("../model-catalogs-CF0mHUVB.js");
8
- const require_process_memory = require("../process-memory-Cb2PecT1.js");
6
+ const require_dist = require("../dist-Bdrk1nVH.js");
7
+ const require_model_catalogs = require("../model-catalogs-N2y8-Q01.js");
8
+ const require_process_memory = require("../process-memory-BVSmOEyu.js");
9
9
  let node_fs = require("node:fs");
10
10
  node_fs = require_chunk.__toESM(node_fs);
11
11
  let node_path = require("node:path");
@@ -1,7 +1,7 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { $ as audioAnalysisCapability, Hn as hydrateSchema, Kn as nodePin, L as PoolMemoryWatchdog, Ln as audioChunkBytesPerSample, Mn as errMsg, Pn as BaseAddon, Rt as mapAudioLabelToMacro, Vn as expandAudioChunkToF32le, cr as EventCategory, et as audioAnalyzerCapability, h as DEFAULT_AUDIO_ANALYZER_CONFIG, r as AUDIO_BACKEND_CHOICES, un as resolvePoolMemoryPolicy } from "../dist-BghVPOQJ.mjs";
3
- import { n as AUDIO_CLASSIFIER_MODELS } from "../model-catalogs-Z-XWcl2N.mjs";
4
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BzQ7asa_.mjs";
2
+ import { $ as audioAnalysisCapability, Hn as hydrateSchema, Kn as nodePin, L as PoolMemoryWatchdog, Ln as audioChunkBytesPerSample, Mn as errMsg, Pn as BaseAddon, Rt as mapAudioLabelToMacro, Vn as expandAudioChunkToF32le, cr as EventCategory, et as audioAnalyzerCapability, h as DEFAULT_AUDIO_ANALYZER_CONFIG, r as AUDIO_BACKEND_CHOICES, un as resolvePoolMemoryPolicy } from "../dist-DBp0sJSg.mjs";
3
+ import { n as AUDIO_CLASSIFIER_MODELS } from "../model-catalogs-vaTuHPUc.mjs";
4
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-CDfbnBGD.mjs";
5
5
  import * as fs from "node:fs";
6
6
  import * as path$1 from "node:path";
7
7
  import { ensureModel } from "@camstack/system/addon-utils";
@@ -1,5 +1,5 @@
1
- const require_dist = require("./dist-DIvGLRdM.js");
2
- const require_model_catalogs = require("./model-catalogs-CF0mHUVB.js");
1
+ const require_dist = require("./dist-Bdrk1nVH.js");
2
+ const require_model_catalogs = require("./model-catalogs-N2y8-Q01.js");
3
3
  const require_worker_protocol = require("./worker-protocol-C-G8qmye.js");
4
4
  let node_crypto = require("node:crypto");
5
5
  //#region src/detection-pipeline/registry/effective-confidence.ts
@@ -1,5 +1,5 @@
1
- import { A as LABEL_SUPPLY_VOCABULARIES, Mt as inferModelProvider, b as DEVICE_BACKEND_TO_FORMAT, f as COCO_80_LABELS, hn as stepModelRunsOnFormat, i as AUDIO_MACRO_LABELS, p as COCO_TO_MACRO, tt as audioKindId } from "./dist-BghVPOQJ.mjs";
2
- import { a as FACE_DETECTION_MODELS, c as OBJECT_DETECTION_MODELS, d as PLATE_OCR_MODELS, f as SEGMENTATION_REFINER_MODELS, i as CLIP_EMBEDDING_MODELS, l as PACKAGE_DETECTION_MODELS, n as AUDIO_CLASSIFIER_MODELS, o as FACE_EMBEDDING_MODELS, p as VEHICLE_CLASSIFIER_MODELS, r as BIRD_CLASSIFIER_MODELS, s as INSTANCE_SEGMENTATION_MODELS, t as ANIMAL_CLASSIFIER_MODELS, u as PLATE_DETECTION_MODELS } from "./model-catalogs-Z-XWcl2N.mjs";
1
+ import { A as LABEL_SUPPLY_VOCABULARIES, Mt as inferModelProvider, b as DEVICE_BACKEND_TO_FORMAT, f as COCO_80_LABELS, hn as stepModelRunsOnFormat, i as AUDIO_MACRO_LABELS, p as COCO_TO_MACRO, tt as audioKindId } from "./dist-DBp0sJSg.mjs";
2
+ import { a as FACE_DETECTION_MODELS, c as OBJECT_DETECTION_MODELS, d as PLATE_OCR_MODELS, f as SEGMENTATION_REFINER_MODELS, i as CLIP_EMBEDDING_MODELS, l as PACKAGE_DETECTION_MODELS, n as AUDIO_CLASSIFIER_MODELS, o as FACE_EMBEDDING_MODELS, p as VEHICLE_CLASSIFIER_MODELS, r as BIRD_CLASSIFIER_MODELS, s as INSTANCE_SEGMENTATION_MODELS, t as ANIMAL_CLASSIFIER_MODELS, u as PLATE_DETECTION_MODELS } from "./model-catalogs-vaTuHPUc.mjs";
3
3
  import { t as isWorkerReply } from "./worker-protocol-D_NzPcnh.mjs";
4
4
  import { randomUUID } from "node:crypto";
5
5
  //#region src/detection-pipeline/registry/effective-confidence.ts
@@ -3,11 +3,11 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../chunk-emK7D4bc.js");
6
- const require_dist = require("../dist-DIvGLRdM.js");
7
- const require_node = require("../node-KGZFTDup.js");
8
- const require_custom_model_catalog = require("../custom-model-catalog-DmgH7i0_.js");
6
+ const require_dist = require("../dist-Bdrk1nVH.js");
7
+ const require_node = require("../node-CRx-Wwok.js");
8
+ const require_custom_model_catalog = require("../custom-model-catalog-BplFsaKz.js");
9
9
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
10
- const require_process_memory = require("../process-memory-Cb2PecT1.js");
10
+ const require_process_memory = require("../process-memory-BVSmOEyu.js");
11
11
  let node_os = require("node:os");
12
12
  node_os = require_chunk.__toESM(node_os);
13
13
  let node_fs = require("node:fs");
@@ -1,9 +1,9 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { Gt as modelBindingKey, Hn as hydrateSchema, It as loadContributionCapability, Kn as nodePin, L as PoolMemoryWatchdog, Mn as errMsg$1, Pn as BaseAddon, Pt as linkedLabelStepId, Q as applyModelBoundSettings, Qt as pipelineExecutorCapability, Rn as createEvent, St as evaluateZoneRules, Y as YAMNET_TO_MACRO, Yn as sleep, Yt as pickClusterStepSettings, Zn as array, an as resolveClusterStepModelId, bn as supportedRuntimes$1, cr as EventCategory, ct as collectModelBoundKeys, d as CLUSTER_MODEL_SCOPED_STEPS, g as DEFAULT_CLUSTER_STEP_SETTINGS, hn as stepModelRunsOnFormat, jt as hfModelUrl, k as LABEL_SUPPLY_MACRO, lt as containingParentIndex, mn as runtimeDevices$1, n as APPLE_SA_TO_MACRO, or as string, pn as rootSuppliesOf, pt as defaultDeviceFor$1, qt as overlayClusterStepSettings, rr as object, sr as union, un as resolvePoolMemoryPolicy, vt as detectionPipelineCapability, xt as enumerateInferenceDevices } from "../dist-BghVPOQJ.mjs";
3
- import { s as readProcessCost } from "../node-BEnsSyvU.mjs";
4
- import { C as resolveModelDefaultConfidence, S as landmarkPrecisionVerdict, _ as ALL_STEPS, b as getStepDefinition, f as localFrameRegistry, g as ALL_PIPELINE_STEPS, l as resolveDefaultDetectionModel, n as mergeCustomModels, o as deviceKeyOf, r as buildSubtreeCanRun, s as resolveDeviceEngine, t as CustomModelCatalog, u as macroGateVerdict, v as getDefaultModelForFormat, x as resolveModelForFormat, y as getStep } from "../custom-model-catalog-DQKIvNnb.mjs";
2
+ import { Gt as modelBindingKey, Hn as hydrateSchema, It as loadContributionCapability, Kn as nodePin, L as PoolMemoryWatchdog, Mn as errMsg$1, Pn as BaseAddon, Pt as linkedLabelStepId, Q as applyModelBoundSettings, Qt as pipelineExecutorCapability, Rn as createEvent, St as evaluateZoneRules, Y as YAMNET_TO_MACRO, Yn as sleep, Yt as pickClusterStepSettings, Zn as array, an as resolveClusterStepModelId, bn as supportedRuntimes$1, cr as EventCategory, ct as collectModelBoundKeys, d as CLUSTER_MODEL_SCOPED_STEPS, g as DEFAULT_CLUSTER_STEP_SETTINGS, hn as stepModelRunsOnFormat, jt as hfModelUrl, k as LABEL_SUPPLY_MACRO, lt as containingParentIndex, mn as runtimeDevices$1, n as APPLE_SA_TO_MACRO, or as string, pn as rootSuppliesOf, pt as defaultDeviceFor$1, qt as overlayClusterStepSettings, rr as object, sr as union, un as resolvePoolMemoryPolicy, vt as detectionPipelineCapability, xt as enumerateInferenceDevices } from "../dist-DBp0sJSg.mjs";
3
+ import { s as readProcessCost } from "../node-IWKQZ5Xj.mjs";
4
+ import { C as resolveModelDefaultConfidence, S as landmarkPrecisionVerdict, _ as ALL_STEPS, b as getStepDefinition, f as localFrameRegistry, g as ALL_PIPELINE_STEPS, l as resolveDefaultDetectionModel, n as mergeCustomModels, o as deviceKeyOf, r as buildSubtreeCanRun, s as resolveDeviceEngine, t as CustomModelCatalog, u as macroGateVerdict, v as getDefaultModelForFormat, x as resolveModelForFormat, y as getStep } from "../custom-model-catalog-DctVXbQ1.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BzQ7asa_.mjs";
6
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-CDfbnBGD.mjs";
7
7
  import * as os$1 from "node:os";
8
8
  import * as fs from "node:fs";
9
9
  import * as path$1 from "node:path";
@@ -1,5 +1,5 @@
1
1
  let node_crypto = require("node:crypto");
2
- //#region ../types/dist/event-category-DaIZi00R.mjs
2
+ //#region ../types/dist/event-category-C4hVnRo8.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -218,7 +218,17 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
218
218
  EventCategory["RecordingStopped"] = "recording.stopped";
219
219
  EventCategory["RecordingError"] = "recording.error";
220
220
  EventCategory["RecordingHealthDegraded"] = "recording.health.degraded";
221
+ /** Recording enabled but no segment finalized for the NC stall window. */
222
+ EventCategory["RecordingHealthStalled"] = "recording.health.stalled";
223
+ /** Recovery from {@link RecordingHealthStalled}. */
224
+ EventCategory["RecordingHealthOk"] = "recording.health.ok";
221
225
  EventCategory["RecordingStorageCritical"] = "recording.storage.critical";
226
+ /** Free space on a storage location crossed the warn bar. */
227
+ EventCategory["StorageLocationLow"] = "storage.location.low";
228
+ /** Free space at/under the critical bar, or capacity probe failed (`null`). */
229
+ EventCategory["StorageLocationCritical"] = "storage.location.critical";
230
+ /** Recovery from low/critical on a storage location. */
231
+ EventCategory["StorageLocationOk"] = "storage.location.ok";
222
232
  EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
223
233
  EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
224
234
  EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
@@ -5377,7 +5387,7 @@ var ZodIssueCode = {
5377
5387
  var ZodFirstPartyTypeKind;
5378
5388
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5379
5389
  //#endregion
5380
- //#region ../types/dist/sleep-DwAQ9sqX.mjs
5390
+ //#region ../types/dist/sleep-Tkp9dHXv.mjs
5381
5391
  /**
5382
5392
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5383
5393
  * window to float samples (D455).
@@ -16066,7 +16076,14 @@ var BrokerProviderInfoSchema = object({
16066
16076
  /** Broker kinds this provider can create, with a display label. */
16067
16077
  kinds: array(object({
16068
16078
  kind: string(),
16069
- label: string()
16079
+ label: string(),
16080
+ /**
16081
+ * Relative hub path to start an interactive account link (OAuth popup).
16082
+ * May include `{{brokerId}}`; admin-ui substitutes and appends `?popup=1`.
16083
+ */
16084
+ interactiveConnectPath: string().min(1).optional(),
16085
+ /** Relative hub path to disconnect the linked account (same popup pattern). */
16086
+ interactiveDisconnectPath: string().min(1).optional()
16070
16087
  }))
16071
16088
  });
16072
16089
  var ListInputSchema = object({
@@ -23439,6 +23456,12 @@ var NcSystemEventKindSchema = _enum([
23439
23456
  "node-updating",
23440
23457
  "node-inference-unavailable",
23441
23458
  "detection-blind",
23459
+ "recording-stalled",
23460
+ "recording-healthy",
23461
+ "recording-degraded",
23462
+ "storage-location-low",
23463
+ "storage-location-critical",
23464
+ "storage-location-ok",
23442
23465
  "addon-crash-loop",
23443
23466
  "addon-update-available",
23444
23467
  "server-update-available",
@@ -56647,6 +56670,9 @@ new Map(Object.entries({
56647
56670
  "stream-online": "device-events",
56648
56671
  "stream-offline": "device-events",
56649
56672
  "detection-blind": "device-events",
56673
+ "recording-stalled": "device-events",
56674
+ "recording-healthy": "device-events",
56675
+ "recording-degraded": "device-events",
56650
56676
  "node-online": "system",
56651
56677
  "node-offline": "system",
56652
56678
  "node-restarting": "system",
@@ -56660,6 +56686,9 @@ new Map(Object.entries({
56660
56686
  "wrapper-update-available": "system",
56661
56687
  "backup-completed": "system",
56662
56688
  "export-completed": "system",
56689
+ "storage-location-low": "system",
56690
+ "storage-location-critical": "system",
56691
+ "storage-location-ok": "system",
56663
56692
  "alarm-triggered": "alarm",
56664
56693
  "alarm-armed": "alarm",
56665
56694
  "alarm-disarmed": "alarm",
@@ -56721,6 +56750,16 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
56721
56750
  label: "Detecting nothing",
56722
56751
  kinds: ["detection-blind"]
56723
56752
  },
56753
+ {
56754
+ id: "recording",
56755
+ family: "device-events",
56756
+ label: "Recording",
56757
+ kinds: [
56758
+ "recording-stalled",
56759
+ "recording-healthy",
56760
+ "recording-degraded"
56761
+ ]
56762
+ },
56724
56763
  {
56725
56764
  id: "nodes",
56726
56765
  family: "system",
@@ -56761,6 +56800,16 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
56761
56800
  label: "Backups & exports",
56762
56801
  kinds: ["backup-completed", "export-completed"]
56763
56802
  },
56803
+ {
56804
+ id: "storage",
56805
+ family: "system",
56806
+ label: "Storage locations",
56807
+ kinds: [
56808
+ "storage-location-low",
56809
+ "storage-location-critical",
56810
+ "storage-location-ok"
56811
+ ]
56812
+ },
56764
56813
  {
56765
56814
  id: "alarm",
56766
56815
  family: "alarm",
@@ -56843,6 +56892,9 @@ var DEVICE_EVENTS = [
56843
56892
  "stream-online",
56844
56893
  "stream-offline",
56845
56894
  "detection-blind",
56895
+ "recording-stalled",
56896
+ "recording-healthy",
56897
+ "recording-degraded",
56846
56898
  ...ALARM
56847
56899
  ];
56848
56900
  /** Every kind a summary may speak about — the two summarisable families. */
@@ -1,5 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
- //#region ../types/dist/event-category-DaIZi00R.mjs
2
+ //#region ../types/dist/event-category-C4hVnRo8.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -218,7 +218,17 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
218
218
  EventCategory["RecordingStopped"] = "recording.stopped";
219
219
  EventCategory["RecordingError"] = "recording.error";
220
220
  EventCategory["RecordingHealthDegraded"] = "recording.health.degraded";
221
+ /** Recording enabled but no segment finalized for the NC stall window. */
222
+ EventCategory["RecordingHealthStalled"] = "recording.health.stalled";
223
+ /** Recovery from {@link RecordingHealthStalled}. */
224
+ EventCategory["RecordingHealthOk"] = "recording.health.ok";
221
225
  EventCategory["RecordingStorageCritical"] = "recording.storage.critical";
226
+ /** Free space on a storage location crossed the warn bar. */
227
+ EventCategory["StorageLocationLow"] = "storage.location.low";
228
+ /** Free space at/under the critical bar, or capacity probe failed (`null`). */
229
+ EventCategory["StorageLocationCritical"] = "storage.location.critical";
230
+ /** Recovery from low/critical on a storage location. */
231
+ EventCategory["StorageLocationOk"] = "storage.location.ok";
222
232
  EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
223
233
  EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
224
234
  EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
@@ -5377,7 +5387,7 @@ var ZodIssueCode = {
5377
5387
  var ZodFirstPartyTypeKind;
5378
5388
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5379
5389
  //#endregion
5380
- //#region ../types/dist/sleep-DwAQ9sqX.mjs
5390
+ //#region ../types/dist/sleep-Tkp9dHXv.mjs
5381
5391
  /**
5382
5392
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5383
5393
  * window to float samples (D455).
@@ -16066,7 +16076,14 @@ var BrokerProviderInfoSchema = object({
16066
16076
  /** Broker kinds this provider can create, with a display label. */
16067
16077
  kinds: array(object({
16068
16078
  kind: string(),
16069
- label: string()
16079
+ label: string(),
16080
+ /**
16081
+ * Relative hub path to start an interactive account link (OAuth popup).
16082
+ * May include `{{brokerId}}`; admin-ui substitutes and appends `?popup=1`.
16083
+ */
16084
+ interactiveConnectPath: string().min(1).optional(),
16085
+ /** Relative hub path to disconnect the linked account (same popup pattern). */
16086
+ interactiveDisconnectPath: string().min(1).optional()
16070
16087
  }))
16071
16088
  });
16072
16089
  var ListInputSchema = object({
@@ -23439,6 +23456,12 @@ var NcSystemEventKindSchema = _enum([
23439
23456
  "node-updating",
23440
23457
  "node-inference-unavailable",
23441
23458
  "detection-blind",
23459
+ "recording-stalled",
23460
+ "recording-healthy",
23461
+ "recording-degraded",
23462
+ "storage-location-low",
23463
+ "storage-location-critical",
23464
+ "storage-location-ok",
23442
23465
  "addon-crash-loop",
23443
23466
  "addon-update-available",
23444
23467
  "server-update-available",
@@ -56647,6 +56670,9 @@ new Map(Object.entries({
56647
56670
  "stream-online": "device-events",
56648
56671
  "stream-offline": "device-events",
56649
56672
  "detection-blind": "device-events",
56673
+ "recording-stalled": "device-events",
56674
+ "recording-healthy": "device-events",
56675
+ "recording-degraded": "device-events",
56650
56676
  "node-online": "system",
56651
56677
  "node-offline": "system",
56652
56678
  "node-restarting": "system",
@@ -56660,6 +56686,9 @@ new Map(Object.entries({
56660
56686
  "wrapper-update-available": "system",
56661
56687
  "backup-completed": "system",
56662
56688
  "export-completed": "system",
56689
+ "storage-location-low": "system",
56690
+ "storage-location-critical": "system",
56691
+ "storage-location-ok": "system",
56663
56692
  "alarm-triggered": "alarm",
56664
56693
  "alarm-armed": "alarm",
56665
56694
  "alarm-disarmed": "alarm",
@@ -56721,6 +56750,16 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
56721
56750
  label: "Detecting nothing",
56722
56751
  kinds: ["detection-blind"]
56723
56752
  },
56753
+ {
56754
+ id: "recording",
56755
+ family: "device-events",
56756
+ label: "Recording",
56757
+ kinds: [
56758
+ "recording-stalled",
56759
+ "recording-healthy",
56760
+ "recording-degraded"
56761
+ ]
56762
+ },
56724
56763
  {
56725
56764
  id: "nodes",
56726
56765
  family: "system",
@@ -56761,6 +56800,16 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
56761
56800
  label: "Backups & exports",
56762
56801
  kinds: ["backup-completed", "export-completed"]
56763
56802
  },
56803
+ {
56804
+ id: "storage",
56805
+ family: "system",
56806
+ label: "Storage locations",
56807
+ kinds: [
56808
+ "storage-location-low",
56809
+ "storage-location-critical",
56810
+ "storage-location-ok"
56811
+ ]
56812
+ },
56764
56813
  {
56765
56814
  id: "alarm",
56766
56815
  family: "alarm",
@@ -56843,6 +56892,9 @@ var DEVICE_EVENTS = [
56843
56892
  "stream-online",
56844
56893
  "stream-offline",
56845
56894
  "detection-blind",
56895
+ "recording-stalled",
56896
+ "recording-healthy",
56897
+ "recording-degraded",
56846
56898
  ...ALARM
56847
56899
  ];
56848
56900
  /** Every kind a summary may speak about — the two summarisable families. */
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-DIvGLRdM.js");
1
+ const require_dist = require("./dist-Bdrk1nVH.js");
2
2
  //#region src/detection-pipeline/registry/model-licenses.ts
3
3
  var COCO_DATA = {
4
4
  name: "COCO 2017",
@@ -1,4 +1,4 @@
1
- import { jt as hfModelUrl } from "./dist-BghVPOQJ.mjs";
1
+ import { jt as hfModelUrl } from "./dist-DBp0sJSg.mjs";
2
2
  //#region src/detection-pipeline/registry/model-licenses.ts
3
3
  var COCO_DATA = {
4
4
  name: "COCO 2017",
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-DIvGLRdM.js");
5
+ const require_dist = require("../dist-Bdrk1nVH.js");
6
6
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
7
7
  let node_fs = require("node:fs");
8
8
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { Hn as hydrateSchema, Kt as motionDetectionCapability, Pn as BaseAddon, St as evaluateZoneRules, jn as DeviceType } from "../dist-BghVPOQJ.mjs";
1
+ import { Hn as hydrateSchema, Kt as motionDetectionCapability, Pn as BaseAddon, St as evaluateZoneRules, jn as DeviceType } from "../dist-DBp0sJSg.mjs";
2
2
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-DIvGLRdM.js");
2
+ const require_dist = require("./dist-Bdrk1nVH.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  let node_fs = require("node:fs");
5
5
  node_fs = require_chunk.__toESM(node_fs, 1);
@@ -1,4 +1,4 @@
1
- import { En as buildFfmpegArgs, Mn as errMsg, Tn as Fmp4BoxSplitter, kn as isSoftwareDecode } from "./dist-BghVPOQJ.mjs";
1
+ import { En as buildFfmpegArgs, Mn as errMsg, Tn as Fmp4BoxSplitter, kn as isSoftwareDecode } from "./dist-DBp0sJSg.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { realpathSync } from "node:fs";
4
4
  import path from "node:path";
@@ -3,9 +3,9 @@ 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-DIvGLRdM.js");
7
- const require_node = require("../node-KGZFTDup.js");
8
- const require_custom_model_catalog = require("../custom-model-catalog-DmgH7i0_.js");
6
+ const require_dist = require("../dist-Bdrk1nVH.js");
7
+ const require_node = require("../node-CRx-Wwok.js");
8
+ const require_custom_model_catalog = require("../custom-model-catalog-BplFsaKz.js");
9
9
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
10
10
  const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
11
11
  const require_restream_intent = require("../restream-intent-7uDNqMKs.js");
@@ -1,6 +1,6 @@
1
- import { $t as pipelineRunnerCapability, Bn as defineCustomActions, E as FailureCounters, Et as failureContributionCapability, Ft as linkedStepOf, I as PIPELINE_RAMP, It as loadContributionCapability, Kn as nodePin, M as NativeLeaseAdmissionSchema, Mn as errMsg, N as NativeLeaseSettingsSchema, P as NodeBenchRunnerInputSchema, Pn as BaseAddon, Qn as boolean, Rn as createEvent, U as ROOT_SUPPLIABLE_STEP_IDS, Xn as _enum, Xt as pickDetailCropConvention, Z as allowedSuppliedEffect, Zn as array, Zt as pickNativeLeaseOverride, _ as DEFAULT_DETAIL_CROP_CONVENTION, _t as deriveRootFaceRefineRect, a as BackgroundRunRegistry, cr as EventCategory, er as lazy, fn as resolveRootSupply, ht as deriveDetailCropRect, it as cameraOwnsMotionViaSensor, j as MODEL_FORMATS, ln as resolveModelBoundSetting, m as CROP_SUPPLY_SOURCES, nr as number, or as string, pn as rootSuppliesOf, rr as object, rt as buildBenchStepTree, tr as literal, x as DEVICE_RAMP, y as DEFAULT_NATIVE_LEASE_SETTINGS, zn as customAction } from "../dist-BghVPOQJ.mjs";
2
- import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-BEnsSyvU.mjs";
3
- import { a as stepsForElectedPool, b as getStepDefinition, d as rootObjectGate, f as localFrameRegistry, h as resolveFrameViewGeometry, i as placeDetailStep, l as resolveDefaultDetectionModel, m as createSessionDecodeCoordinator, p as isSessionDecodeReadGone, s as resolveDeviceEngine, t as CustomModelCatalog, u as macroGateVerdict, y as getStep } from "../custom-model-catalog-DQKIvNnb.mjs";
1
+ import { $t as pipelineRunnerCapability, Bn as defineCustomActions, E as FailureCounters, Et as failureContributionCapability, Ft as linkedStepOf, I as PIPELINE_RAMP, It as loadContributionCapability, Kn as nodePin, M as NativeLeaseAdmissionSchema, Mn as errMsg, N as NativeLeaseSettingsSchema, P as NodeBenchRunnerInputSchema, Pn as BaseAddon, Qn as boolean, Rn as createEvent, U as ROOT_SUPPLIABLE_STEP_IDS, Xn as _enum, Xt as pickDetailCropConvention, Z as allowedSuppliedEffect, Zn as array, Zt as pickNativeLeaseOverride, _ as DEFAULT_DETAIL_CROP_CONVENTION, _t as deriveRootFaceRefineRect, a as BackgroundRunRegistry, cr as EventCategory, er as lazy, fn as resolveRootSupply, ht as deriveDetailCropRect, it as cameraOwnsMotionViaSensor, j as MODEL_FORMATS, ln as resolveModelBoundSetting, m as CROP_SUPPLY_SOURCES, nr as number, or as string, pn as rootSuppliesOf, rr as object, rt as buildBenchStepTree, tr as literal, x as DEVICE_RAMP, y as DEFAULT_NATIVE_LEASE_SETTINGS, zn as customAction } from "../dist-DBp0sJSg.mjs";
2
+ import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-IWKQZ5Xj.mjs";
3
+ import { a as stepsForElectedPool, b as getStepDefinition, d as rootObjectGate, f as localFrameRegistry, h as resolveFrameViewGeometry, i as placeDetailStep, l as resolveDefaultDetectionModel, m as createSessionDecodeCoordinator, p as isSessionDecodeReadGone, s as resolveDeviceEngine, t as CustomModelCatalog, u as macroGateVerdict, y as getStep } from "../custom-model-catalog-DctVXbQ1.mjs";
4
4
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
6
  import { c as withDetectionIntent, o as preRollRequestOf, t as DETECTION_PRE_ROLL_REQUEST_MS } from "../restream-intent-DyGmLAU9.mjs";
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-DIvGLRdM.js");
2
+ const require_dist = require("./dist-Bdrk1nVH.js");
3
3
  let node_fs = require("node:fs");
4
4
  node_fs = require_chunk.__toESM(node_fs);
5
5
  let node_child_process = require("node:child_process");
@@ -1,4 +1,4 @@
1
- import { Jt as parseProcStatus } from "./dist-BghVPOQJ.mjs";
1
+ import { Jt as parseProcStatus } from "./dist-DBp0sJSg.mjs";
2
2
  import * as fs from "node:fs";
3
3
  import { execFile } from "node:child_process";
4
4
  //#region src/shared/node-topology-platform.ts
@@ -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-DIvGLRdM.js");
7
- const require_node = require("../node-KGZFTDup.js");
6
+ const require_dist = require("../dist-Bdrk1nVH.js");
7
+ const require_node = require("../node-CRx-Wwok.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
  const require_retire_root_keys = require("../retire-root-keys-Csb8z2f3.js");
@@ -16328,6 +16328,94 @@ var SpawnPressureGovernor = class {
16328
16328
  return this.deps.now?.() ?? Date.now();
16329
16329
  }
16330
16330
  };
16331
+ var DEFAULT_RECORDING_STALL_CONFIG = {
16332
+ thresholdMs: 5 * 6e4,
16333
+ degradedCooldownMs: 30 * 6e4
16334
+ };
16335
+ var RecordingStallMonitor = class {
16336
+ config;
16337
+ state = /* @__PURE__ */ new Map();
16338
+ constructor(config = DEFAULT_RECORDING_STALL_CONFIG) {
16339
+ this.config = config;
16340
+ }
16341
+ /**
16342
+ * Declare whether this camera is expected to produce segments. When
16343
+ * `expected` becomes false, any open stall episode is cleared without a
16344
+ * healthy event (switched-off must not look like recovery).
16345
+ */
16346
+ setExpected(deviceId, expected, now) {
16347
+ const prev = this.state.get(deviceId);
16348
+ if (!expected) {
16349
+ this.state.set(deviceId, {
16350
+ expected: false,
16351
+ lastSegmentAt: prev?.lastSegmentAt ?? null,
16352
+ stalledReported: false,
16353
+ lastDegradedAt: prev?.lastDegradedAt ?? null
16354
+ });
16355
+ return;
16356
+ }
16357
+ this.state.set(deviceId, {
16358
+ expected: true,
16359
+ lastSegmentAt: prev?.lastSegmentAt ?? now,
16360
+ stalledReported: prev?.stalledReported ?? false,
16361
+ lastDegradedAt: prev?.lastDegradedAt ?? null
16362
+ });
16363
+ }
16364
+ /** A segment finalized for this camera (any profile). */
16365
+ noteSegment(deviceId, now) {
16366
+ const prev = this.state.get(deviceId);
16367
+ const wasStalled = prev?.stalledReported === true;
16368
+ this.state.set(deviceId, {
16369
+ expected: prev?.expected ?? false,
16370
+ lastSegmentAt: now,
16371
+ stalledReported: false,
16372
+ lastDegradedAt: prev?.lastDegradedAt ?? null
16373
+ });
16374
+ if (wasStalled && (prev?.expected ?? false)) return { deviceId };
16375
+ return null;
16376
+ }
16377
+ /**
16378
+ * Devices that have JUST crossed into stalled. Call from a periodic sweep.
16379
+ */
16380
+ sweep(now) {
16381
+ const out = [];
16382
+ for (const [deviceId, s] of this.state) {
16383
+ if (!s.expected || s.stalledReported) continue;
16384
+ if (s.lastSegmentAt === null) continue;
16385
+ const idleMs = now - s.lastSegmentAt;
16386
+ if (idleMs < this.config.thresholdMs) continue;
16387
+ this.state.set(deviceId, {
16388
+ ...s,
16389
+ stalledReported: true
16390
+ });
16391
+ out.push({
16392
+ deviceId,
16393
+ idleMs,
16394
+ thresholdMs: this.config.thresholdMs
16395
+ });
16396
+ }
16397
+ return out;
16398
+ }
16399
+ /**
16400
+ * Writer restart budget exhausted. Cooldown per camera so a storm is one
16401
+ * notification, not one per give-up.
16402
+ */
16403
+ noteDegraded(deviceId, message, now) {
16404
+ const prev = this.state.get(deviceId);
16405
+ const last = prev?.lastDegradedAt ?? null;
16406
+ if (last !== null && now - last < this.config.degradedCooldownMs) return null;
16407
+ this.state.set(deviceId, {
16408
+ expected: prev?.expected ?? false,
16409
+ lastSegmentAt: prev?.lastSegmentAt ?? null,
16410
+ stalledReported: prev?.stalledReported ?? false,
16411
+ lastDegradedAt: now
16412
+ });
16413
+ return {
16414
+ deviceId,
16415
+ message
16416
+ };
16417
+ }
16418
+ };
16331
16419
  //#endregion
16332
16420
  //#region src/recorder/addon/recording-controller.ts
16333
16421
  /**
@@ -16688,6 +16776,7 @@ var RecordingController = class {
16688
16776
  * for good reason. Every bounded-parallel attach in this file reads it.
16689
16777
  */
16690
16778
  spawnPressure;
16779
+ stallMonitor = new RecordingStallMonitor();
16691
16780
  constructor(deps) {
16692
16781
  this.deps = deps;
16693
16782
  this.spawnPressure = new SpawnPressureGovernor({
@@ -17266,6 +17355,20 @@ var RecordingController = class {
17266
17355
  segmentSeconds: this.active.get(s.deviceId)?.find((r) => r.profile === s.profile)?.segmentSeconds
17267
17356
  }
17268
17357
  });
17358
+ for (const edge of this.stallMonitor.sweep(now)) {
17359
+ this.deps.logger.warn("recorder: recording stalled for Notification Center", {
17360
+ tags: { deviceId: edge.deviceId },
17361
+ meta: {
17362
+ idleMs: edge.idleMs,
17363
+ thresholdMs: edge.thresholdMs
17364
+ }
17365
+ });
17366
+ this.deps.emitRecordingHealth?.(require_dist.EventCategory.RecordingHealthStalled, {
17367
+ deviceId: edge.deviceId,
17368
+ idleMs: edge.idleMs,
17369
+ thresholdMs: edge.thresholdMs
17370
+ });
17371
+ }
17269
17372
  const byDevice = /* @__PURE__ */ new Map();
17270
17373
  for (const s of stalled) {
17271
17374
  const list = byDevice.get(s.deviceId);
@@ -17415,6 +17518,7 @@ var RecordingController = class {
17415
17518
  const config = await this.deps.loadConfig(deviceId);
17416
17519
  if (this.stopped || this.paused) return;
17417
17520
  const wantRecording = shouldRecordAt(config, this.triggersFor(deviceId), new Date(this.now()));
17521
+ this.stallMonitor.setExpected(deviceId, wantRecording, this.now());
17418
17522
  this.scheduleNextDecision(deviceId, config);
17419
17523
  if (!wantRecording) {
17420
17524
  this.reportUnrecordable(deviceId, config);
@@ -17889,6 +17993,20 @@ var RecordingController = class {
17889
17993
  pid
17890
17994
  }) ?? require_node.NO_COST_CLAIM,
17891
17995
  onGaveUp: () => {
17996
+ const degraded = this.stallMonitor.noteDegraded(deviceId, `writer gave up on profile ${profile}`, this.now());
17997
+ if (degraded !== null) {
17998
+ this.deps.logger.warn("recorder: recording degraded (restart budget exhausted)", {
17999
+ tags: { deviceId },
18000
+ meta: {
18001
+ profile,
18002
+ message: degraded.message
18003
+ }
18004
+ });
18005
+ this.deps.emitRecordingHealth?.(require_dist.EventCategory.RecordingHealthDegraded, {
18006
+ deviceId,
18007
+ message: degraded.message
18008
+ });
18009
+ }
17892
18010
  this.recoverWriterGaveUp(deviceId, profile);
17893
18011
  },
17894
18012
  onResourcePressure: () => this.spawnPressure.report(deviceId)
@@ -17930,7 +18048,10 @@ var RecordingController = class {
17930
18048
  },
17931
18049
  intervalMs: this.deps.watchIntervalMs > 0 ? this.deps.watchIntervalMs : DEFAULT_WATCH_INTERVAL_MS,
17932
18050
  onFinalized: async (startMs, durMs, flatAbsPath) => {
17933
- this.lastSegmentAt.set(idleKey(deviceId, profile), this.now());
18051
+ const segmentAt = this.now();
18052
+ this.lastSegmentAt.set(idleKey(deviceId, profile), segmentAt);
18053
+ const recovered = this.stallMonitor.noteSegment(deviceId, segmentAt);
18054
+ if (recovered !== null) this.deps.emitRecordingHealth?.(require_dist.EventCategory.RecordingHealthOk, { deviceId: recovered.deviceId });
17934
18055
  if (startMs >= writerStartedMs - 1e3 && !firstSegmentSeen) {
17935
18056
  firstSegmentSeen = true;
17936
18057
  this.deps.logger.info("recorder: first segment of this attach", {
@@ -21714,6 +21835,9 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
21714
21835
  count: missed.count
21715
21836
  });
21716
21837
  },
21838
+ emitRecordingHealth: (category, data) => {
21839
+ this.emitExportEvent(category, data);
21840
+ },
21717
21841
  spawn: node_child_process.spawn,
21718
21842
  costRegistry: this.costRegistry,
21719
21843
  segmentSeconds: this.config.segmentSeconds,
@@ -1,5 +1,5 @@
1
- import { An as DeviceFeature, B as RECORDING_EXPORT_MAX_READ_BYTES, Bn as defineCustomActions, Bt as mayReadLocation, C as EVENT_PAD_MS, Ct as evictionPolicyForMode, Dn as evaluateSensorEdge, F as OpsLogEntrySchema, G as RecordingSignalStatusSchema, H as RECORDING_SOURCE_CAMSTACK_ADDON, Hn as hydrateSchema, Ht as memoizePinnedFfmpeg, It as loadContributionCapability, J as VISIT_MERGE_GAP_MS, Jn as selectAssignedProfileSlots, Kn as nodePin, Mn as errMsg$1, Nt as isFirstLevelMacroClass, Ot as gbToBytes, Pn as BaseAddon, Qn as boolean, S as EVENT_OWNER_TYPES, T as ExportRecordSchema, Tt as exportSubjectOf, Ut as migrateLegacyDeviceSignalConfig, V as RECORDING_SOURCE_CAMSTACK, Vt as mayWriteToLocation, W as RecordingConfigSchema, Wt as modeMayWrite, Xn as _enum, Yn as sleep$1, Zn as array, _n as storageOccupancyCapability, ar as record, cn as resolveLocationMode, cr as EventCategory, dn as resolveRecordingProfiles, gn as storageEvictableCapability, gt as deriveRecordingMode, in as recordingSignalCapability, ir as preprocess, jn as DeviceType, mt as deriveBatteryPresence, nn as recordingCapability, nr as number, nt as batteryCapability, o as BatteryStatusSchema, on as resolveCreateExportSubject, or as string, ot as clipExportFailure, q as VIDEOCLIPS_MAX_OFFER_BYTES, rn as recordingExportCapability, rr as object, s as CLIP_BROKER_PACED_RATES, st as clipExportFailureOf, tn as recordingArchiveCapability, v as DEFAULT_EVENTS_BAND_BUFFER_SEC, wt as evictionPolicyOfLocation, xn as videoclipsCapability, yn as stripRetiredBandPreBufferSec, zn as customAction } from "../dist-BghVPOQJ.mjs";
2
- import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-BEnsSyvU.mjs";
1
+ import { An as DeviceFeature, B as RECORDING_EXPORT_MAX_READ_BYTES, Bn as defineCustomActions, Bt as mayReadLocation, C as EVENT_PAD_MS, Ct as evictionPolicyForMode, Dn as evaluateSensorEdge, F as OpsLogEntrySchema, G as RecordingSignalStatusSchema, H as RECORDING_SOURCE_CAMSTACK_ADDON, Hn as hydrateSchema, Ht as memoizePinnedFfmpeg, It as loadContributionCapability, J as VISIT_MERGE_GAP_MS, Jn as selectAssignedProfileSlots, Kn as nodePin, Mn as errMsg$1, Nt as isFirstLevelMacroClass, Ot as gbToBytes, Pn as BaseAddon, Qn as boolean, S as EVENT_OWNER_TYPES, T as ExportRecordSchema, Tt as exportSubjectOf, Ut as migrateLegacyDeviceSignalConfig, V as RECORDING_SOURCE_CAMSTACK, Vt as mayWriteToLocation, W as RecordingConfigSchema, Wt as modeMayWrite, Xn as _enum, Yn as sleep$1, Zn as array, _n as storageOccupancyCapability, ar as record, cn as resolveLocationMode, cr as EventCategory, dn as resolveRecordingProfiles, gn as storageEvictableCapability, gt as deriveRecordingMode, in as recordingSignalCapability, ir as preprocess, jn as DeviceType, mt as deriveBatteryPresence, nn as recordingCapability, nr as number, nt as batteryCapability, o as BatteryStatusSchema, on as resolveCreateExportSubject, or as string, ot as clipExportFailure, q as VIDEOCLIPS_MAX_OFFER_BYTES, rn as recordingExportCapability, rr as object, s as CLIP_BROKER_PACED_RATES, st as clipExportFailureOf, tn as recordingArchiveCapability, v as DEFAULT_EVENTS_BAND_BUFFER_SEC, wt as evictionPolicyOfLocation, xn as videoclipsCapability, yn as stripRetiredBandPreBufferSec, zn as customAction } from "../dist-DBp0sJSg.mjs";
2
+ import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-IWKQZ5Xj.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 { n as RowMapStore, t as retireRootKeys } from "../retire-root-keys-DZvlso2l.mjs";
@@ -16320,6 +16320,94 @@ var SpawnPressureGovernor = class {
16320
16320
  return this.deps.now?.() ?? Date.now();
16321
16321
  }
16322
16322
  };
16323
+ var DEFAULT_RECORDING_STALL_CONFIG = {
16324
+ thresholdMs: 5 * 6e4,
16325
+ degradedCooldownMs: 30 * 6e4
16326
+ };
16327
+ var RecordingStallMonitor = class {
16328
+ config;
16329
+ state = /* @__PURE__ */ new Map();
16330
+ constructor(config = DEFAULT_RECORDING_STALL_CONFIG) {
16331
+ this.config = config;
16332
+ }
16333
+ /**
16334
+ * Declare whether this camera is expected to produce segments. When
16335
+ * `expected` becomes false, any open stall episode is cleared without a
16336
+ * healthy event (switched-off must not look like recovery).
16337
+ */
16338
+ setExpected(deviceId, expected, now) {
16339
+ const prev = this.state.get(deviceId);
16340
+ if (!expected) {
16341
+ this.state.set(deviceId, {
16342
+ expected: false,
16343
+ lastSegmentAt: prev?.lastSegmentAt ?? null,
16344
+ stalledReported: false,
16345
+ lastDegradedAt: prev?.lastDegradedAt ?? null
16346
+ });
16347
+ return;
16348
+ }
16349
+ this.state.set(deviceId, {
16350
+ expected: true,
16351
+ lastSegmentAt: prev?.lastSegmentAt ?? now,
16352
+ stalledReported: prev?.stalledReported ?? false,
16353
+ lastDegradedAt: prev?.lastDegradedAt ?? null
16354
+ });
16355
+ }
16356
+ /** A segment finalized for this camera (any profile). */
16357
+ noteSegment(deviceId, now) {
16358
+ const prev = this.state.get(deviceId);
16359
+ const wasStalled = prev?.stalledReported === true;
16360
+ this.state.set(deviceId, {
16361
+ expected: prev?.expected ?? false,
16362
+ lastSegmentAt: now,
16363
+ stalledReported: false,
16364
+ lastDegradedAt: prev?.lastDegradedAt ?? null
16365
+ });
16366
+ if (wasStalled && (prev?.expected ?? false)) return { deviceId };
16367
+ return null;
16368
+ }
16369
+ /**
16370
+ * Devices that have JUST crossed into stalled. Call from a periodic sweep.
16371
+ */
16372
+ sweep(now) {
16373
+ const out = [];
16374
+ for (const [deviceId, s] of this.state) {
16375
+ if (!s.expected || s.stalledReported) continue;
16376
+ if (s.lastSegmentAt === null) continue;
16377
+ const idleMs = now - s.lastSegmentAt;
16378
+ if (idleMs < this.config.thresholdMs) continue;
16379
+ this.state.set(deviceId, {
16380
+ ...s,
16381
+ stalledReported: true
16382
+ });
16383
+ out.push({
16384
+ deviceId,
16385
+ idleMs,
16386
+ thresholdMs: this.config.thresholdMs
16387
+ });
16388
+ }
16389
+ return out;
16390
+ }
16391
+ /**
16392
+ * Writer restart budget exhausted. Cooldown per camera so a storm is one
16393
+ * notification, not one per give-up.
16394
+ */
16395
+ noteDegraded(deviceId, message, now) {
16396
+ const prev = this.state.get(deviceId);
16397
+ const last = prev?.lastDegradedAt ?? null;
16398
+ if (last !== null && now - last < this.config.degradedCooldownMs) return null;
16399
+ this.state.set(deviceId, {
16400
+ expected: prev?.expected ?? false,
16401
+ lastSegmentAt: prev?.lastSegmentAt ?? null,
16402
+ stalledReported: prev?.stalledReported ?? false,
16403
+ lastDegradedAt: now
16404
+ });
16405
+ return {
16406
+ deviceId,
16407
+ message
16408
+ };
16409
+ }
16410
+ };
16323
16411
  //#endregion
16324
16412
  //#region src/recorder/addon/recording-controller.ts
16325
16413
  /**
@@ -16680,6 +16768,7 @@ var RecordingController = class {
16680
16768
  * for good reason. Every bounded-parallel attach in this file reads it.
16681
16769
  */
16682
16770
  spawnPressure;
16771
+ stallMonitor = new RecordingStallMonitor();
16683
16772
  constructor(deps) {
16684
16773
  this.deps = deps;
16685
16774
  this.spawnPressure = new SpawnPressureGovernor({
@@ -17258,6 +17347,20 @@ var RecordingController = class {
17258
17347
  segmentSeconds: this.active.get(s.deviceId)?.find((r) => r.profile === s.profile)?.segmentSeconds
17259
17348
  }
17260
17349
  });
17350
+ for (const edge of this.stallMonitor.sweep(now)) {
17351
+ this.deps.logger.warn("recorder: recording stalled for Notification Center", {
17352
+ tags: { deviceId: edge.deviceId },
17353
+ meta: {
17354
+ idleMs: edge.idleMs,
17355
+ thresholdMs: edge.thresholdMs
17356
+ }
17357
+ });
17358
+ this.deps.emitRecordingHealth?.(EventCategory.RecordingHealthStalled, {
17359
+ deviceId: edge.deviceId,
17360
+ idleMs: edge.idleMs,
17361
+ thresholdMs: edge.thresholdMs
17362
+ });
17363
+ }
17261
17364
  const byDevice = /* @__PURE__ */ new Map();
17262
17365
  for (const s of stalled) {
17263
17366
  const list = byDevice.get(s.deviceId);
@@ -17407,6 +17510,7 @@ var RecordingController = class {
17407
17510
  const config = await this.deps.loadConfig(deviceId);
17408
17511
  if (this.stopped || this.paused) return;
17409
17512
  const wantRecording = shouldRecordAt(config, this.triggersFor(deviceId), new Date(this.now()));
17513
+ this.stallMonitor.setExpected(deviceId, wantRecording, this.now());
17410
17514
  this.scheduleNextDecision(deviceId, config);
17411
17515
  if (!wantRecording) {
17412
17516
  this.reportUnrecordable(deviceId, config);
@@ -17881,6 +17985,20 @@ var RecordingController = class {
17881
17985
  pid
17882
17986
  }) ?? NO_COST_CLAIM,
17883
17987
  onGaveUp: () => {
17988
+ const degraded = this.stallMonitor.noteDegraded(deviceId, `writer gave up on profile ${profile}`, this.now());
17989
+ if (degraded !== null) {
17990
+ this.deps.logger.warn("recorder: recording degraded (restart budget exhausted)", {
17991
+ tags: { deviceId },
17992
+ meta: {
17993
+ profile,
17994
+ message: degraded.message
17995
+ }
17996
+ });
17997
+ this.deps.emitRecordingHealth?.(EventCategory.RecordingHealthDegraded, {
17998
+ deviceId,
17999
+ message: degraded.message
18000
+ });
18001
+ }
17884
18002
  this.recoverWriterGaveUp(deviceId, profile);
17885
18003
  },
17886
18004
  onResourcePressure: () => this.spawnPressure.report(deviceId)
@@ -17922,7 +18040,10 @@ var RecordingController = class {
17922
18040
  },
17923
18041
  intervalMs: this.deps.watchIntervalMs > 0 ? this.deps.watchIntervalMs : DEFAULT_WATCH_INTERVAL_MS,
17924
18042
  onFinalized: async (startMs, durMs, flatAbsPath) => {
17925
- this.lastSegmentAt.set(idleKey(deviceId, profile), this.now());
18043
+ const segmentAt = this.now();
18044
+ this.lastSegmentAt.set(idleKey(deviceId, profile), segmentAt);
18045
+ const recovered = this.stallMonitor.noteSegment(deviceId, segmentAt);
18046
+ if (recovered !== null) this.deps.emitRecordingHealth?.(EventCategory.RecordingHealthOk, { deviceId: recovered.deviceId });
17926
18047
  if (startMs >= writerStartedMs - 1e3 && !firstSegmentSeen) {
17927
18048
  firstSegmentSeen = true;
17928
18049
  this.deps.logger.info("recorder: first segment of this attach", {
@@ -21706,6 +21827,9 @@ var RecorderV2Addon = class extends BaseAddon {
21706
21827
  count: missed.count
21707
21828
  });
21708
21829
  },
21830
+ emitRecordingHealth: (category, data) => {
21831
+ this.emitExportEvent(category, data);
21832
+ },
21709
21833
  spawn,
21710
21834
  costRegistry: this.costRegistry,
21711
21835
  segmentSeconds: this.config.segmentSeconds,
@@ -1,5 +1,5 @@
1
1
  import { r as __toESM, t as __commonJSMin } from "./chunk-DnnnRqeS.mjs";
2
- import { Mn as errMsg } from "./dist-BghVPOQJ.mjs";
2
+ import { Mn as errMsg } from "./dist-DBp0sJSg.mjs";
3
3
  import { spawn } from "node:child_process";
4
4
  //#region src/stream-broker/recorded/avcc-annexb.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-emK7D4bc.js");
2
- const require_dist = require("./dist-DIvGLRdM.js");
2
+ const require_dist = require("./dist-Bdrk1nVH.js");
3
3
  let node_child_process = require("node:child_process");
4
4
  //#region src/stream-broker/recorded/avcc-annexb.ts
5
5
  /**
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.350",
21
+ version: "1.2.353",
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.277",
36
+ version: "1.2.281",
37
37
  scope: ["default"],
38
38
  loaded: !1,
39
39
  from: "addon_stream_broker_widgets",
@@ -1,4 +1,4 @@
1
- const require_segment_demux_js = require("../segment-demux-js-CnaecM7W.js");
1
+ const require_segment_demux_js = require("../segment-demux-js-BmpHWno-.js");
2
2
  let node_worker_threads = require("node:worker_threads");
3
3
  //#region src/stream-broker/recorded/demux-worker-child.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { t as demuxSegmentFullJs } from "../segment-demux-js-ChKm1pOF.mjs";
1
+ import { t as demuxSegmentFullJs } from "../segment-demux-js-B1Mx4mJd.mjs";
2
2
  import { parentPort } from "node:worker_threads";
3
3
  //#region src/stream-broker/recorded/demux-worker-child.ts
4
4
  /**
@@ -36,7 +36,7 @@ async function r() {
36
36
  }
37
37
  },
38
38
  "@camstack/types": {
39
- version: "1.2.350",
39
+ version: "1.2.353",
40
40
  scope: "default",
41
41
  shareConfig: {
42
42
  singleton: !0,
@@ -81,7 +81,7 @@ async function r() {
81
81
  }
82
82
  },
83
83
  "@camstack/ui-library": {
84
- version: "1.2.277",
84
+ version: "1.2.281",
85
85
  scope: "default",
86
86
  shareConfig: {
87
87
  singleton: !0,
@@ -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-DIvGLRdM.js");
7
- const require_node = require("../node-KGZFTDup.js");
6
+ const require_dist = require("../dist-Bdrk1nVH.js");
7
+ const require_node = require("../node-CRx-Wwok.js");
8
8
  const require_restream_intent = require("../restream-intent-7uDNqMKs.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-CnaecM7W.js");
11
+ const require_segment_demux_js = require("../segment-demux-js-BmpHWno-.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");
@@ -1,10 +1,10 @@
1
1
  import { r as __toESM } from "../chunk-DnnnRqeS.mjs";
2
- import { $n as discriminatedUnion, An as DeviceFeature, At as gifFromMp4Args, Cn as AUDIO_PRESETS, D as G711_SCALE_CORRECTION_DB, Dt as ffmpegRate, En as buildFfmpegArgs, Fn as CAM_PROFILE_ORDER, Gn as makeSourceBrokerId, Ht as memoizePinnedFfmpeg, In as CamProfileSchema, It as loadContributionCapability, K as RingBuffer, Kn as nodePin, Lt as logChannelsCapability, Mn as errMsg, Nn as BOOT_RECOVERY_BACKOFF_MS, On as invocationFromEncodeProfile, Pn as BaseAddon, Qn as boolean, R as RATE_CONTROL_RELAXED, Rn as createEvent, Sn as webrtcSessionCapability, Un as isEvent, Vn as expandAudioChunkToF32le, Wn as makeProfileBrokerId, X as addonWidgetsSourceCapability, Xn as _enum, Zn as array, ar as record, at as cameraStreamsCapability, bt as egressTransportFromRequest, c as CLIP_STILL_REASON_CODE_HEADER, cr as EventCategory, dt as createLogChannelsProvider, en as rankStreams, ft as declareLogChannel, jn as DeviceType, kn as isSoftwareDecode, kt as gifDeriveSpeed, mt as deriveBatteryPresence, nr as number, nt as batteryCapability, o as BatteryStatusSchema, or as string, qn as parseProfileBrokerId, rr as object, s as CLIP_BROKER_PACED_RATES, sn as resolveEgressDecodeHwAccel, sr as union, st as clipExportFailureOf, tr as literal, ut as createHwAccelCache, vn as streamBrokerCapability, w as EncodeProfileSchema, yt as egressTranscodeSharingKey, z as RATE_CONTROL_TIGHT, zt as maskUrlCredentials } from "../dist-BghVPOQJ.mjs";
3
- import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, o as probeFfmpegBinary, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-BEnsSyvU.mjs";
2
+ import { $n as discriminatedUnion, An as DeviceFeature, At as gifFromMp4Args, Cn as AUDIO_PRESETS, D as G711_SCALE_CORRECTION_DB, Dt as ffmpegRate, En as buildFfmpegArgs, Fn as CAM_PROFILE_ORDER, Gn as makeSourceBrokerId, Ht as memoizePinnedFfmpeg, In as CamProfileSchema, It as loadContributionCapability, K as RingBuffer, Kn as nodePin, Lt as logChannelsCapability, Mn as errMsg, Nn as BOOT_RECOVERY_BACKOFF_MS, On as invocationFromEncodeProfile, Pn as BaseAddon, Qn as boolean, R as RATE_CONTROL_RELAXED, Rn as createEvent, Sn as webrtcSessionCapability, Un as isEvent, Vn as expandAudioChunkToF32le, Wn as makeProfileBrokerId, X as addonWidgetsSourceCapability, Xn as _enum, Zn as array, ar as record, at as cameraStreamsCapability, bt as egressTransportFromRequest, c as CLIP_STILL_REASON_CODE_HEADER, cr as EventCategory, dt as createLogChannelsProvider, en as rankStreams, ft as declareLogChannel, jn as DeviceType, kn as isSoftwareDecode, kt as gifDeriveSpeed, mt as deriveBatteryPresence, nr as number, nt as batteryCapability, o as BatteryStatusSchema, or as string, qn as parseProfileBrokerId, rr as object, s as CLIP_BROKER_PACED_RATES, sn as resolveEgressDecodeHwAccel, sr as union, st as clipExportFailureOf, tr as literal, ut as createHwAccelCache, vn as streamBrokerCapability, w as EncodeProfileSchema, yt as egressTranscodeSharingKey, z as RATE_CONTROL_TIGHT, zt as maskUrlCredentials } from "../dist-DBp0sJSg.mjs";
3
+ import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, o as probeFfmpegBinary, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-IWKQZ5Xj.mjs";
4
4
  import { a as parseRestreamPath, d as PREBUFFER_MAX_MS, f as capPreRollRequestMs, i as isLiveEdgeOnlyDial, m as resolvePrebuffer, n as NO_DECLARATION, p as prebufferRetentionMs, s as sdpVariantFor, u as withSentryIntent } from "../restream-intent-DyGmLAU9.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 { a as require_mp4box_all, c as parseNalLengthSize, i as runFfmpegOnce, n as demuxSegmentPreferJs, o as avccSampleToAnnexB, r as FfmpegFallbackRefusedError, s as buildKeyframeAnnexB, t as demuxSegmentFullJs } from "../segment-demux-js-ChKm1pOF.mjs";
7
+ import { a as require_mp4box_all, c as parseNalLengthSize, i as runFfmpegOnce, n as demuxSegmentPreferJs, o as avccSampleToAnnexB, r as FfmpegFallbackRefusedError, s as buildKeyframeAnnexB, t as demuxSegmentFullJs } from "../segment-demux-js-B1Mx4mJd.mjs";
8
8
  import { createRequire } from "node:module";
9
9
  import * as os$1 from "node:os";
10
10
  import { networkInterfaces, tmpdir } from "node:os";
@@ -30,7 +30,7 @@ async function d(e) {
30
30
  }
31
31
  }
32
32
  async function f() {
33
- return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BTzjBMRP.mjs")).catch((e) => {
33
+ return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Ccq5jxp-.mjs")).catch((e) => {
34
34
  throw l = void 0, e;
35
35
  }), l;
36
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-pipeline",
3
- "version": "1.2.356",
3
+ "version": "1.2.358",
4
4
  "description": "Pipeline bundle — runner, detection, motion, audio + stream broker. Multi-entry npm package shipping pipeline addons under a single bundle.",
5
5
  "keywords": [
6
6
  "camstack",