@camstack/addon-pipeline 1.2.164 → 1.2.166

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 (33) hide show
  1. package/dist/audio-analyzer/index.js +2 -2
  2. package/dist/audio-analyzer/index.mjs +2 -2
  3. package/dist/detection-pipeline/index.js +5 -5
  4. package/dist/detection-pipeline/index.mjs +4 -4
  5. package/dist/{dist-Bz00AHCy.mjs → dist-D58lTgkb.mjs} +38 -2
  6. package/dist/{dist-15qysRyR.js → dist-DzDy7GQy.js} +38 -2
  7. package/dist/{lazy-sharp-CusvUEdy.js → lazy-sharp-BbFUtott.js} +1 -1
  8. package/dist/{local-frame-registry-BnimNHwT.js → local-frame-registry-BApB7L10.js} +1 -1
  9. package/dist/{local-frame-registry-B7cPLEW-.mjs → local-frame-registry-Bsubr_k_.mjs} +1 -1
  10. package/dist/motion-wasm/index.js +2 -2
  11. package/dist/motion-wasm/index.mjs +1 -1
  12. package/dist/{node-CpW6WY9n.mjs → node-CLOpRiqg.mjs} +1 -1
  13. package/dist/{node-BdjJPTLk.js → node-jFu0Gq80.js} +1 -1
  14. package/dist/pipeline-runner/index.js +5 -5
  15. package/dist/pipeline-runner/index.mjs +4 -4
  16. package/dist/{process-memory-BosDzc_U.mjs → process-memory-BKFQtEwX.mjs} +1 -1
  17. package/dist/{process-memory-CJHwbMAy.js → process-memory-DxEFct9z.js} +1 -1
  18. package/dist/recorder/index.js +230 -17
  19. package/dist/recorder/index.mjs +230 -17
  20. package/dist/{segment-demux-js-CmaBsM0K.mjs → segment-demux-js-6FaY07xG.mjs} +1 -1
  21. package/dist/{segment-demux-js-DoH8TCnt.js → segment-demux-js-DQ3u40kJ.js} +1 -1
  22. package/dist/session-decode/decode-worker-child.js +2 -2
  23. package/dist/session-decode/decode-worker-child.mjs +1 -1
  24. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BtUtinHp.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DuGUF2qi.mjs} +3 -3
  25. package/dist/stream-broker/demux-worker-child.js +1 -1
  26. package/dist/stream-broker/demux-worker-child.mjs +1 -1
  27. package/dist/stream-broker/{hostInit-BD_TFj7O.mjs → hostInit-BL2C-Ru6.mjs} +3 -3
  28. package/dist/stream-broker/index.js +3 -3
  29. package/dist/stream-broker/index.mjs +3 -3
  30. package/dist/stream-broker/remoteEntry.js +1 -1
  31. package/dist/{worker-protocol-DczDySjo.js → worker-protocol-BSKMHGDG.js} +1 -1
  32. package/dist/{worker-protocol-B2RCeDwS.mjs → worker-protocol-l0Mqtqka.mjs} +1 -1
  33. package/package.json +1 -1
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-15qysRyR.js");
6
- const require_process_memory = require("../process-memory-CJHwbMAy.js");
5
+ const require_dist = require("../dist-DzDy7GQy.js");
6
+ const require_process_memory = require("../process-memory-DxEFct9z.js");
7
7
  let node_fs = require("node:fs");
8
8
  node_fs = require_dist.__toESM(node_fs);
9
9
  let node_path = require("node:path");
@@ -1,6 +1,6 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { A as audioAnalysisCapability, It as hydrateSchema, S as PoolMemoryWatchdog, _t as resolvePoolMemoryPolicy, j as audioAnalyzerCapability, jt as BaseAddon, n as AUDIO_BACKEND_CHOICES, nt as mapAudioLabelToMacro, s as DEFAULT_AUDIO_ANALYZER_CONFIG, v as HF_BASE_URL, wt as errMsg } from "../dist-Bz00AHCy.mjs";
3
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BosDzc_U.mjs";
2
+ import { A as audioAnalysisCapability, It as hydrateSchema, S as PoolMemoryWatchdog, _t as resolvePoolMemoryPolicy, j as audioAnalyzerCapability, jt as BaseAddon, n as AUDIO_BACKEND_CHOICES, nt as mapAudioLabelToMacro, s as DEFAULT_AUDIO_ANALYZER_CONFIG, v as HF_BASE_URL, wt as errMsg } from "../dist-D58lTgkb.mjs";
3
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BKFQtEwX.mjs";
4
4
  import * as fs from "node:fs";
5
5
  import * as path$1 from "node:path";
6
6
  import { downloadFile } from "@camstack/system/addon-utils";
@@ -2,12 +2,12 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-15qysRyR.js");
6
- const require_node = require("../node-BdjJPTLk.js");
7
- const require_local_frame_registry = require("../local-frame-registry-BnimNHwT.js");
8
- const require_lazy_sharp = require("../lazy-sharp-CusvUEdy.js");
5
+ const require_dist = require("../dist-DzDy7GQy.js");
6
+ const require_node = require("../node-jFu0Gq80.js");
7
+ const require_local_frame_registry = require("../local-frame-registry-BApB7L10.js");
8
+ const require_lazy_sharp = require("../lazy-sharp-BbFUtott.js");
9
9
  const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DaUBcb13.js");
10
- const require_process_memory = require("../process-memory-CJHwbMAy.js");
10
+ const require_process_memory = require("../process-memory-DxEFct9z.js");
11
11
  let node_fs = require("node:fs");
12
12
  node_fs = require_dist.__toESM(node_fs);
13
13
  let node_path = require("node:path");
@@ -1,10 +1,10 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { Bt as nodePin, Ft as createEvent, It as hydrateSchema, Kt as array, O as YAMNET_TO_MACRO, Q as inferModelProvider, Qt as object, S as PoolMemoryWatchdog, St as supportedRuntimes$1, Vt as parseJsonUnknown, W as detectionPipelineCapability, Wt as sleep, Y as evaluateZoneRules, _t as resolvePoolMemoryPolicy, at as overlayClusterStepSettings, c as DEFAULT_CLUSTER_STEP_MODELS, ct as pickClusterStepSettings, dt as pipelineExecutorCapability, en as string, et as loadContributionCapability, ht as resolveClusterStepModelId, jt as BaseAddon, l as DEFAULT_CLUSTER_STEP_SETTINGS, m as DEVICE_BACKEND_TO_FORMAT, nn as EventCategory, q as enumerateInferenceDevices, st as pickClusterStepModels, t as APPLE_SA_TO_MACRO, tn as union, wt as errMsg, yt as runtimeDevices$1, z as defaultDeviceFor$1 } from "../dist-Bz00AHCy.mjs";
3
- import { a as readProcessCost } from "../node-CpW6WY9n.mjs";
4
- import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep, t as localFrameRegistry, u as landmarkPrecisionVerdict } from "../local-frame-registry-B7cPLEW-.mjs";
2
+ import { Bt as nodePin, Ft as createEvent, It as hydrateSchema, Kt as array, O as YAMNET_TO_MACRO, Q as inferModelProvider, Qt as object, S as PoolMemoryWatchdog, St as supportedRuntimes$1, Vt as parseJsonUnknown, W as detectionPipelineCapability, Wt as sleep, Y as evaluateZoneRules, _t as resolvePoolMemoryPolicy, at as overlayClusterStepSettings, c as DEFAULT_CLUSTER_STEP_MODELS, ct as pickClusterStepSettings, dt as pipelineExecutorCapability, en as string, et as loadContributionCapability, ht as resolveClusterStepModelId, jt as BaseAddon, l as DEFAULT_CLUSTER_STEP_SETTINGS, m as DEVICE_BACKEND_TO_FORMAT, nn as EventCategory, q as enumerateInferenceDevices, st as pickClusterStepModels, t as APPLE_SA_TO_MACRO, tn as union, wt as errMsg, yt as runtimeDevices$1, z as defaultDeviceFor$1 } from "../dist-D58lTgkb.mjs";
3
+ import { a as readProcessCost } from "../node-CLOpRiqg.mjs";
4
+ import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep, t as localFrameRegistry, u as landmarkPrecisionVerdict } from "../local-frame-registry-Bsubr_k_.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
6
6
  import { n as startEventLoopStallMonitor } from "../event-loop-stall-monitor-DXLNBMkY.mjs";
7
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BosDzc_U.mjs";
7
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BKFQtEwX.mjs";
8
8
  import * as fs from "node:fs";
9
9
  import * as path$1 from "node:path";
10
10
  import { spawn } from "node:child_process";
@@ -8948,7 +8948,8 @@ var OpsLogReasonSchema = _enum([
8948
8948
  "quota",
8949
8949
  "manual",
8950
8950
  "operator",
8951
- "maintenance"
8951
+ "maintenance",
8952
+ "orphaned-device"
8952
8953
  ]);
