@camstack/addon-pipeline 1.2.96 → 1.2.98

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 (31) hide show
  1. package/dist/{addon-utils-B6usm-YO.js → addon-utils-eUS6n_Zj.js} +1 -1
  2. package/dist/audio-analyzer/index.js +3 -3
  3. package/dist/audio-analyzer/index.mjs +2 -2
  4. package/dist/detection-pipeline/index.js +5 -5
  5. package/dist/detection-pipeline/index.mjs +3 -3
  6. package/dist/{dist-w9QWDvWn.js → dist-dm3t4BOt.js} +29 -3
  7. package/dist/{dist-LIWfUNC_.mjs → dist-gXdWP96z.mjs} +29 -3
  8. package/dist/{event-loop-stall-monitor-DndI0S2s.js → event-loop-stall-monitor-Lki2_mYY.js} +1 -1
  9. package/dist/{event-loop-stall-monitor-BDC8qURn.mjs → event-loop-stall-monitor-TnQ21mu0.mjs} +1 -1
  10. package/dist/{lazy-sharp-BVqBydNU.js → lazy-sharp-oYppDIZR.js} +1 -1
  11. package/dist/motion-wasm/index.js +2 -2
  12. package/dist/motion-wasm/index.mjs +1 -1
  13. package/dist/pipeline-runner/index.js +51 -4
  14. package/dist/pipeline-runner/index.mjs +50 -3
  15. package/dist/{process-memory-k45KJaKH.mjs → process-memory-CKWh609B.mjs} +1 -1
  16. package/dist/{process-memory-C6zWIgos.js → process-memory-vkFVOdkV.js} +1 -1
  17. package/dist/recorder/index.js +296 -48
  18. package/dist/recorder/index.mjs +295 -47
  19. package/dist/session-decode/decode-worker-child.js +2 -2
  20. package/dist/session-decode/decode-worker-child.mjs +1 -1
  21. package/dist/stream-broker/_stub.js +1 -1
  22. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CJWMZMhQ.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-B7ERJocD.mjs} +3 -3
  23. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-zT-cYUdF.mjs +26 -0
  24. package/dist/stream-broker/{hostInit-CGIo3d4K.mjs → hostInit-Cm2rl8-e.mjs} +3 -3
  25. package/dist/stream-broker/index.js +21 -6
  26. package/dist/stream-broker/index.mjs +21 -6
  27. package/dist/stream-broker/remoteEntry.js +1 -1
  28. package/dist/{worker-protocol-DqrXmX0g.js → worker-protocol-BrlrMxXu.js} +1 -1
  29. package/dist/{worker-protocol-DTe7Ntat.mjs → worker-protocol-DJWdPLKF.mjs} +1 -1
  30. package/package.json +1 -1
  31. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D2WOTeYi.mjs +0 -26
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-w9QWDvWn.js");
1
+ const require_dist = require("./dist-dm3t4BOt.js");
2
2
  require("node:crypto");
3
3
  let node_path = require("node:path");
4
4
  node_path = require_dist.__toESM(node_path, 1);
@@ -2,9 +2,9 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-w9QWDvWn.js");
6
- const require_process_memory = require("../process-memory-C6zWIgos.js");
7
- const require_addon_utils = require("../addon-utils-B6usm-YO.js");
5
+ const require_dist = require("../dist-dm3t4BOt.js");
6
+ const require_process_memory = require("../process-memory-vkFVOdkV.js");
7
+ const require_addon_utils = require("../addon-utils-eUS6n_Zj.js");
8
8
  let node_path = require("node:path");
9
9
  node_path = require_dist.__toESM(node_path);
10
10
  let node_fs = require("node:fs");