8953
8954
  /** One audit row, shared verbatim by both domains. */
8954
8955
  var OpsLogEntrySchema = object({
@@ -14642,10 +14643,39 @@ var DevicePersistConfigPayloadSchema = object({
14642
14643
  deviceId: number(),
14643
14644
  data: record(string(), unknown())
14644
14645
  });
14646
+ /** What a migration actually did, per switch. `unreachable` is a first-class
14647
+ * answer: a camera that could not be asked is not a camera that was silenced. */
14648
+ var MigrateSwitchOutcomeSchema = _enum([
14649
+ "off",
14650
+ "on",
14651
+ "not-offered",
14652
+ "unreachable"
14653
+ ]);
14654
+ var MigrateSwitchReportSchema = object({
14655
+ deviceId: number(),
14656
+ switchId: CameraSwitchIdSchema,
14657
+ outcome: MigrateSwitchOutcomeSchema,
14658
+ detail: string().optional()
14659
+ });
14660
+ var MigrateDeviceResultSchema = object({
14661
+ sourceId: number(),
14662
+ targetId: number(),
14663
+ switches: array(MigrateSwitchReportSchema).readonly(),
14664
+ /** Switches that could NOT be turned off on the source. Empty is the only
14665
+ * value meaning the replaced hardware is quiet. */
14666
+ sourceStillLive: array(CameraSwitchIdSchema).readonly(),
14667
+ swapped: boolean()
14668
+ });
14645
14669
  method(object({
14646
14670
  addonId: string(),
14647
14671
  stableId: string()
14648
- }), object({ id: number() }), { kind: "mutation" }), method(DeviceRegisterPayloadSchema, _void(), { kind: "mutation" }), method(DeviceRemovePayloadSchema, _void(), { kind: "mutation" }), method(DevicePersistConfigPayloadSchema, _void(), { kind: "mutation" }), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), DeviceMetaSchema.nullable()), method(object({
14672
+ }), object({ id: number() }), { kind: "mutation" }), method(object({
14673
+ sourceId: number(),
14674
+ targetId: number()
14675
+ }), MigrateDeviceResultSchema, {
14676
+ kind: "mutation",
14677
+ auth: "admin"
14678
+ }), method(DeviceRegisterPayloadSchema, _void(), { kind: "mutation" }), method(DeviceRemovePayloadSchema, _void(), { kind: "mutation" }), method(DevicePersistConfigPayloadSchema, _void(), { kind: "mutation" }), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), DeviceMetaSchema.nullable()), method(object({
14649
14679
  deviceId: number(),
14650
14680
  name: string()
14651
14681
  }), _void(), {
@@ -33424,6 +33454,12 @@ Object.freeze({
33424
33454
  addonId: null,
33425
33455
  access: "view"
33426
33456
  },
33457
+ "deviceManager.migrateDevice": {
33458
+ capName: "device-manager",
33459
+ capScope: "system",
33460
+ addonId: null,
33461
+ access: "create"
33462
+ },
33427
33463
  "deviceManager.persistConfig": {
33428
33464
  capName: "device-manager",
33429
33465
  capScope: "system",
@@ -8971,7 +8971,8 @@ var OpsLogReasonSchema = _enum([
8971
8971
  "quota",
8972
8972
  "manual",
8973
8973
  "operator",
8974
- "maintenance"
8974
+ "maintenance",
8975
+ "orphaned-device"
8975
8976
  ]);
8976
8977
  /** One audit row, shared verbatim by both domains. */
8977
8978
  var OpsLogEntrySchema = object({
@@ -14665,10 +14666,39 @@ var DevicePersistConfigPayloadSchema = object({
14665
14666
  deviceId: number(),
14666
14667
  data: record(string(), unknown())
14667
14668
  });
14669
+ /** What a migration actually did, per switch. `unreachable` is a first-class
14670
+ * answer: a camera that could not be asked is not a camera that was silenced. */
14671
+ var MigrateSwitchOutcomeSchema = _enum([
14672
+ "off",
14673
+ "on",
14674
+ "not-offered",
14675
+ "unreachable"
14676
+ ]);
14677
+ var MigrateSwitchReportSchema = object({
14678
+ deviceId: number(),
14679
+ switchId: CameraSwitchIdSchema,
14680
+ outcome: MigrateSwitchOutcomeSchema,
14681
+ detail: string().optional()
14682
+ });
14683
+ var MigrateDeviceResultSchema = object({
14684
+ sourceId: number(),
14685
+ targetId: number(),
14686
+ switches: array(MigrateSwitchReportSchema).readonly(),
14687
+ /** Switches that could NOT be turned off on the source. Empty is the only
14688
+ * value meaning the replaced hardware is quiet. */
14689
+ sourceStillLive: array(CameraSwitchIdSchema).readonly(),
14690
+ swapped: boolean()
14691
+ });
14668
14692
  method(object({
14669
14693
  addonId: string(),
14670
14694
  stableId: string()
14671
- }), object({ id: number() }), { kind: "mutation" }), method(DeviceRegisterPayloadSchema, _void(), { kind: "mutation" }), method(DeviceRemovePayloadSchema, _void(), { kind: "mutation" }), method(DevicePersistConfigPayloadSchema, _void(), { kind: "mutation" }), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), DeviceMetaSchema.nullable()), method(object({
14695
+ }), object({ id: number() }), { kind: "mutation" }), method(object({
14696
+ sourceId: number(),
14697
+ targetId: number()
14698
+ }), MigrateDeviceResultSchema, {
14699
+ kind: "mutation",
14700
+ auth: "admin"
14701
+ }), method(DeviceRegisterPayloadSchema, _void(), { kind: "mutation" }), method(DeviceRemovePayloadSchema, _void(), { kind: "mutation" }), method(DevicePersistConfigPayloadSchema, _void(), { kind: "mutation" }), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), DeviceMetaSchema.nullable()), method(object({
14672
14702
  deviceId: number(),
14673
14703
  name: string()
14674
14704
  }), _void(), {
@@ -33447,6 +33477,12 @@ Object.freeze({
33447
33477
  addonId: null,
33448
33478
  access: "view"
33449
33479
  },
33480
+ "deviceManager.migrateDevice": {
33481
+ capName: "device-manager",
33482
+ capScope: "system",
33483
+ addonId: null,
33484
+ access: "create"
33485
+ },
33450
33486
  "deviceManager.persistConfig": {
33451
33487
  capName: "device-manager",
33452
33488
  capScope: "system",
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-15qysRyR.js");
1
+ const require_dist = require("./dist-DzDy7GQy.js");
2
2
  let node_path = require("node:path");
3
3
  node_path = require_dist.__toESM(node_path);
4
4
  let node_url = require("node:url");
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-15qysRyR.js");
1
+ const require_dist = require("./dist-DzDy7GQy.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -1,4 +1,4 @@
1
- import { M as audioKindId, Z as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-Bz00AHCy.mjs";
1
+ import { M as audioKindId, Z as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-D58lTgkb.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-15qysRyR.js");
6
- const require_lazy_sharp = require("../lazy-sharp-CusvUEdy.js");
5
+ const require_dist = require("../dist-DzDy7GQy.js");
6
+ const require_lazy_sharp = require("../lazy-sharp-BbFUtott.js");
7
7
  let node_fs = require("node:fs");
8
8
  let node_path = require("node:path");
9
9
  //#region src/motion-wasm/wasm-motion-detector.ts
@@ -1,4 +1,4 @@
1
- import { It as hydrateSchema, Pt as DeviceType, Y as evaluateZoneRules, it as motionDetectionCapability, jt as BaseAddon } from "../dist-Bz00AHCy.mjs";
1
+ import { It as hydrateSchema, Pt as DeviceType, Y as evaluateZoneRules, it as motionDetectionCapability, jt as BaseAddon } from "../dist-D58lTgkb.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,4 +1,4 @@
1
- import { Dt as buildFfmpegArgs, Et as Fmp4BoxSplitter, kt as isSoftwareDecode, wt as errMsg } from "./dist-Bz00AHCy.mjs";
1
+ import { Dt as buildFfmpegArgs, Et as Fmp4BoxSplitter, kt as isSoftwareDecode, wt as errMsg } from "./dist-D58lTgkb.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import "node:fs";
4
4
  import "node:path";
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-15qysRyR.js");
1
+ const require_dist = require("./dist-DzDy7GQy.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  let node_fs = require("node:fs");
4
4
  node_fs = require_dist.__toESM(node_fs, 1);
@@ -2,12 +2,12 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-15qysRyR.js");
6
- const require_node = require("../node-BdjJPTLk.js");
7
- const require_local_frame_registry = require("../local-frame-registry-BnimNHwT.js");
8
- const require_worker_protocol = require("../worker-protocol-DczDySjo.js");
5
+ const require_dist = require("../dist-DzDy7GQy.js");
6
+ const require_node = require("../node-jFu0Gq80.js");
7
+ const require_local_frame_registry = require("../local-frame-registry-BApB7L10.js");
8
+ const require_worker_protocol = require("../worker-protocol-BSKMHGDG.js");
9
9
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
10
- const require_lazy_sharp = require("../lazy-sharp-CusvUEdy.js");
10
+ const require_lazy_sharp = require("../lazy-sharp-BbFUtott.js");
11
11
  const require_restream_intent = require("../restream-intent-Cv9x3jmu.js");
12
12
  const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DaUBcb13.js");
13
13
  const require_remote_restream = require("../remote-restream-CO36Sr30.js");
@@ -1,7 +1,7 @@
1
- import { B as defineCustomActions, Bt as nodePin, Ft as createEvent, Gt as _enum, H as deriveDetailCropRect, Kt as array, L as customAction, Qt as object, X as failureContributionCapability, Xt as literal, Yt as lazy, Zt as number, _ as FailureCounters, en as string, et as loadContributionCapability, ft as pipelineRunnerCapability, jt as BaseAddon, lt as pickDetailCropConvention, m as DEVICE_BACKEND_TO_FORMAT, nn as EventCategory, p as DEFAULT_NATIVE_LEASE_SETTINGS, qt as boolean, u as DEFAULT_DETAIL_CROP_CONVENTION, ut as pickNativeLeaseOverride, wt as errMsg } from "../dist-Bz00AHCy.mjs";
2
- import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-CpW6WY9n.mjs";
3
- import { c as getStepDefinition, n as resolveFrameViewGeometry, t as localFrameRegistry } from "../local-frame-registry-B7cPLEW-.mjs";
4
- import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-B2RCeDwS.mjs";
1
+ import { B as defineCustomActions, Bt as nodePin, Ft as createEvent, Gt as _enum, H as deriveDetailCropRect, Kt as array, L as customAction, Qt as object, X as failureContributionCapability, Xt as literal, Yt as lazy, Zt as number, _ as FailureCounters, en as string, et as loadContributionCapability, ft as pipelineRunnerCapability, jt as BaseAddon, lt as pickDetailCropConvention, m as DEVICE_BACKEND_TO_FORMAT, nn as EventCategory, p as DEFAULT_NATIVE_LEASE_SETTINGS, qt as boolean, u as DEFAULT_DETAIL_CROP_CONVENTION, ut as pickNativeLeaseOverride, wt as errMsg } from "../dist-D58lTgkb.mjs";
2
+ import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-CLOpRiqg.mjs";
3
+ import { c as getStepDefinition, n as resolveFrameViewGeometry, t as localFrameRegistry } from "../local-frame-registry-Bsubr_k_.mjs";
4
+ import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-l0Mqtqka.mjs";
5
5
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
6
6
  import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
7
7
  import { n as withDetectionIntent } from "../restream-intent-B4BXZra7.mjs";
@@ -1,4 +1,4 @@
1
- import { ot as parseProcStatus } from "./dist-Bz00AHCy.mjs";
1
+ import { ot as parseProcStatus } from "./dist-D58lTgkb.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
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-15qysRyR.js");
1
+ const require_dist = require("./dist-DzDy7GQy.js");
2
2
  let node_fs = require("node:fs");
3
3
  node_fs = require_dist.__toESM(node_fs);
4
4
  let node_child_process = require("node:child_process");
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-15qysRyR.js");
6
- const require_node = require("../node-BdjJPTLk.js");
5
+ const require_dist = require("../dist-DzDy7GQy.js");
6
+ const require_node = require("../node-jFu0Gq80.js");
7
7
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
8
8
  const require_restream_intent = require("../restream-intent-Cv9x3jmu.js");
9
9
  const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DaUBcb13.js");
@@ -3002,21 +3002,145 @@ function selectEvictionsByBytes(segments, targetBytes) {
3002
3002
  }
3003
3003
  return out;
3004
3004
  }
3005
+ var OrphanDeviceLane = class {
3006
+ deps;
3007
+ /** deviceId → consecutive ANSWERED reads that did not contain it. */
3008
+ absenceStreak = /* @__PURE__ */ new Map();
3009
+ /** The verdict the last answered read reached, reused inside the gap. */
3010
+ confirmed = /* @__PURE__ */ new Set();
3011
+ /** When a read was last TAKEN (answered or not) — the gap is a rate limit on
3012
+ * asking, not on believing. */
3013
+ lastReadAtMs = null;
3014
+ constructor(deps) {
3015
+ this.deps = deps;
3016
+ }
3017
+ /**
3018
+ * Of the devices that hold footage here, which ones has the registry
3019
+ * confirmed — twice, on reads taken apart in time — that it no longer knows?
3020
+ *
3021
+ * Never throws: every failure returns the empty set, which is "evict the way
3022
+ * this repo evicted before the lane existed".
3023
+ */
3024
+ async confirmedOrphans(footageDevices) {
3025
+ if (footageDevices.size === 0) return /* @__PURE__ */ new Set();
3026
+ const now = this.deps.now?.() ?? Date.now();
3027
+ const minGap = this.deps.minGapMs ?? 3e4;
3028
+ if (this.lastReadAtMs !== null && now - this.lastReadAtMs < minGap) return intersect(this.confirmed, footageDevices);
3029
+ const read = await this.readOnce();
3030
+ this.lastReadAtMs = now;
3031
+ const known = this.trustedDeviceIds(read, footageDevices);
3032
+ if (known === null) return intersect(this.confirmed, footageDevices);
3033
+ this.advanceStreaks(known, footageDevices);
3034
+ const confirmed = /* @__PURE__ */ new Set();
3035
+ for (const [deviceId, streak] of this.absenceStreak) if (streak >= 2) confirmed.add(deviceId);
3036
+ this.confirmed = confirmed;
3037
+ return intersect(confirmed, footageDevices);
3038
+ }
3039
+ /** The read, with a throw folded into the union rather than escaping. */
3040
+ async readOnce() {
3041
+ try {
3042
+ return await this.deps.readRegistry();
3043
+ } catch (err) {
3044
+ return {
3045
+ status: "unanswered",
3046
+ detail: err instanceof Error ? err.message : String(err)
3047
+ };
3048
+ }
3049
+ }
3050
+ /**
3051
+ * Rules 1-3: the device ids this read may be believed about, or `null` when
3052
+ * it may not be believed at all.
3053
+ *
3054
+ * Every refusal is SAID — a lane that silently declines to run is
3055
+ * indistinguishable from one nobody wired, and this branch drops work (the
3056
+ * operator's ordering) on purpose.
3057
+ */
3058
+ trustedDeviceIds(read, footageDevices) {
3059
+ if (read.status === "unanswered") {
3060
+ this.deps.logger.warn("recorder: dead-device eviction lane disarmed — the device registry did not answer; evicting oldest-first only", { meta: {
3061
+ detail: read.detail,
3062
+ footageDevices: footageDevices.size
3063
+ } });
3064
+ return null;
3065
+ }
3066
+ if (read.deviceIds.size === 0) {
3067
+ this.deps.logger.warn("recorder: dead-device eviction lane disarmed — the device enumeration came back empty, which an empty store snapshot also looks like", { meta: { footageDevices: footageDevices.size } });
3068
+ return null;
3069
+ }
3070
+ let recognised = 0;
3071
+ for (const deviceId of footageDevices) if (read.deviceIds.has(deviceId)) recognised += 1;
3072
+ if (recognised === 0) {
3073
+ this.deps.logger.warn("recorder: dead-device eviction lane disarmed — the registry knows NONE of the cameras holding footage here, which is a defect report and not a fleet-wide deletion", { meta: {
3074
+ footageDevices: footageDevices.size,
3075
+ registryDevices: read.deviceIds.size
3076
+ } });
3077
+ return null;
3078
+ }
3079
+ return read.deviceIds;
3080
+ }
3081
+ /** Rules 4 and 5, plus the bound: the map only ever holds devices that hold
3082
+ * footage right now, so it cannot outgrow the archive. */
3083
+ advanceStreaks(known, footageDevices) {
3084
+ for (const deviceId of this.absenceStreak.keys()) if (!footageDevices.has(deviceId)) this.absenceStreak.delete(deviceId);
3085
+ for (const deviceId of footageDevices) {
3086
+ if (known.has(deviceId)) {
3087
+ this.absenceStreak.delete(deviceId);
3088
+ continue;
3089
+ }
3090
+ const streak = (this.absenceStreak.get(deviceId) ?? 0) + 1;
3091
+ this.absenceStreak.set(deviceId, streak);
3092
+ if (streak === 2) this.deps.logger.warn("recorder: camera confirmed gone by two independent registry reads — its footage is now evicted before anything chosen by age", {
3093
+ tags: { deviceId },
3094
+ meta: { confirmations: streak }
3095
+ });
3096
+ }
3097
+ }
3098
+ };
3099
+ function intersect(a, b) {
3100
+ const out = /* @__PURE__ */ new Set();
3101
+ for (const value of a) if (b.has(value)) out.add(value);
3102
+ return out;
3103
+ }
3005
3104
  //#endregion
3006
3105
  //#region src/recorder/storage-evictable-provider.ts
3007
3106
  /**
3008
3107
  * Implements the `storage-evictable` cap surface for recording footage. The core
3009
3108
  * StoragePressureManager owns the trigger (per-location free-space monitoring); this
3010
- * provider decides WHAT footage is expendable (oldest-first, no pinning) and deletes it
3011
- * via `SegmentStore.evict`, which removes the file through the `storage` cap and de-indexes.
3109
+ * provider decides WHAT footage is expendable and deletes it via `SegmentStore.evict`,
3110
+ * which removes the file through the `storage` cap and de-indexes.
3111
+ *
3112
+ * ## Two tiers, one budget
3113
+ *
3114
+ * Footage of a camera the registry no longer knows is chosen BEFORE any age
3115
+ * comparison; within that tier, and in everything after it, still oldest-first.
3116
+ * The operator's rule is "when the disk fills, lose the dead cameras first",
3117
+ * and it applies under disk pressure ONLY — there is deliberately no
3118
+ * time-based sweep of dead-device footage, so a camera that is gone keeps its
3119
+ * footage until the space is actually needed.
3120
+ *
3121
+ * This changes the ORDER and not the amount: the two tiers share one
3122
+ * `targetBytes` budget, the second is asked only for what the first left
3123
+ * uncovered, and nothing is selected that plain oldest-first would not have
3124
+ * been willing to select eventually.
3125
+ *
3126
+ * The dead-device tier is gated by {@link OrphanDeviceLane} — a registry read
3127
+ * that fails, comes back empty, or contradicts itself arms nothing, and the
3128
+ * round degrades to exactly the oldest-first behaviour that predates the tier.
3012
3129
  *
3013
3130
  * The cap's `locationId` is used directly as the storage `location` (identity); see Plan 2d
3014
3131
  * notes. Wiring this class to the cap + the SegmentStore happens in Plan 2e.
3015
3132
  */
3016
3133
  var StorageEvictableProvider = class {
3017
3134
  deps;
3135
+ orphanLane;
3018
3136
  constructor(deps) {
3019
3137
  this.deps = deps;
3138
+ this.orphanLane = new OrphanDeviceLane({
3139
+ readRegistry: deps.deviceRegistry,
3140
+ logger: deps.logger,
3141
+ ...deps.now !== void 0 ? { now: deps.now } : {},
3142
+ ...deps.orphanConfirmGapMs !== void 0 ? { minGapMs: deps.orphanConfirmGapMs } : {}
3143
+ });
3020
3144
  }
3021
3145
  /** The eviction domain of `locationId` — aliases sharing its disk, else
3022
3146
  * itself — MINUS read-only members (drain mode: their bytes are neither
@@ -3056,8 +3180,19 @@ var StorageEvictableProvider = class {
3056
3180
  exhausted: true
3057
3181
  };
3058
3182
  }
3059
- const oldest = await archive.oldestSegments(this.domainOf(input.locationId), input.targetBytes);
3060
- const victims = selectEvictionsByBytes(oldest.rows, input.targetBytes);
3183
+ const domain = this.domainOf(input.locationId);
3184
+ const orphans = await this.orphanLane.confirmedOrphans(archive.devicesWithFootage(domain));
3185
+ const orphanVictims = orphans.size === 0 ? [] : selectEvictionsByBytes((await archive.oldestSegmentsForDevices(domain, orphans, input.targetBytes)).rows, input.targetBytes);
3186
+ const orphanBytes = orphanVictims.reduce((sum, v) => sum + v.bytes, 0);
3187
+ const remainingBytes = input.targetBytes - orphanBytes;
3188
+ const oldest = remainingBytes > 0 ? await archive.oldestSegments(domain, remainingBytes) : {
3189
+ rows: [],
3190
+ exhausted: false
3191
+ };
3192
+ const taken = new Set(orphanVictims.map((v) => v.path));
3193
+ const ageCandidates = oldest.rows.filter((r) => !taken.has(r.path));
3194
+ const ageVictims = selectEvictionsByBytes(ageCandidates, remainingBytes);
3195
+ const victims = [...orphanVictims, ...ageVictims];
3061
3196
  const byLocation = /* @__PURE__ */ new Map();
3062
3197
  for (const v of victims) {
3063
3198
  const group = byLocation.get(v.locationId);
@@ -3066,8 +3201,8 @@ var StorageEvictableProvider = class {
3066
3201
  }
3067
3202
  let reclaimedBytes = 0;
3068
3203
  for (const [locationId, rows] of byLocation) reclaimedBytes += await this.deps.store.evict(locationId, rows);
3069
- if (reclaimedBytes > 0 && this.deps.onEvicted) this.deps.onEvicted(summarizeEvictionsByDevice(victims));
3070
- const exhausted = oldest.exhausted && victims.length >= oldest.rows.length;
3204
+ if (reclaimedBytes > 0 && this.deps.onEvicted) this.deps.onEvicted(summarizeEvictionsByDevice(victims, orphans));
3205
+ const exhausted = oldest.exhausted && ageVictims.length >= ageCandidates.length;
3071
3206
  return {
3072
3207
  reclaimedBytes,
3073
3208
  exhausted
@@ -3077,8 +3212,14 @@ var StorageEvictableProvider = class {
3077
3212
  /** Group an eviction round's victims into per-(device, location) summaries (bytes
3078
3213
  * come from the pre-delete selection — partial delete failures may overstate
3079
3214
  * slightly). A domain round can span aliased locations, so each victim is bucketed
3080
- * by its OWN `locationId` (not a single round-level location). */
3081
- function summarizeEvictionsByDevice(victims) {
3215
+ * by its OWN `locationId` (not a single round-level location).
3216
+ *
3217
+ * `orphanDeviceIds` is the round's CONFIRMED-gone set and it decides each
3218
+ * summary's {@link EvictionReason}. Required rather than defaulted: the reason
3219
+ * is what the operator reads in the activity history, and a caller that forgot
3220
+ * to pass it would file every eviction as `oldest-first` — the one wrong
3221
+ * answer nothing downstream could detect. */
3222
+ function summarizeEvictionsByDevice(victims, orphanDeviceIds) {
3082
3223
  const byKey = /* @__PURE__ */ new Map();
3083
3224
  for (const v of victims) {
3084
3225
  const key = `${v.deviceId}${v.locationId}`;
@@ -3089,11 +3230,11 @@ function summarizeEvictionsByDevice(victims) {
3089
3230
  segments: 1,
3090
3231
  bytes: v.bytes,
3091
3232
  fromMs: v.startMs,
3092
- toMs: v.startMs + v.durMs
3233
+ toMs: v.startMs + v.durMs,
3234
+ reason: orphanDeviceIds.has(v.deviceId) ? "orphaned-device" : "oldest-first"
3093
3235
  });
3094
3236
  else byKey.set(key, {
3095
- deviceId: v.deviceId,
3096
- locationId: v.locationId,
3237
+ ...cur,
3097
3238
  segments: cur.segments + 1,
3098
3239
  bytes: cur.bytes + v.bytes,
3099
3240
  fromMs: Math.min(cur.fromMs, v.startMs),
@@ -8922,6 +9063,49 @@ var SegmentHourLedger = class SegmentHourLedger {
8922
9063
  * able to say truthfully.
8923
9064
  */
8924
9065
  async oldestSegments(locationIds, targetBytes) {
9066
+ return this.oldestSegmentsScoped(locationIds, null, targetBytes);
9067
+ }
9068
+ /**
9069
+ * {@link oldestSegments}, narrowed to a set of cameras.
9070
+ *
9071
+ * The disk-pressure evictor's dead-device tier needs the oldest footage OF
9072
+ * THE CAMERAS THAT NO LONGER EXIST, which is a different question from the
9073
+ * oldest footage on the disk: an orphan's newest hour has to be reachable
9074
+ * even when a live camera holds every one of the oldest ones. The narrowing
9075
+ * is a `deviceId IN (…)` on the same statement, so it stays ONE ordered,
9076
+ * bounded, paged read and never a per-device merge.
9077
+ *
9078
+ * The device set is the CALLER's business — this method neither knows nor
9079
+ * checks what makes a device evictable. Refuses an empty set rather than
9080
+ * compiling to "every camera", for the same reason
9081
+ * {@link SegmentHourLedger.predicate} refuses an empty scope.
9082
+ */
9083
+ async oldestSegmentsForDevices(locationIds, deviceIds, targetBytes) {
9084
+ if (deviceIds.size === 0) return {
9085
+ rows: [],
9086
+ exhausted: true
9087
+ };
9088
+ return this.oldestSegmentsScoped(locationIds, [...deviceIds], targetBytes);
9089
+ }
9090
+ /**
9091
+ * Every camera the ledger holds an hour for on these locations.
9092
+ *
9093
+ * Answered from T1 — the always-resident hour summary, which carries
9094
+ * `deviceId` and `locationId` — exactly like {@link profilesWithFootage},
9095
+ * and for the same reason: this is an O(writers × days) question and it must
9096
+ * cost no I/O. It runs on the disk-pressure path, where an I/O that fails
9097
+ * would have to be turned into a verdict.
9098
+ *
9099
+ * An EMPTY answer is "the mirror knows no hour here", which is also what a
9100
+ * ledger whose load failed reports — so the caller must treat it as "decide
9101
+ * nothing", never as "no camera owns this footage".
9102
+ */
9103
+ devicesWithFootage(locationIds) {
9104
+ const out = /* @__PURE__ */ new Set();
9105
+ for (const row of this.ledger.snapshot()) if (locationIds.has(row.locationId)) out.add(row.deviceId);
9106
+ return out;
9107
+ }
9108
+ async oldestSegmentsScoped(locationIds, deviceIds, targetBytes) {
8925
9109
  const ids = [...locationIds];
8926
9110
  if (ids.length === 0 || targetBytes <= 0) return {
8927
9111
  rows: [],
@@ -8936,7 +9120,10 @@ var SegmentHourLedger = class SegmentHourLedger {
8936
9120
  collection: RECORDING_SEGMENT_HOURS_COLLECTION,
8937
9121
  columns: OLDEST_PROBE_COLUMNS,
8938
9122
  filter: {
8939
- whereIn: { locationId: ids },
9123
+ whereIn: deviceIds === null ? { locationId: ids } : {
9124
+ locationId: ids,
9125
+ deviceId: deviceIds
9126
+ },
8940
9127
  orderBy: {
8941
9128
  field: "hourStartMs",
8942
9129
  direction: "asc"
@@ -16660,15 +16847,40 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
16660
16847
  store: this.segmentStore,
16661
16848
  resolveDomain: (locationId) => this.locationDomain(locationId),
16662
16849
  isReadOnly: (locationId) => this.resolvedLocations.find((l) => l.id === locationId)?.readOnly === true,
16850
+ deviceRegistry: async () => {
16851
+ try {
16852
+ const devices = await this.ctx.api.deviceManager.listAll.query({ projection: "slim" });
16853
+ return {
16854
+ status: "answered",
16855
+ deviceIds: new Set(devices.map((d) => d.id))
16856
+ };
16857
+ } catch (err) {
16858
+ return {
16859
+ status: "unanswered",
16860
+ detail: err instanceof Error ? err.message : String(err)
16861
+ };
16862
+ }
16863
+ },
16663
16864
  onEvicted: (summaries) => {
16664
16865
  for (const s of summaries) {
16866
+ const opReason = s.reason === "orphaned-device" ? "orphaned-device" : "quota";
16665
16867
  opsLog.append({
16666
16868
  op: "prune",
16667
- reason: "quota",
16869
+ reason: opReason,
16668
16870
  deviceId: s.deviceId,
16669
16871
  itemsAffected: s.segments,
16670
16872
  bytesReclaimed: s.bytes,
16671
- detail: `disk-pressure evicted [${new Date(s.fromMs).toISOString()}, ${new Date(s.toMs).toISOString()}) on ${s.locationId}`
16873
+ detail: `disk-pressure evicted [${new Date(s.fromMs).toISOString()}, ${new Date(s.toMs).toISOString()}) on ${s.locationId} — ${s.reason}`
16874
+ });
16875
+ if (s.reason === "orphaned-device") this.ctx.logger.info("recorder: disk-pressure evicted footage of a camera that no longer exists — chosen ahead of older footage of live cameras", {
16876
+ tags: { deviceId: s.deviceId },
16877
+ meta: {
16878
+ locationId: s.locationId,
16879
+ segments: s.segments,
16880
+ bytes: s.bytes,
16881
+ fromMs: s.fromMs,
16882
+ toMs: s.toMs
16883
+ }
16672
16884
  });
16673
16885
  this.ctx.eventBus.emit({
16674
16886
  id: (0, node_crypto.randomUUID)(),
@@ -16688,7 +16900,8 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
16688
16900
  bytes: s.bytes,
16689
16901
  fromMs: s.fromMs,
16690
16902
  toMs: s.toMs,
16691
- trigger: "disk-pressure"
16903
+ trigger: "disk-pressure",
16904
+ reason: s.reason
16692
16905
  }
16693
16906
  });
16694
16907
  }
@@ -1,5 +1,5 @@
1
- import { $ as isFirstLevelMacroClass, $t as record, B as defineCustomActions, Bt as nodePin, E as RecordingConfigSchema, Gt as _enum, It as hydrateSchema, J as evaluateSensorEdge, Kt as array, L as customAction, N as batteryCapability, Nt as DeviceFeature, Pt as DeviceType, Qt as object, T as RECORDING_EXPORT_MAX_READ_BYTES, U as deriveRecordingMode, Ut as selectAssignedProfileSlots, V as deriveBatteryPresence, Wt as sleep$1, Zt as number, bt as storageEvictableCapability, d as DEFAULT_EVENTS_BAND_BUFFER_SEC, en as string, et as loadContributionCapability, g as ExportRecordSchema, i as BatteryStatusSchema, jt as BaseAddon, mt as recordingExportCapability, nn as EventCategory, pt as recordingCapability, qt as boolean, vt as resolveRecordingProfiles, wt as errMsg, x as OpsLogEntrySchema } from "../dist-Bz00AHCy.mjs";
2
- import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-CpW6WY9n.mjs";
1
+ import { $ as isFirstLevelMacroClass, $t as record, B as defineCustomActions, Bt as nodePin, E as RecordingConfigSchema, Gt as _enum, It as hydrateSchema, J as evaluateSensorEdge, Kt as array, L as customAction, N as batteryCapability, Nt as DeviceFeature, Pt as DeviceType, Qt as object, T as RECORDING_EXPORT_MAX_READ_BYTES, U as deriveRecordingMode, Ut as selectAssignedProfileSlots, V as deriveBatteryPresence, Wt as sleep$1, Zt as number, bt as storageEvictableCapability, d as DEFAULT_EVENTS_BAND_BUFFER_SEC, en as string, et as loadContributionCapability, g as ExportRecordSchema, i as BatteryStatusSchema, jt as BaseAddon, mt as recordingExportCapability, nn as EventCategory, pt as recordingCapability, qt as boolean, vt as resolveRecordingProfiles, wt as errMsg, x as OpsLogEntrySchema } from "../dist-D58lTgkb.mjs";
2
+ import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-CLOpRiqg.mjs";
3
3
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
4
4
  import { r as withRecordingIntent } from "../restream-intent-B4BXZra7.mjs";
5
5
  import { n as startEventLoopStallMonitor } from "../event-loop-stall-monitor-DXLNBMkY.mjs";
@@ -2997,21 +2997,145 @@ function selectEvictionsByBytes(segments, targetBytes) {
2997
2997
  }
2998
2998
  return out;
2999
2999
  }
3000
+ var OrphanDeviceLane = class {
3001
+ deps;
3002
+ /** deviceId → consecutive ANSWERED reads that did not contain it. */
3003
+ absenceStreak = /* @__PURE__ */ new Map();
3004
+ /** The verdict the last answered read reached, reused inside the gap. */
3005
+ confirmed = /* @__PURE__ */ new Set();
3006
+ /** When a read was last TAKEN (answered or not) — the gap is a rate limit on
3007
+ * asking, not on believing. */
3008
+ lastReadAtMs = null;
3009
+ constructor(deps) {
3010
+ this.deps = deps;
3011
+ }
3012
+ /**
3013
+ * Of the devices that hold footage here, which ones has the registry
3014
+ * confirmed — twice, on reads taken apart in time — that it no longer knows?
3015
+ *
3016
+ * Never throws: every failure returns the empty set, which is "evict the way
3017
+ * this repo evicted before the lane existed".
3018
+ */
3019
+ async confirmedOrphans(footageDevices) {
3020
+ if (footageDevices.size === 0) return /* @__PURE__ */ new Set();
3021
+ const now = this.deps.now?.() ?? Date.now();
3022
+ const minGap = this.deps.minGapMs ?? 3e4;
3023
+ if (this.lastReadAtMs !== null && now - this.lastReadAtMs < minGap) return intersect(this.confirmed, footageDevices);
3024
+ const read = await this.readOnce();
3025
+ this.lastReadAtMs = now;
3026
+ const known = this.trustedDeviceIds(read, footageDevices);
3027
+ if (known === null) return intersect(this.confirmed, footageDevices);
3028
+ this.advanceStreaks(known, footageDevices);
3029
+ const confirmed = /* @__PURE__ */ new Set();
3030
+ for (const [deviceId, streak] of this.absenceStreak) if (streak >= 2) confirmed.add(deviceId);
3031
+ this.confirmed = confirmed;
3032
+ return intersect(confirmed, footageDevices);
3033
+ }
3034
+ /** The read, with a throw folded into the union rather than escaping. */
3035
+ async readOnce() {
3036
+ try {
3037
+ return await this.deps.readRegistry();
3038
+ } catch (err) {
3039
+ return {
3040
+ status: "unanswered",
3041
+ detail: err instanceof Error ? err.message : String(err)
3042
+ };
3043
+ }
3044
+ }
3045
+ /**
3046
+ * Rules 1-3: the device ids this read may be believed about, or `null` when
3047
+ * it may not be believed at all.
3048
+ *
3049
+ * Every refusal is SAID — a lane that silently declines to run is
3050
+ * indistinguishable from one nobody wired, and this branch drops work (the
3051
+ * operator's ordering) on purpose.
3052
+ */
3053
+ trustedDeviceIds(read, footageDevices) {
3054
+ if (read.status === "unanswered") {
3055
+ this.deps.logger.warn("recorder: dead-device eviction lane disarmed — the device registry did not answer; evicting oldest-first only", { meta: {
3056
+ detail: read.detail,
3057
+ footageDevices: footageDevices.size
3058
+ } });
3059
+ return null;
3060
+ }
3061
+ if (read.deviceIds.size === 0) {
3062
+ this.deps.logger.warn("recorder: dead-device eviction lane disarmed — the device enumeration came back empty, which an empty store snapshot also looks like", { meta: { footageDevices: footageDevices.size } });
3063
+ return null;
3064
+ }
3065
+ let recognised = 0;
3066
+ for (const deviceId of footageDevices) if (read.deviceIds.has(deviceId)) recognised += 1;
3067
+ if (recognised === 0) {
3068
+ this.deps.logger.warn("recorder: dead-device eviction lane disarmed — the registry knows NONE of the cameras holding footage here, which is a defect report and not a fleet-wide deletion", { meta: {
3069
+ footageDevices: footageDevices.size,
3070
+ registryDevices: read.deviceIds.size
3071
+ } });
3072
+ return null;
3073
+ }
3074
+ return read.deviceIds;
3075
+ }
3076
+ /** Rules 4 and 5, plus the bound: the map only ever holds devices that hold
3077
+ * footage right now, so it cannot outgrow the archive. */
3078
+ advanceStreaks(known, footageDevices) {
3079
+ for (const deviceId of this.absenceStreak.keys()) if (!footageDevices.has(deviceId)) this.absenceStreak.delete(deviceId);
3080
+ for (const deviceId of footageDevices) {
3081
+ if (known.has(deviceId)) {
3082
+ this.absenceStreak.delete(deviceId);
3083
+ continue;
3084
+ }
3085
+ const streak = (this.absenceStreak.get(deviceId) ?? 0) + 1;
3086
+ this.absenceStreak.set(deviceId, streak);
3087
+ if (streak === 2) this.deps.logger.warn("recorder: camera confirmed gone by two independent registry reads — its footage is now evicted before anything chosen by age", {
3088
+ tags: { deviceId },
3089
+ meta: { confirmations: streak }
3090
+ });
3091
+ }
3092
+ }
3093
+ };
3094
+ function intersect(a, b) {
3095
+ const out = /* @__PURE__ */ new Set();
3096
+ for (const value of a) if (b.has(value)) out.add(value);
3097
+ return out;
3098
+ }
3000
3099
  //#endregion
3001
3100
  //#region src/recorder/storage-evictable-provider.ts
3002
3101
  /**
3003
3102
  * Implements the `storage-evictable` cap surface for recording footage. The core
3004
3103
  * StoragePressureManager owns the trigger (per-location free-space monitoring); this
3005
- * provider decides WHAT footage is expendable (oldest-first, no pinning) and deletes it
3006
- * via `SegmentStore.evict`, which removes the file through the `storage` cap and de-indexes.
3104
+ * provider decides WHAT footage is expendable and deletes it via `SegmentStore.evict`,
3105
+ * which removes the file through the `storage` cap and de-indexes.
3106
+ *
3107
+ * ## Two tiers, one budget
3108
+ *
3109
+ * Footage of a camera the registry no longer knows is chosen BEFORE any age
3110
+ * comparison; within that tier, and in everything after it, still oldest-first.
3111
+ * The operator's rule is "when the disk fills, lose the dead cameras first",
3112
+ * and it applies under disk pressure ONLY — there is deliberately no
3113
+ * time-based sweep of dead-device footage, so a camera that is gone keeps its
3114
+ * footage until the space is actually needed.
3115
+ *
3116
+ * This changes the ORDER and not the amount: the two tiers share one
3117
+ * `targetBytes` budget, the second is asked only for what the first left
3118
+ * uncovered, and nothing is selected that plain oldest-first would not have
3119
+ * been willing to select eventually.
3120
+ *
3121
+ * The dead-device tier is gated by {@link OrphanDeviceLane} — a registry read
3122
+ * that fails, comes back empty, or contradicts itself arms nothing, and the
3123
+ * round degrades to exactly the oldest-first behaviour that predates the tier.
3007
3124
  *
3008
3125
  * The cap's `locationId` is used directly as the storage `location` (identity); see Plan 2d
3009
3126
  * notes. Wiring this class to the cap + the SegmentStore happens in Plan 2e.
3010
3127
  */
3011
3128
  var StorageEvictableProvider = class {
3012
3129
  deps;
3130
+ orphanLane;
3013
3131
  constructor(deps) {
3014
3132
  this.deps = deps;
3133
+ this.orphanLane = new OrphanDeviceLane({
3134
+ readRegistry: deps.deviceRegistry,
3135
+ logger: deps.logger,
3136
+ ...deps.now !== void 0 ? { now: deps.now } : {},
3137
+ ...deps.orphanConfirmGapMs !== void 0 ? { minGapMs: deps.orphanConfirmGapMs } : {}
3138
+ });
3015
3139
  }
3016
3140
  /** The eviction domain of `locationId` — aliases sharing its disk, else
3017
3141
  * itself — MINUS read-only members (drain mode: their bytes are neither
@@ -3051,8 +3175,19 @@ var StorageEvictableProvider = class {
3051
3175
  exhausted: true
3052
3176
  };
3053
3177
  }
3054
- const oldest = await archive.oldestSegments(this.domainOf(input.locationId), input.targetBytes);
3055
- const victims = selectEvictionsByBytes(oldest.rows, input.targetBytes);
3178
+ const domain = this.domainOf(input.locationId);
3179
+ const orphans = await this.orphanLane.confirmedOrphans(archive.devicesWithFootage(domain));
3180
+ const orphanVictims = orphans.size === 0 ? [] : selectEvictionsByBytes((await archive.oldestSegmentsForDevices(domain, orphans, input.targetBytes)).rows, input.targetBytes);
3181
+ const orphanBytes = orphanVictims.reduce((sum, v) => sum + v.bytes, 0);
3182
+ const remainingBytes = input.targetBytes - orphanBytes;
3183
+ const oldest = remainingBytes > 0 ? await archive.oldestSegments(domain, remainingBytes) : {
3184
+ rows: [],
3185
+ exhausted: false
3186
+ };
3187
+ const taken = new Set(orphanVictims.map((v) => v.path));
3188
+ const ageCandidates = oldest.rows.filter((r) => !taken.has(r.path));
3189
+ const ageVictims = selectEvictionsByBytes(ageCandidates, remainingBytes);
3190
+ const victims = [...orphanVictims, ...ageVictims];
3056
3191
  const byLocation = /* @__PURE__ */ new Map();
3057
3192
  for (const v of victims) {
3058
3193
  const group = byLocation.get(v.locationId);
@@ -3061,8 +3196,8 @@ var StorageEvictableProvider = class {
3061
3196
  }
3062
3197
  let reclaimedBytes = 0;
3063
3198
  for (const [locationId, rows] of byLocation) reclaimedBytes += await this.deps.store.evict(locationId, rows);
3064
- if (reclaimedBytes > 0 && this.deps.onEvicted) this.deps.onEvicted(summarizeEvictionsByDevice(victims));
3065
- const exhausted = oldest.exhausted && victims.length >= oldest.rows.length;
3199
+ if (reclaimedBytes > 0 && this.deps.onEvicted) this.deps.onEvicted(summarizeEvictionsByDevice(victims, orphans));
3200
+ const exhausted = oldest.exhausted && ageVictims.length >= ageCandidates.length;
3066
3201
  return {
3067
3202
  reclaimedBytes,
3068
3203
  exhausted
@@ -3072,8 +3207,14 @@ var StorageEvictableProvider = class {
3072
3207
  /** Group an eviction round's victims into per-(device, location) summaries (bytes
3073
3208
  * come from the pre-delete selection — partial delete failures may overstate
3074
3209
  * slightly). A domain round can span aliased locations, so each victim is bucketed
3075
- * by its OWN `locationId` (not a single round-level location). */
3076
- function summarizeEvictionsByDevice(victims) {
3210
+ * by its OWN `locationId` (not a single round-level location).
3211
+ *
3212
+ * `orphanDeviceIds` is the round's CONFIRMED-gone set and it decides each
3213
+ * summary's {@link EvictionReason}. Required rather than defaulted: the reason
3214
+ * is what the operator reads in the activity history, and a caller that forgot
3215
+ * to pass it would file every eviction as `oldest-first` — the one wrong
3216
+ * answer nothing downstream could detect. */
3217
+ function summarizeEvictionsByDevice(victims, orphanDeviceIds) {
3077
3218
  const byKey = /* @__PURE__ */ new Map();
3078
3219
  for (const v of victims) {
3079
3220
  const key = `${v.deviceId}${v.locationId}`;
@@ -3084,11 +3225,11 @@ function summarizeEvictionsByDevice(victims) {
3084
3225
  segments: 1,
3085
3226
  bytes: v.bytes,
3086
3227
  fromMs: v.startMs,
3087
- toMs: v.startMs + v.durMs
3228
+ toMs: v.startMs + v.durMs,
3229
+ reason: orphanDeviceIds.has(v.deviceId) ? "orphaned-device" : "oldest-first"
3088
3230
  });
3089
3231
  else byKey.set(key, {
3090
- deviceId: v.deviceId,
3091
- locationId: v.locationId,
3232
+ ...cur,
3092
3233
  segments: cur.segments + 1,
3093
3234
  bytes: cur.bytes + v.bytes,
3094
3235
  fromMs: Math.min(cur.fromMs, v.startMs),
@@ -8916,6 +9057,49 @@ var SegmentHourLedger = class SegmentHourLedger {
8916
9057
  * able to say truthfully.
8917
9058
  */
8918
9059
  async oldestSegments(locationIds, targetBytes) {
9060
+ return this.oldestSegmentsScoped(locationIds, null, targetBytes);
9061
+ }
9062
+ /**
9063
+ * {@link oldestSegments}, narrowed to a set of cameras.
9064
+ *
9065
+ * The disk-pressure evictor's dead-device tier needs the oldest footage OF
9066
+ * THE CAMERAS THAT NO LONGER EXIST, which is a different question from the
9067
+ * oldest footage on the disk: an orphan's newest hour has to be reachable
9068
+ * even when a live camera holds every one of the oldest ones. The narrowing
9069
+ * is a `deviceId IN (…)` on the same statement, so it stays ONE ordered,
9070
+ * bounded, paged read and never a per-device merge.
9071
+ *
9072
+ * The device set is the CALLER's business — this method neither knows nor
9073
+ * checks what makes a device evictable. Refuses an empty set rather than
9074
+ * compiling to "every camera", for the same reason
9075
+ * {@link SegmentHourLedger.predicate} refuses an empty scope.
9076
+ */
9077
+ async oldestSegmentsForDevices(locationIds, deviceIds, targetBytes) {
9078
+ if (deviceIds.size === 0) return {
9079
+ rows: [],
9080
+ exhausted: true
9081
+ };
9082
+ return this.oldestSegmentsScoped(locationIds, [...deviceIds], targetBytes);
9083
+ }
9084
+ /**
9085
+ * Every camera the ledger holds an hour for on these locations.
9086
+ *
9087
+ * Answered from T1 — the always-resident hour summary, which carries
9088
+ * `deviceId` and `locationId` — exactly like {@link profilesWithFootage},
9089
+ * and for the same reason: this is an O(writers × days) question and it must
9090
+ * cost no I/O. It runs on the disk-pressure path, where an I/O that fails
9091
+ * would have to be turned into a verdict.
9092
+ *
9093
+ * An EMPTY answer is "the mirror knows no hour here", which is also what a
9094
+ * ledger whose load failed reports — so the caller must treat it as "decide
9095
+ * nothing", never as "no camera owns this footage".
9096
+ */
9097
+ devicesWithFootage(locationIds) {
9098
+ const out = /* @__PURE__ */ new Set();
9099
+ for (const row of this.ledger.snapshot()) if (locationIds.has(row.locationId)) out.add(row.deviceId);
9100
+ return out;
9101
+ }
9102
+ async oldestSegmentsScoped(locationIds, deviceIds, targetBytes) {
8919
9103
  const ids = [...locationIds];
8920
9104
  if (ids.length === 0 || targetBytes <= 0) return {
8921
9105
  rows: [],
@@ -8930,7 +9114,10 @@ var SegmentHourLedger = class SegmentHourLedger {
8930
9114
  collection: RECORDING_SEGMENT_HOURS_COLLECTION,
8931
9115
  columns: OLDEST_PROBE_COLUMNS,
8932
9116
  filter: {
8933
- whereIn: { locationId: ids },
9117
+ whereIn: deviceIds === null ? { locationId: ids } : {
9118
+ locationId: ids,
9119
+ deviceId: deviceIds
9120
+ },
8934
9121
  orderBy: {
8935
9122
  field: "hourStartMs",
8936
9123
  direction: "asc"
@@ -16654,15 +16841,40 @@ var RecorderV2Addon = class extends BaseAddon {
16654
16841
  store: this.segmentStore,
16655
16842
  resolveDomain: (locationId) => this.locationDomain(locationId),
16656
16843
  isReadOnly: (locationId) => this.resolvedLocations.find((l) => l.id === locationId)?.readOnly === true,
16844
+ deviceRegistry: async () => {
16845
+ try {
16846
+ const devices = await this.ctx.api.deviceManager.listAll.query({ projection: "slim" });
16847
+ return {
16848
+ status: "answered",
16849
+ deviceIds: new Set(devices.map((d) => d.id))
16850
+ };
16851
+ } catch (err) {
16852
+ return {
16853
+ status: "unanswered",
16854
+ detail: err instanceof Error ? err.message : String(err)
16855
+ };
16856
+ }
16857
+ },
16657
16858
  onEvicted: (summaries) => {
16658
16859
  for (const s of summaries) {
16860
+ const opReason = s.reason === "orphaned-device" ? "orphaned-device" : "quota";
16659
16861
  opsLog.append({
16660
16862
  op: "prune",
16661
- reason: "quota",
16863
+ reason: opReason,
16662
16864
  deviceId: s.deviceId,
16663
16865
  itemsAffected: s.segments,
16664
16866
  bytesReclaimed: s.bytes,
16665
- detail: `disk-pressure evicted [${new Date(s.fromMs).toISOString()}, ${new Date(s.toMs).toISOString()}) on ${s.locationId}`
16867
+ detail: `disk-pressure evicted [${new Date(s.fromMs).toISOString()}, ${new Date(s.toMs).toISOString()}) on ${s.locationId} — ${s.reason}`
16868
+ });
16869
+ if (s.reason === "orphaned-device") this.ctx.logger.info("recorder: disk-pressure evicted footage of a camera that no longer exists — chosen ahead of older footage of live cameras", {
16870
+ tags: { deviceId: s.deviceId },
16871
+ meta: {
16872
+ locationId: s.locationId,
16873
+ segments: s.segments,
16874
+ bytes: s.bytes,
16875
+ fromMs: s.fromMs,
16876
+ toMs: s.toMs
16877
+ }
16666
16878
  });
16667
16879
  this.ctx.eventBus.emit({
16668
16880
  id: randomUUID(),
@@ -16682,7 +16894,8 @@ var RecorderV2Addon = class extends BaseAddon {
16682
16894
  bytes: s.bytes,
16683
16895
  fromMs: s.fromMs,
16684
16896
  toMs: s.toMs,
16685
- trigger: "disk-pressure"
16897
+ trigger: "disk-pressure",
16898
+ reason: s.reason
16686
16899
  }
16687
16900
  });
16688
16901
  }
@@ -1,5 +1,5 @@
1
1
  import { r as __toESM, t as __commonJSMin } from "./chunk-DnnnRqeS.mjs";
2
- import { wt as errMsg } from "./dist-Bz00AHCy.mjs";
2
+ import { wt as errMsg } from "./dist-D58lTgkb.mjs";
3
3
  import { spawn } from "node:child_process";
4
4
  //#region ../../node_modules/mp4box/dist/mp4box.all.js
5
5
  var require_mp4box_all = /* @__PURE__ */ __commonJSMin(((exports) => {
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-15qysRyR.js");
1
+ const require_dist = require("./dist-DzDy7GQy.js");
2
2
  let node_child_process = require("node:child_process");
3
3
  //#region ../../node_modules/mp4box/dist/mp4box.all.js
4
4
  var require_mp4box_all = /* @__PURE__ */ require_dist.__commonJSMin(((exports) => {
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_worker_protocol = require("../worker-protocol-DczDySjo.js");
3
- const require_lazy_sharp = require("../lazy-sharp-CusvUEdy.js");
2
+ const require_worker_protocol = require("../worker-protocol-BSKMHGDG.js");
3
+ const require_lazy_sharp = require("../lazy-sharp-BbFUtott.js");
4
4
  //#region src/session-decode/color-conversion.ts
5
5
  /**
6
6
  * Explicit YUV→RGB colorspace/range resolution for the session-decode worker.
@@ -1,4 +1,4 @@
1
- import { i as formatNativeLeaseKnobs, n as isWorkerRequest, o as resolveNativeLeaseKnobs, r as logLevelForLine } from "../worker-protocol-B2RCeDwS.mjs";
1
+ import { i as formatNativeLeaseKnobs, n as isWorkerRequest, o as resolveNativeLeaseKnobs, r as logLevelForLine } from "../worker-protocol-l0Mqtqka.mjs";
2
2
  import { n as setSharpWarnSink, r as hostExternalEntryUrls, t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
3
3
  //#region src/session-decode/color-conversion.ts
4
4
  /**
@@ -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.55",
6
+ version: "1.2.56",
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.135",
21
+ version: "1.2.136",
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.101",
36
+ version: "1.2.102",
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-DoH8TCnt.js");
1
+ const require_segment_demux_js = require("../segment-demux-js-DQ3u40kJ.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-CmaBsM0K.mjs";
1
+ import { t as demuxSegmentFullJs } from "../segment-demux-js-6FaY07xG.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.135",
39
+ version: "1.2.136",
40
40
  scope: "default",
41
41
  shareConfig: {
42
42
  singleton: !0,
@@ -45,7 +45,7 @@ async function r() {
45
45
  }
46
46
  },
47
47
  "@camstack/sdk": {
48
- version: "1.2.55",
48
+ version: "1.2.56",
49
49
  scope: "default",
50
50
  shareConfig: {
51
51
  singleton: !0,
@@ -81,7 +81,7 @@ async function r() {
81
81
  }
82
82
  },
83
83
  "@camstack/ui-library": {
84
- version: "1.2.101",
84
+ version: "1.2.102",
85
85
  scope: "default",
86
86
  shareConfig: {
87
87
  singleton: !0,
@@ -2,12 +2,12 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-15qysRyR.js");
6
- const require_node = require("../node-BdjJPTLk.js");
5
+ const require_dist = require("../dist-DzDy7GQy.js");
6
+ const require_node = require("../node-jFu0Gq80.js");
7
7
  const require_restream_intent = require("../restream-intent-Cv9x3jmu.js");
8
8
  const require_remote_restream = require("../remote-restream-CO36Sr30.js");
9
9
  const require_retire_root_keys = require("../retire-root-keys-KE6D6Xh_.js");
10
- const require_segment_demux_js = require("../segment-demux-js-DoH8TCnt.js");
10
+ const require_segment_demux_js = require("../segment-demux-js-DQ3u40kJ.js");
11
11
  let node_crypto = require("node:crypto");
12
12
  node_crypto = require_dist.__toESM(node_crypto);
13
13
  let node_fs = require("node:fs");
@@ -1,10 +1,10 @@
1
1
  import { r as __toESM } from "../chunk-DnnnRqeS.mjs";
2
- import { $t as record, At as BOOT_RECOVERY_BACKOFF_MS, Bt as nodePin, C as RATE_CONTROL_RELAXED, Ct as webrtcSessionCapability, D as RingBuffer, Dt as buildFfmpegArgs$1, F as createHwAccelCache, Ft as createEvent, G as egressTranscodeSharingKey, Gt as _enum, Ht as parseProfileBrokerId, I as createLogChannelsProvider, Jt as discriminatedUnion, K as egressTransportFromRequest, Kt as array, Lt as isEvent, Mt as CAM_PROFILE_ORDER, N as batteryCapability, Nt as DeviceFeature, Ot as invocationFromEncodeProfile, P as cameraStreamsCapability, Pt as DeviceType, Qt as object, R as declareLogChannel, Rt as makeProfileBrokerId, Tt as AUDIO_PRESETS, V as deriveBatteryPresence, Xt as literal, Zt as number, en as string, et as loadContributionCapability, gt as resolveEgressDecodeHwAccel, h as EncodeProfileSchema, i as BatteryStatusSchema, jt as BaseAddon, k as addonWidgetsSourceCapability, kt as isSoftwareDecode, nn as EventCategory, qt as boolean, rt as maskUrlCredentials, tn as union, tt as logChannelsCapability, w as RATE_CONTROL_TIGHT, wt as errMsg, xt as streamBrokerCapability, zt as makeSourceBrokerId } from "../dist-Bz00AHCy.mjs";
3
- import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-CpW6WY9n.mjs";
2
+ import { $t as record, At as BOOT_RECOVERY_BACKOFF_MS, Bt as nodePin, C as RATE_CONTROL_RELAXED, Ct as webrtcSessionCapability, D as RingBuffer, Dt as buildFfmpegArgs$1, F as createHwAccelCache, Ft as createEvent, G as egressTranscodeSharingKey, Gt as _enum, Ht as parseProfileBrokerId, I as createLogChannelsProvider, Jt as discriminatedUnion, K as egressTransportFromRequest, Kt as array, Lt as isEvent, Mt as CAM_PROFILE_ORDER, N as batteryCapability, Nt as DeviceFeature, Ot as invocationFromEncodeProfile, P as cameraStreamsCapability, Pt as DeviceType, Qt as object, R as declareLogChannel, Rt as makeProfileBrokerId, Tt as AUDIO_PRESETS, V as deriveBatteryPresence, Xt as literal, Zt as number, en as string, et as loadContributionCapability, gt as resolveEgressDecodeHwAccel, h as EncodeProfileSchema, i as BatteryStatusSchema, jt as BaseAddon, k as addonWidgetsSourceCapability, kt as isSoftwareDecode, nn as EventCategory, qt as boolean, rt as maskUrlCredentials, tn as union, tt as logChannelsCapability, w as RATE_CONTROL_TIGHT, wt as errMsg, xt as streamBrokerCapability, zt as makeSourceBrokerId } from "../dist-D58lTgkb.mjs";
3
+ import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-CLOpRiqg.mjs";
4
4
  import { t as parseRestreamPath } from "../restream-intent-B4BXZra7.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-DMolfhsP.mjs";
7
- import { i as require_mp4box_all, n as demuxSegmentPreferJs, r as runFfmpegOnce, t as demuxSegmentFullJs } from "../segment-demux-js-CmaBsM0K.mjs";
7
+ import { i as require_mp4box_all, n as demuxSegmentPreferJs, r as runFfmpegOnce, t as demuxSegmentFullJs } from "../segment-demux-js-6FaY07xG.mjs";
8
8
  import { createRequire } from "node:module";
9
9
  import * as crypto$1 from "node:crypto";
10
10
  import crypto, { createHash, randomBytes, randomUUID } from "node:crypto";
@@ -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-BtUtinHp.mjs")).catch((e) => {
33
+ return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DuGUF2qi.mjs")).catch((e) => {
34
34
  throw l = void 0, e;
35
35
  }), l;
36
36
  }
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-15qysRyR.js");
1
+ const require_dist = require("./dist-DzDy7GQy.js");
2
2
  //#region src/session-decode/native-lease-config.ts
3
3
  /**
4
4
  * Resolution of the native-frame hold / tile knobs for one decode worker.
@@ -1,4 +1,4 @@
1
- import { b as NativeLeaseSettingsSchema, p as DEFAULT_NATIVE_LEASE_SETTINGS, y as NativeLeaseAdmissionSchema } from "./dist-Bz00AHCy.mjs";
1
+ import { b as NativeLeaseSettingsSchema, p as DEFAULT_NATIVE_LEASE_SETTINGS, y as NativeLeaseAdmissionSchema } from "./dist-D58lTgkb.mjs";
2
2
  //#region src/session-decode/native-lease-config.ts
3
3
  /**
4
4
  * Resolution of the native-frame hold / tile knobs for one decode worker.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-pipeline",
3
- "version": "1.2.164",
3
+ "version": "1.2.166",
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",