@@ -1,6 +1,6 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { D as audioAnalysisCapability, O as audioAnalyzerCapability, W as mapAudioLabelToMacro, ct as errMsg, h as HF_BASE_URL, mt as BaseAddon, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG, tt as resolvePoolMemoryPolicy, y as PoolMemoryWatchdog, yt as hydrateSchema } from "../dist-LIWfUNC_.mjs";
3
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-k45KJaKH.mjs";
2
+ import { D as audioAnalysisCapability, O as audioAnalyzerCapability, W as mapAudioLabelToMacro, ct as errMsg, h as HF_BASE_URL, mt as BaseAddon, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG, tt as resolvePoolMemoryPolicy, y as PoolMemoryWatchdog, yt as hydrateSchema } from "../dist-gXdWP96z.mjs";
3
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-CKWh609B.mjs";
4
4
  import { i as downloadFile } from "../addon-utils-A2S9D7pu.mjs";
5
5
  import * as path$1 from "node:path";
6
6
  import * as fs from "node:fs";
@@ -2,11 +2,11 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-w9QWDvWn.js");
6
- const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DndI0S2s.js");
7
- const require_lazy_sharp = require("../lazy-sharp-BVqBydNU.js");
8
- const require_process_memory = require("../process-memory-C6zWIgos.js");
9
- const require_addon_utils = require("../addon-utils-B6usm-YO.js");
5
+ const require_dist = require("../dist-dm3t4BOt.js");
6
+ const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-Lki2_mYY.js");
7
+ const require_lazy_sharp = require("../lazy-sharp-oYppDIZR.js");
8
+ const require_process_memory = require("../process-memory-vkFVOdkV.js");
9
+ const require_addon_utils = require("../addon-utils-eUS6n_Zj.js");
10
10
  let sharp = require("sharp");
11
11
  sharp = require_dist.__toESM(sharp);
12
12
  let node_child_process = require("node:child_process");
@@ -1,8 +1,8 @@
1
1
  import { n as __require } from "../chunk-DnnnRqeS.mjs";
2
- import { Ct as nodePin, Dt as sleep, Ft as object, H as evaluateZoneRules, Lt as string, N as defaultDeviceFor$1, R as detectionPipelineCapability, Rt as union, T as YAMNET_TO_MACRO, V as enumerateInferenceDevices, X as pipelineExecutorCapability, ct as errMsg, d as DEVICE_BACKEND_TO_FORMAT, kt as array, mt as BaseAddon, ot as supportedRuntimes$1, rt as runtimeDevices$1, t as APPLE_SA_TO_MACRO, tt as resolvePoolMemoryPolicy, vt as createEvent, wt as parseJsonUnknown, y as PoolMemoryWatchdog, yt as hydrateSchema, zt as EventCategory } from "../dist-LIWfUNC_.mjs";
3
- import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, n as startEventLoopStallMonitor, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep } from "../event-loop-stall-monitor-BDC8qURn.mjs";
2
+ import { Ct as nodePin, Dt as sleep, Ft as object, H as evaluateZoneRules, Lt as string, N as defaultDeviceFor$1, R as detectionPipelineCapability, Rt as union, T as YAMNET_TO_MACRO, V as enumerateInferenceDevices, X as pipelineExecutorCapability, ct as errMsg, d as DEVICE_BACKEND_TO_FORMAT, kt as array, mt as BaseAddon, ot as supportedRuntimes$1, rt as runtimeDevices$1, t as APPLE_SA_TO_MACRO, tt as resolvePoolMemoryPolicy, vt as createEvent, wt as parseJsonUnknown, y as PoolMemoryWatchdog, yt as hydrateSchema, zt as EventCategory } from "../dist-gXdWP96z.mjs";
3
+ import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, n as startEventLoopStallMonitor, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep } from "../event-loop-stall-monitor-TnQ21mu0.mjs";
4
4
  import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
5
- import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-k45KJaKH.mjs";
5
+ import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-CKWh609B.mjs";
6
6
  import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../addon-utils-A2S9D7pu.mjs";
7
7
  import sharp from "sharp";
8
8
  import { spawn } from "node:child_process";
@@ -26519,9 +26519,21 @@ var RecordingLocationUsageSchema = object({
26519
26519
  * previously rendered as two identical "disks" with a nonsensical used
26520
26520
  * split — hydrate attribution across aliases is arbitrary by nature. */
26521
26521
  locationIds: array(string()).optional(),
26522
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
26522
+ /**
26523
+ * Filesystem root of the physical volume this row accounts — the only
26524
+ * operator-legible identity when a location has no `displayName` yet, and
26525
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
26526
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
26527
+ * it, and this schema must keep validating that older provider's payload.
26528
+ */
26529
+ root: string().optional(),
26530
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
26531
+ * the footage's SHARE of the volume, not how full the volume is — the disk
26532
+ * also holds everything that is not recordings. Volume fill is
26533
+ * `(totalBytes - availableBytes) / totalBytes`. */
26523
26534
  usedBytes: number(),
26524
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
26535
+ /** Free bytes on the location's volume; null when capacity is unknown
26536
+ * (remote/unstattable — the recorder logs the statfs failure with the root). */
26525
26537
  availableBytes: number().nullable(),
26526
26538
  /** Total bytes of the location's volume; null when unknown. */
26527
26539
  totalBytes: number().nullable()
@@ -26533,7 +26545,15 @@ var RecordingStorageUsageSchema = object({
26533
26545
  nodeId: string(),
26534
26546
  totalUsedBytes: number(),
26535
26547
  devices: array(RecordingDeviceUsageSchema),
26536
- locations: array(RecordingLocationUsageSchema)
26548
+ /**
26549
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
26550
+ * of the payload without it: the hub serves this method through a BAKED
26551
+ * router, so a hub whose framework train predates a change to this array
26552
+ * strips it out of an answer a newer recorder happily produced. A UI that
26553
+ * dereferences it unconditionally crashes the whole Storage page over a
26554
+ * missing disk bar.
26555
+ */
26556
+ locations: array(RecordingLocationUsageSchema).optional()
26537
26557
  });
26538
26558
  /**
26539
26559
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -35821,8 +35841,14 @@ Object.freeze({
35821
35841
  "network-access": "ingress",
35822
35842
  "smtp-provider": "email"
35823
35843
  });
35844
+ /** Schema defaults — an untouched sub-field must author exactly these. */
35845
+ var NC_AUDIO_DEFAULTS = {
35846
+ hitPercent: 60,
35847
+ samplingSeconds: 10
35848
+ };
35824
35849
  new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
35825
35850
  new Set(["devices", "classes"]);
35851
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
35826
35852
  /**
35827
35853
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
35828
35854
  *
@@ -26496,9 +26496,21 @@ var RecordingLocationUsageSchema = object({
26496
26496
  * previously rendered as two identical "disks" with a nonsensical used
26497
26497
  * split — hydrate attribution across aliases is arbitrary by nature. */
26498
26498
  locationIds: array(string()).optional(),
26499
- /** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
26499
+ /**
26500
+ * Filesystem root of the physical volume this row accounts — the only
26501
+ * operator-legible identity when a location has no `displayName` yet, and
26502
+ * what a "which disk is full" alert has to name. OPTIONAL for the same
26503
+ * train-skew reason as `oldestMs`: a recorder that predates the field omits
26504
+ * it, and this schema must keep validating that older provider's payload.
26505
+ */
26506
+ root: string().optional(),
26507
+ /** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
26508
+ * the footage's SHARE of the volume, not how full the volume is — the disk
26509
+ * also holds everything that is not recordings. Volume fill is
26510
+ * `(totalBytes - availableBytes) / totalBytes`. */
26500
26511
  usedBytes: number(),
26501
- /** Free bytes on the location's volume; null when capacity is unknown (remote). */
26512
+ /** Free bytes on the location's volume; null when capacity is unknown
26513
+ * (remote/unstattable — the recorder logs the statfs failure with the root). */
26502
26514
  availableBytes: number().nullable(),
26503
26515
  /** Total bytes of the location's volume; null when unknown. */
26504
26516
  totalBytes: number().nullable()
@@ -26510,7 +26522,15 @@ var RecordingStorageUsageSchema = object({
26510
26522
  nodeId: string(),
26511
26523
  totalUsedBytes: number(),
26512
26524
  devices: array(RecordingDeviceUsageSchema),
26513
- locations: array(RecordingLocationUsageSchema)
26525
+ /**
26526
+ * Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
26527
+ * of the payload without it: the hub serves this method through a BAKED
26528
+ * router, so a hub whose framework train predates a change to this array
26529
+ * strips it out of an answer a newer recorder happily produced. A UI that
26530
+ * dereferences it unconditionally crashes the whole Storage page over a
26531
+ * missing disk bar.
26532
+ */
26533
+ locations: array(RecordingLocationUsageSchema).optional()
26514
26534
  });
26515
26535
  /**
26516
26536
  * The OPERATOR-ARMED half of multi-location recordings (D116).
@@ -35798,8 +35818,14 @@ Object.freeze({
35798
35818
  "network-access": "ingress",
35799
35819
  "smtp-provider": "email"
35800
35820
  });
35821
+ /** Schema defaults — an untouched sub-field must author exactly these. */
35822
+ var NC_AUDIO_DEFAULTS = {
35823
+ hitPercent: 60,
35824
+ samplingSeconds: 10
35825
+ };
35801
35826
  new Map(AUDIO_MACRO_LABELS.flatMap((macro) => macro.icon === void 0 ? [] : [[macro.id, macro.icon]]));
35802
35827
  new Set(["devices", "classes"]);
35828
+ NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
35803
35829
  /**
35804
35830
  * TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
35805
35831
  *
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-w9QWDvWn.js");
1
+ const require_dist = require("./dist-dm3t4BOt.js");
2
2
  let node_perf_hooks = require("node:perf_hooks");
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -1,4 +1,4 @@
1
- import { U as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-LIWfUNC_.mjs";
1
+ import { U as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-gXdWP96z.mjs";
2
2
  import { PerformanceObserver } from "node:perf_hooks";
3
3
  //#region src/detection-pipeline/registry/model-catalogs.ts
4
4
  var HF_REPO = "camstack/camstack-models";
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-w9QWDvWn.js");
1
+ const require_dist = require("./dist-dm3t4BOt.js");
2
2
  let node_url = require("node:url");
3
3
  let node_module = require("node:module");
4
4
  let node_path = require("node:path");
@@ -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-w9QWDvWn.js");
6
- const require_lazy_sharp = require("../lazy-sharp-BVqBydNU.js");
5
+ const require_dist = require("../dist-dm3t4BOt.js");
6
+ const require_lazy_sharp = require("../lazy-sharp-oYppDIZR.js");
7
7
  let node_path = require("node:path");
8
8
  let node_fs = require("node:fs");
9
9
  //#region src/motion-wasm/wasm-motion-detector.ts
@@ -1,4 +1,4 @@
1
- import { H as evaluateZoneRules, K as motionDetectionCapability, _t as DeviceType, mt as BaseAddon, yt as hydrateSchema } from "../dist-LIWfUNC_.mjs";
1
+ import { H as evaluateZoneRules, K as motionDetectionCapability, _t as DeviceType, mt as BaseAddon, yt as hydrateSchema } from "../dist-gXdWP96z.mjs";
2
2
  import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
3
3
  import { join } from "node:path";
4
4
  import { readFileSync } from "node:fs";
@@ -2,11 +2,11 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-w9QWDvWn.js");
6
- const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-DndI0S2s.js");
7
- const require_worker_protocol = require("../worker-protocol-DqrXmX0g.js");
5
+ const require_dist = require("../dist-dm3t4BOt.js");
6
+ const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-Lki2_mYY.js");
7
+ const require_worker_protocol = require("../worker-protocol-BrlrMxXu.js");
8
8
  const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
9
- const require_lazy_sharp = require("../lazy-sharp-BVqBydNU.js");
9
+ const require_lazy_sharp = require("../lazy-sharp-oYppDIZR.js");
10
10
  const require_remote_restream = require("../remote-restream-BYbAsgUf.js");
11
11
  let sharp = require("sharp");
12
12
  sharp = require_dist.__toESM(sharp);
@@ -1372,6 +1372,19 @@ var CapacityRampStatusSchema = require_dist.object({
1372
1372
  result: RunCapacityRampResultSchema.optional(),
1373
1373
  error: require_dist.string().optional()
1374
1374
  });
1375
+ /**
1376
+ * `z.object({})`, never `z.void()`: the `addons.custom` envelope insists on
1377
+ * an `input` object and a `z.void()` schema rejects `{}` — such an action
1378
+ * resolves and can never be called, from a button or from `hub.mjs`.
1379
+ */
1380
+ var ListCapacityRampsInputSchema = require_dist.object({});
1381
+ var CapacityRampOverviewSchema = require_dist.object({
1382
+ nodeId: require_dist.string(),
1383
+ maxHistory: require_dist.number().int().min(0),
1384
+ quiet: require_dist.boolean(),
1385
+ busyCameras: require_dist.array(require_dist.number()).readonly(),
1386
+ runs: require_dist.array(CapacityRampStatusSchema).readonly()
1387
+ });
1375
1388
  //#endregion
1376
1389
  //#region src/pipeline-runner/bench-actions.ts
1377
1390
  /**
@@ -1464,6 +1477,16 @@ var pipelineRunnerBenchActions = require_dist.defineCustomActions({
1464
1477
  */
1465
1478
  runCapacityRamp: require_dist.customAction(RunCapacityRampInputSchema, RunCapacityRampAcceptedSchema, { kind: "mutation" }),
1466
1479
  getCapacityRampStatus: require_dist.customAction(GetCapacityRampStatusInputSchema, CapacityRampStatusSchema),
1480
+ /**
1481
+ * Which node am I, is it quiet, and what ramps does it know about?
1482
+ *
1483
+ * `getCapacityRampStatus` needs a sessionId and throws without one, which
1484
+ * is fine for a script and useless for a page: a ramp outlives the tab that
1485
+ * started it, and the node then refuses a second one. This makes recovery,
1486
+ * the node assertion and the quiet-node precondition READABLE instead of
1487
+ * discovered through a rejection string. Read-only — no `kind: 'mutation'`.
1488
+ */
1489
+ listCapacityRamps: require_dist.customAction(ListCapacityRampsInputSchema, CapacityRampOverviewSchema),
1467
1490
  abortCapacityRamp: require_dist.customAction(AbortCapacityRampInputSchema, AbortCapacityRampResultSchema, { kind: "mutation" })
1468
1491
  });
1469
1492
  //#endregion
@@ -4726,6 +4749,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
4726
4749
  runSyntheticBench: async (input) => this.runSyntheticBench(input),
4727
4750
  runCapacityRamp: async (input) => this.runCapacityRampAction(input),
4728
4751
  getCapacityRampStatus: async (input) => this.getCapacityRampStatusAction(input),
4752
+ listCapacityRamps: async () => this.listCapacityRampsAction(),
4729
4753
  abortCapacityRamp: async (input) => this.abortCapacityRampAction(input)
4730
4754
  }
4731
4755
  };
@@ -5397,6 +5421,29 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
5397
5421
  if (!entry) throw new Error(`getCapacityRampStatus: unknown sessionId '${input.sessionId}' (only the last ${PipelineRunnerAddon.MAX_CAPACITY_RUN_HISTORY} runs are kept)`);
5398
5422
  return entry.status;
5399
5423
  }
5424
+ /**
5425
+ * The node, its quiet state and every ramp this runner still remembers.
5426
+ *
5427
+ * A caller holding a sessionId uses `getCapacityRampStatus`; a caller that
5428
+ * has just been opened (a page reloaded mid-ramp, a fresh shell) has no id
5429
+ * at all, and the ramp it needs to watch or stop may have another 40
5430
+ * minutes to run. Without this the only recovery path is parsing the
5431
+ * "already running" rejection for the id it names.
5432
+ *
5433
+ * `nodeId` is this runner answering about itself — the ramp is node-local
5434
+ * and `addons.custom` reaches exactly one runner, so a caller that wanted
5435
+ * another node can refuse instead of attributing this one's number to it.
5436
+ */
5437
+ async listCapacityRampsAction() {
5438
+ const busy = (this.runner?.getAllCameraMetrics() ?? []).filter((m) => m.phase !== "idle");
5439
+ return {
5440
+ nodeId: this.nodeId,
5441
+ maxHistory: PipelineRunnerAddon.MAX_CAPACITY_RUN_HISTORY,
5442
+ quiet: busy.length === 0,
5443
+ busyCameras: busy.map((m) => m.deviceId),
5444
+ runs: [...this.capacityRuns.values()].map((entry) => entry.status)
5445
+ };
5446
+ }
5400
5447
  async abortCapacityRampAction(input) {
5401
5448
  const entry = this.capacityRuns.get(input.sessionId);
5402
5449
  if (!entry || entry.status.state !== "running") return { aborted: false };
@@ -1,6 +1,6 @@
1
- import { At as boolean, Ct as nodePin, Ft as object, I as deriveDetailCropRect, J as pickDetailCropConvention, Lt as string, M as customAction, Mt as lazy, Nt as literal, Ot as _enum, P as defineCustomActions, Pt as number, Y as pickNativeLeaseOverride, Z as pipelineRunnerCapability, c as DEFAULT_DETAIL_CROP_CONVENTION, ct as errMsg, d as DEVICE_BACKEND_TO_FORMAT, kt as array, mt as BaseAddon, vt as createEvent, zt as EventCategory } from "../dist-LIWfUNC_.mjs";
2
- import { c as getStepDefinition, t as attributeStall } from "../event-loop-stall-monitor-BDC8qURn.mjs";
3
- import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-DTe7Ntat.mjs";
1
+ import { At as boolean, Ct as nodePin, Ft as object, I as deriveDetailCropRect, J as pickDetailCropConvention, Lt as string, M as customAction, Mt as lazy, Nt as literal, Ot as _enum, P as defineCustomActions, Pt as number, Y as pickNativeLeaseOverride, Z as pipelineRunnerCapability, c as DEFAULT_DETAIL_CROP_CONVENTION, ct as errMsg, d as DEVICE_BACKEND_TO_FORMAT, kt as array, mt as BaseAddon, vt as createEvent, zt as EventCategory } from "../dist-gXdWP96z.mjs";
2
+ import { c as getStepDefinition, t as attributeStall } from "../event-loop-stall-monitor-TnQ21mu0.mjs";
3
+ import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-DJWdPLKF.mjs";
4
4
  import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
5
5
  import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
6
6
  import { i as withDetectionIntent, n as profileForStreamId, t as isRemoteRestream } from "../remote-restream-Ci7RXNGb.mjs";
@@ -1365,6 +1365,19 @@ var CapacityRampStatusSchema = object({
1365
1365
  result: RunCapacityRampResultSchema.optional(),
1366
1366
  error: string().optional()
1367
1367
  });
1368
+ /**
1369
+ * `z.object({})`, never `z.void()`: the `addons.custom` envelope insists on
1370
+ * an `input` object and a `z.void()` schema rejects `{}` — such an action
1371
+ * resolves and can never be called, from a button or from `hub.mjs`.
1372
+ */
1373
+ var ListCapacityRampsInputSchema = object({});
1374
+ var CapacityRampOverviewSchema = object({
1375
+ nodeId: string(),
1376
+ maxHistory: number().int().min(0),
1377
+ quiet: boolean(),
1378
+ busyCameras: array(number()).readonly(),
1379
+ runs: array(CapacityRampStatusSchema).readonly()
1380
+ });
1368
1381
  //#endregion
1369
1382
  //#region src/pipeline-runner/bench-actions.ts
1370
1383
  /**
@@ -1457,6 +1470,16 @@ var pipelineRunnerBenchActions = defineCustomActions({
1457
1470
  */
1458
1471
  runCapacityRamp: customAction(RunCapacityRampInputSchema, RunCapacityRampAcceptedSchema, { kind: "mutation" }),
1459
1472
  getCapacityRampStatus: customAction(GetCapacityRampStatusInputSchema, CapacityRampStatusSchema),
1473
+ /**
1474
+ * Which node am I, is it quiet, and what ramps does it know about?
1475
+ *
1476
+ * `getCapacityRampStatus` needs a sessionId and throws without one, which
1477
+ * is fine for a script and useless for a page: a ramp outlives the tab that
1478
+ * started it, and the node then refuses a second one. This makes recovery,
1479
+ * the node assertion and the quiet-node precondition READABLE instead of
1480
+ * discovered through a rejection string. Read-only — no `kind: 'mutation'`.
1481
+ */
1482
+ listCapacityRamps: customAction(ListCapacityRampsInputSchema, CapacityRampOverviewSchema),
1460
1483
  abortCapacityRamp: customAction(AbortCapacityRampInputSchema, AbortCapacityRampResultSchema, { kind: "mutation" })
1461
1484
  });
1462
1485
  //#endregion
@@ -4719,6 +4742,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
4719
4742
  runSyntheticBench: async (input) => this.runSyntheticBench(input),
4720
4743
  runCapacityRamp: async (input) => this.runCapacityRampAction(input),
4721
4744
  getCapacityRampStatus: async (input) => this.getCapacityRampStatusAction(input),
4745
+ listCapacityRamps: async () => this.listCapacityRampsAction(),
4722
4746
  abortCapacityRamp: async (input) => this.abortCapacityRampAction(input)
4723
4747
  }
4724
4748
  };
@@ -5390,6 +5414,29 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
5390
5414
  if (!entry) throw new Error(`getCapacityRampStatus: unknown sessionId '${input.sessionId}' (only the last ${PipelineRunnerAddon.MAX_CAPACITY_RUN_HISTORY} runs are kept)`);
5391
5415
  return entry.status;
5392
5416
  }
5417
+ /**
5418
+ * The node, its quiet state and every ramp this runner still remembers.
5419
+ *
5420
+ * A caller holding a sessionId uses `getCapacityRampStatus`; a caller that
5421
+ * has just been opened (a page reloaded mid-ramp, a fresh shell) has no id
5422
+ * at all, and the ramp it needs to watch or stop may have another 40
5423
+ * minutes to run. Without this the only recovery path is parsing the
5424
+ * "already running" rejection for the id it names.
5425
+ *
5426
+ * `nodeId` is this runner answering about itself — the ramp is node-local
5427
+ * and `addons.custom` reaches exactly one runner, so a caller that wanted
5428
+ * another node can refuse instead of attributing this one's number to it.
5429
+ */
5430
+ async listCapacityRampsAction() {
5431
+ const busy = (this.runner?.getAllCameraMetrics() ?? []).filter((m) => m.phase !== "idle");
5432
+ return {
5433
+ nodeId: this.nodeId,
5434
+ maxHistory: PipelineRunnerAddon.MAX_CAPACITY_RUN_HISTORY,
5435
+ quiet: busy.length === 0,
5436
+ busyCameras: busy.map((m) => m.deviceId),
5437
+ runs: [...this.capacityRuns.values()].map((entry) => entry.status)
5438
+ };
5439
+ }
5393
5440
  async abortCapacityRampAction(input) {
5394
5441
  const entry = this.capacityRuns.get(input.sessionId);
5395
5442
  if (!entry || entry.status.state !== "running") return { aborted: false };
@@ -1,4 +1,4 @@
1
- import { q as parseProcStatus } from "./dist-LIWfUNC_.mjs";
1
+ import { q as parseProcStatus } from "./dist-gXdWP96z.mjs";
2
2
  import { execFile } from "node:child_process";
3
3
  import * as fs from "node:fs";
4
4
  //#region src/shared/node-topology-platform.ts
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-w9QWDvWn.js");
1
+ const require_dist = require("./dist-dm3t4BOt.js");
2
2
  let node_child_process = require("node:child_process");
3
3
  let node_fs = require("node:fs");
4
4
  node_fs = require_dist.__toESM(node_fs);