@camstack/addon-mqtt-broker 1.2.118 → 1.2.120

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.
@@ -44,7 +44,7 @@ let crypto$10 = __toESM(crypto$1, 1);
44
44
  crypto$1 = __toESM(crypto$1);
45
45
  let node_fs = require("node:fs");
46
46
  let node_path = require("node:path");
47
- //#region ../types/dist/event-category-BGmz_oxW.mjs
47
+ //#region ../types/dist/event-category-B_0XEcLF.mjs
48
48
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
49
49
  EventCategory["SystemBoot"] = "system.boot";
50
50
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -545,15 +545,6 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
545
545
  EventCategory["AgentWsDisconnected"] = "agent.ws.disconnected";
546
546
  EventCategory["AgentBackupActivated"] = "agent.backup.activated";
547
547
  EventCategory["OrchestrationSettingsUpdated"] = "orchestration.settings-updated";
548
- /**
549
- * Per-agent hwaccel preference changed (user override set, cleared, or
550
- * re-probed). Observability event — decoders pull the current pref at
551
- * `createSession`, so running sessions keep their current backend until
552
- * they rotate naturally (camera add/remove, stream restart). Future
553
- * work can wire a listener in stream-broker that force-rotates live
554
- * sessions; for now this event powers logs + admin-UI toast feedback.
555
- */
556
- EventCategory["PipelineAgentHwaccelChanged"] = "pipeline.agent-hwaccel-changed";
557
548
  EventCategory["MotionAnalysis"] = "detection.motion-analysis";
558
549
  /** All raw motion zones from CCL before minArea filter — for UI debug overlay. */
559
550
  EventCategory["MotionZonesRaw"] = "detection.motion-zones-raw";
@@ -5424,7 +5415,7 @@ var ZodIssueCode = {
5424
5415
  var ZodFirstPartyTypeKind;
5425
5416
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5426
5417
  //#endregion
5427
- //#region ../types/dist/sleep-DXKLNFvA.mjs
5418
+ //#region ../types/dist/sleep-BNeXenvr.mjs
5428
5419
  /**
5429
5420
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5430
5421
  * window to float samples (D455).
@@ -6790,32 +6781,12 @@ object({
6790
6781
  audioCodec: string().optional(),
6791
6782
  metadata: record(string(), unknown()).readonly().optional()
6792
6783
  });
6793
- var EncodedPacketSchema = object({
6794
- type: _enum(["video", "audio"]),
6795
- data: _instanceof(Uint8Array),
6796
- pts: number(),
6797
- dts: number(),
6798
- keyframe: boolean(),
6799
- codec: string()
6800
- });
6801
- var DecodedFrameSchema = object({
6802
- data: _instanceof(Uint8Array),
6803
- width: number(),
6804
- height: number(),
6805
- format: _enum([
6806
- "jpeg",
6807
- "rgb",
6808
- "bgr",
6809
- "yuv420",
6810
- "gray"
6811
- ]),
6812
- timestamp: number()
6813
- });
6814
6784
  /**
6815
6785
  * Wire schema for `FrameHandle` — a zero-pixel, serialisable reference to a
6816
6786
  * frame in a shared-memory ring (Phase 5 / D9). Mirrors the `FrameHandle` TS
6817
- * interface in `interfaces/frame-handle.ts` field-for-field so a decoder cap
6818
- * method (`pullHandles`) can carry handles over tRPC / Moleculer.
6787
+ * interface in `interfaces/frame-handle.ts` field-for-field so a cap method
6788
+ * (the runner's native-crop and pipeline-executor inputs) can carry handles
6789
+ * over tRPC / Moleculer.
6819
6790
  *
6820
6791
  * The `satisfies` assertion below pins this schema to the interface: if a
6821
6792
  * field is added to / removed from `FrameHandle` without a matching schema
@@ -6841,50 +6812,6 @@ var FrameHandleSchema = object({
6841
6812
  slotCount: number().int().positive()
6842
6813
  });
6843
6814
  /**
6844
- * Pixel format a frame-handle subscriber can request from the broker
6845
- * (Phase 5 / D9). The packed, raster subset of `FrameFormat` — the formats a
6846
- * `frameSink: 'shm'` decoder session can write into a `FrameRing` slot.
6847
- * `jpeg` is excluded: a variable-length stream is not a fixed-stride ring
6848
- * payload, and no decoded-frame consumer requests it over the shm plane.
6849
- */
6850
- var FrameHandleFormatSchema = _enum([
6851
- "rgb",
6852
- "bgr",
6853
- "yuv420",
6854
- "gray"
6855
- ]);
6856
- /**
6857
- * Input for `stream-broker.subscribeFrames` (Phase 5 / D9). A consumer asks the
6858
- * broker for a `FrameHandle` stream of one `format`; the broker maintains one
6859
- * shared-memory ring per `(brokerId, format)` actually requested, so a `gray`
6860
- * subscriber (motion) and an `rgb` subscriber (detection) each read the format
6861
- * they asked for with no broker-side conversion.
6862
- */
6863
- var SubscribeFramesInputSchema = object({
6864
- brokerId: string(),
6865
- format: FrameHandleFormatSchema,
6866
- /**
6867
- * Optional reader-side cadence hint in frames per second. The broker does
6868
- * NOT throttle — latest-wins ring reads drop frames implicitly for a slow
6869
- * consumer. The value is echoed back in `SubscribeFramesResult.maxFps` so
6870
- * the consumer can pace its own `pullFrameHandles` polling.
6871
- */
6872
- maxFps: number().positive().optional(),
6873
- /** Short caller-identity tag (`motion`, `detection`, …) for diagnostics. */
6874
- tag: string().optional()
6875
- });
6876
- /**
6877
- * Result of `stream-broker.subscribeFrames`. The consumer then polls
6878
- * `pullFrameHandles({ subscriptionId, maxCount })` and feeds each returned
6879
- * `FrameHandle` to a `FrameRingReader`.
6880
- */
6881
- var SubscribeFramesResultSchema = object({
6882
- /** Opaque id the consumer passes to `pullFrameHandles` / `unsubscribeFrames`. */
6883
- subscriptionId: string(),
6884
- /** Reader-side cadence hint (frames/s) — echoes `SubscribeFramesInput.maxFps`. */
6885
- maxFps: number().nonnegative()
6886
- });
6887
- /**
6888
6815
  * Wire schema for a decoded audio chunk (Phase 5 / D9). Mirrors the
6889
6816
  * `DecodedAudioChunk` TS interface in `interfaces/stream-broker.ts`: PCM
6890
6817
  * sample bytes plus the track parameters a consumer needs to interpret them.
@@ -6892,8 +6819,8 @@ var SubscribeFramesResultSchema = object({
6892
6819
  * Audio chunks are tiny (a ~500ms AudioCodecSession window is a few KB of
6893
6820
  * Float32 PCM), so unlike video frames they ship their bytes INLINE over
6894
6821
  * tRPC / Moleculer — no shared-memory plane. `data` is typed `Uint8Array`
6895
- * (the wire-serialisable supertype of `Buffer`) to match `DecodedFrameSchema`
6896
- * / `EncodedPacketSchema`'s precedent; a `Buffer` is assignable to it.
6822
+ * (the wire-serialisable supertype of `Buffer`); a `Buffer` is assignable to
6823
+ * it.
6897
6824
  */
6898
6825
  var AudioChunkFormatSchema = _enum(AUDIO_CHUNK_FORMATS);
6899
6826
  var DecodedAudioChunkSchema = object({
@@ -6911,11 +6838,10 @@ var DecodedAudioChunkSchema = object({
6911
6838
  format: AudioChunkFormatSchema.optional()
6912
6839
  });
6913
6840
  /**
6914
- * Input for `stream-broker.subscribeAudioChunks` (Phase 5 / D9). The
6915
- * handle-free, ship-bytes-inline analogue of `subscribeFrames`: a consumer
6916
- * asks the broker for the decoded audio-chunk stream of one broker; the
6917
- * broker keeps a per-subscription bounded FIFO queue the consumer drains via
6918
- * `pullAudioChunks`.
6841
+ * Input for `stream-broker.subscribeAudioChunks` (Phase 5 / D9). Audio ships
6842
+ * its bytes inline: a consumer asks the broker for the decoded audio-chunk
6843
+ * stream of one broker; the broker keeps a per-subscription bounded FIFO queue
6844
+ * the consumer drains via `pullAudioChunks`.
6919
6845
  */
6920
6846
  var SubscribeAudioChunksInputSchema = object({
6921
6847
  brokerId: string(),
@@ -6946,9 +6872,7 @@ var BrokerStatsSchema = object({
6946
6872
  "stopped"
6947
6873
  ]),
6948
6874
  inputFps: number(),
6949
- decodeFps: number(),
6950
6875
  encodedSubscribers: number(),
6951
- decodedSubscribers: number(),
6952
6876
  uptimeMs: number(),
6953
6877
  bitrateKbps: number(),
6954
6878
  idrIntervalMs: number(),
@@ -6961,14 +6885,6 @@ var BrokerStatsSchema = object({
6961
6885
  preBufferMs: number(),
6962
6886
  preBufferPackets: number(),
6963
6887
  /**
6964
- * Moleculer node id of the decoder provider currently servicing this
6965
- * stream's decoded subscribers. `null` until the deferred decoder is
6966
- * created (no decoded clients yet, or codec not detected). Surfaces the
6967
- * runtime decoder placement so the UI can show "Decoder: <agent>" without
6968
- * a separate cap call per broker.
6969
- */
6970
- decoderNodeId: string().nullable(),
6971
- /**
6972
6888
  * Detected audio track parameters from the RTSP DESCRIBE / SDP. `null`
6973
6889
  * when the stream has no audio track or the broker is in cold start.
6974
6890
  * `supported = false` means the codec was detected but the local
@@ -10290,70 +10206,6 @@ var StorageLocationDeclarationSchema = object({
10290
10206
  "backup"
10291
10207
  ]).optional()
10292
10208
  });
10293
- var DecoderStatsSchema = object({
10294
- inputFps: number(),
10295
- outputFps: number(),
10296
- avgDecodeTimeMs: number(),
10297
- droppedFrames: number(),
10298
- /**
10299
- * Pull-mode adaptive-fps telemetry (optional — only pull sessions run the
10300
- * lag-driven controller; push sessions omit these). `lagMs` is the EWMA of
10301
- * the decoder's real-time drift (rising = falling behind live); `adaptiveFps`
10302
- * is the current lag-throttled emit rate (≤ `effectiveFps` ceiling).
10303
- */
10304
- lagMs: number().optional(),
10305
- effectiveFps: number().optional(),
10306
- adaptiveFps: number().optional()
10307
- });
10308
- var DecoderSessionConfigSchema = object({
10309
- codec: string(),
10310
- maxFps: number().default(0),
10311
- outputFormat: _enum([
10312
- "jpeg",
10313
- "rgb",
10314
- "bgr",
10315
- "yuv420",
10316
- "gray"
10317
- ]).default("jpeg"),
10318
- scale: number().default(1),
10319
- width: number().optional(),
10320
- height: number().optional(),
10321
- /**
10322
- * Identifier of the camera this decoder session serves. Optional
10323
- * because the cap is generic (any caller could request decode), but
10324
- * stream-broker passes it so decoder logs include `deviceId` for
10325
- * per-camera filtering when diagnosing failures (e.g. node-av
10326
- * sendPacket errors on a single hung camera).
10327
- */
10328
- deviceId: number().int().nonnegative().optional(),
10329
- /**
10330
- * Free-form tag for log scoping. Stream-broker uses
10331
- * `broker:<deviceId>/<profile>`. Decoder session logger surfaces it
10332
- * on every line so `grep tag=broker:5/high` filters one camera
10333
- * profile cleanly.
10334
- */
10335
- tag: string().optional(),
10336
- /**
10337
- * Where the session delivers decoded frames (Phase 5 / D9):
10338
- *
10339
- * - `'callback'` (default) — the legacy pixel path: decoded frames are
10340
- * buffered as `DecodedFrame`s and drained via `pullFrames`.
10341
- * - `'shm'` — the shared-memory frame plane: decoded frames are written
10342
- * into an OS shared-memory ring and drained as zero-pixel
10343
- * `FrameHandle`s via `pullHandles`. A session is one mode or the
10344
- * other — `pullFrames` returns nothing for an `'shm'` session and
10345
- * `pullHandles` returns nothing for a `'callback'` session.
10346
- */
10347
- frameSink: _enum(["callback", "shm"]).default("callback"),
10348
- /**
10349
- * Per-camera decoder DEBUG facility. When `true`, a pull-mode session emits
10350
- * a throttled (~1Hz) structured `decoder debug` line (effective/adaptive fps,
10351
- * real-time lag, dropped-frame delta, avg decode time, hwaccel). Mirrors the
10352
- * stream-broker's `streamingDebug` gate — off by default so production logs
10353
- * stay quiet and the emit path pays zero per-frame cost when disabled.
10354
- */
10355
- debug: boolean().optional()
10356
- });
10357
10209
  /**
10358
10210
  * Per-component log CHANNELS — the gate a hot path consults, and the registry
10359
10211
  * an addon declares its channels in.
@@ -10496,6 +10348,26 @@ var ClipSearchStrictnessSchema = _enum([
10496
10348
  "balanced",
10497
10349
  "strict"
10498
10350
  ]);
10351
+ /** Steps whose effect a root label can BE. */
10352
+ var LABEL_SUPPLY_STEP_IDS = [
10353
+ "animal-classifier",
10354
+ "vehicle-classifier",
10355
+ "package-detection"
10356
+ ];
10357
+ /** Steps whose box a root detection can BE. */
10358
+ var CROP_SUPPLY_STEP_IDS = ["plate-detection", "face-detection"];
10359
+ /**
10360
+ * Steps whose per-detection MASK a root detection can carry (D737). The live
10361
+ * mask step is `segmentation` — a frame-plane refiner that runs its own model
10362
+ * once per detection crop. (`instance-segmentation` is a dormant step id that
10363
+ * no camera tree carries.)
10364
+ */
10365
+ var MASK_SUPPLY_STEP_IDS = ["segmentation"];
10366
+ [
10367
+ ...LABEL_SUPPLY_STEP_IDS,
10368
+ ...CROP_SUPPLY_STEP_IDS,
10369
+ ...MASK_SUPPLY_STEP_IDS
10370
+ ];
10499
10371
  var MODEL_FORMATS = [
10500
10372
  "onnx",
10501
10373
  "coreml",
@@ -10524,7 +10396,53 @@ var ModelFormatEntrySchema = object({
10524
10396
  /** Multi-file payload (directory members or sibling files). */
10525
10397
  files: array(string()).readonly().optional(),
10526
10398
  /** Runtime(s) that can use this format. If omitted, inferred from ModelFormat key */
10527
- runtimes: array(_enum(["python"])).readonly().optional()
10399
+ runtimes: array(_enum(["python"])).readonly().optional(),
10400
+ /**
10401
+ * Content revision of the artefact, for one hosted OFF the CamStack mirror.
10402
+ * A format on the mirror leaves it unset: its revision (the sha256 of its
10403
+ * weight file) comes from the downloader's generated table, kept in step
10404
+ * with the mirror by `scripts/check-hosted-model-revisions.ts` (D744). A
10405
+ * node records the revision it downloaded next to the file
10406
+ * (`<file>.revision`); a copy with no record or a different one is stale
10407
+ * unless its weight file hashes to the revision, and a stale copy is
10408
+ * downloaded again, the old one serving until the new one is complete. No
10409
+ * revision at all ⇒ a file on disk is current, whatever it holds (D743).
10410
+ */
10411
+ revision: string().min(1).optional()
10412
+ });
10413
+ /**
10414
+ * What a node holds for one (model, format) (D746). `current` is a complete
10415
+ * copy at its catalog revision — exactly what `downloaded: true` means.
10416
+ * `stale` is bytes on disk that are not (yet) proven current under D743/D744:
10417
+ * no or a different revision record, or a missing sibling. `missing` is no
10418
+ * copy. `downloaded` alone folds `stale` into "not downloaded", which hid
10419
+ * reclaimable bytes and a copy about to be replaced.
10420
+ */
10421
+ var ModelOnDiskStateSchema = _enum([
10422
+ "current",
10423
+ "stale",
10424
+ "missing"
10425
+ ]);
10426
+ /**
10427
+ * The numeric precision of one format's BUILD (D746) — reported only when the
10428
+ * build states it (file-name token, an INT8 variant, an EdgeTPU compile, a
10429
+ * CamStack Core ML export). Absent means "not stated", never "fp32".
10430
+ */
10431
+ var ModelFormatPrecisionSchema = _enum([
10432
+ "fp32",
10433
+ "fp16",
10434
+ "int8"
10435
+ ]);
10436
+ /**
10437
+ * One format of one model as a node's `pipelineExecutor.getSchema` reports it.
10438
+ * `onDisk` / `precision` are optional for version skew: a runner that predates
10439
+ * them omits them, and a reader falls back to `downloaded`.
10440
+ */
10441
+ var PipelineModelFormatStatusSchema = object({
10442
+ downloaded: boolean(),
10443
+ sizeMB: number(),
10444
+ onDisk: ModelOnDiskStateSchema.optional(),
10445
+ precision: ModelFormatPrecisionSchema.optional()
10528
10446
  });
10529
10447
  /**
10530
10448
  * Extra file that must be downloaded alongside the model (e.g., labels JSON, dict.txt).
@@ -10565,11 +10483,11 @@ var ModelVariantGroupSchema = object({
10565
10483
  /** Quantization axis. Omit ⇒ the fp32 base build. */
10566
10484
  precision: _enum(["fp32", "int8"]).optional(),
10567
10485
  /**
10568
- * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
10569
- * latency-optimized export (e.g. ReLU-activation variant) — the slot the
10570
- * future performance variants plug into.
10486
+ * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
10487
+ * an alternate training of the same family (Scrypted `relu_test`); chip
10488
+ * label is "Test".
10571
10489
  */
10572
- optimization: _enum(["standard", "fast"]).optional(),
10490
+ optimization: _enum(["standard", "test"]).optional(),
10573
10491
  /**
10574
10492
  * Input-resolution axis (square input side, px). Omit ⇒ the family's native
10575
10493
  * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
@@ -10592,9 +10510,10 @@ var ModelProviderIdSchema = _enum([
10592
10510
  * are per upstream. A persisted custom-model row written when this field was a
10593
10511
  * string still parses — the string is lifted into `{ weights }`.
10594
10512
  *
10595
- * Every licence surface (the admin "Models and licenses" page,
10596
- * `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
10597
- * these records by `scripts/gen-model-licenses.ts` (D661).
10513
+ * Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
10514
+ * model table) is GENERATED from these records by
10515
+ * `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
10516
+ * `camstack/docs` → `/docs/detection/models`.
10598
10517
  */
10599
10518
  var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { weights: value } : value, object({
10600
10519
  /** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
@@ -10627,6 +10546,46 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
10627
10546
  /** True when the weights or their data forbid commercial use. */
10628
10547
  nonCommercial: boolean().optional()
10629
10548
  }));
10549
+ /**
10550
+ * One step a ROOT detector can supply from its own output (D730) — see
10551
+ * `ModelCatalogEntry.suppliesSteps`.
10552
+ *
10553
+ * - `label`: the root's raw class IS the step's answer. `labelToEffect` maps
10554
+ * the root's label to the step's vocabulary; `uncovered` is the vocabulary
10555
+ * the root cannot produce (shown as unavailable, never a blocker).
10556
+ * - `crop`: the root draws the box the step would have found (`license_plate`
10557
+ * for plate-detection, `face` for face-detection). The box becomes a detail
10558
+ * child of the `parentMacro` detection that contains it — never a track.
10559
+ * - `mask`: the root's decode emits an instance mask with every detection (a
10560
+ * YOLO26-seg root, D737) — the `segmentation` step's result, carried on the
10561
+ * detection in the shape that step produces. Derived from the model's
10562
+ * postprocessor on read, never stored by an import.
10563
+ */
10564
+ var RootStepSupplySchema = discriminatedUnion("kind", [
10565
+ object({
10566
+ kind: literal("label"),
10567
+ stepId: _enum(LABEL_SUPPLY_STEP_IDS),
10568
+ labelToEffect: record(string(), string()),
10569
+ uncovered: array(string()).readonly()
10570
+ }),
10571
+ object({
10572
+ kind: literal("crop"),
10573
+ stepId: _enum(CROP_SUPPLY_STEP_IDS),
10574
+ rootLabels: array(string()).readonly(),
10575
+ parentMacro: _enum(["vehicle", "person"]),
10576
+ childClass: _enum(["plate", "face"]),
10577
+ /**
10578
+ * The root's smaller input side, stamped on read by `rootSuppliesOf` from
10579
+ * the model entry — what a step's `minRootInputPx` gate judges. Never
10580
+ * stored by an import.
10581
+ */
10582
+ rootInputPx: number().int().positive().optional()
10583
+ }),
10584
+ object({
10585
+ kind: literal("mask"),
10586
+ stepId: _enum(MASK_SUPPLY_STEP_IDS)
10587
+ })
10588
+ ]);
10630
10589
  var ModelCatalogEntrySchema = object({
10631
10590
  id: string(),
10632
10591
  name: string(),
@@ -10692,6 +10651,35 @@ var ModelCatalogEntrySchema = object({
10692
10651
  */
10693
10652
  defaultConfidence: number().min(0).max(1).optional(),
10694
10653
  /**
10654
+ * Per-MODEL default of the per-class confidence floors (`minConfidence<Macro>`
10655
+ * on a detector step), keyed by macro class: `{ person: 0.45 }`. A class
10656
+ * absent here runs at the step slider's global default. The same row shape
10657
+ * the floor measurement produces (`model-floors.json`: modelId → floors), so
10658
+ * a measured table is copied in as-is. An operator override is bound to the
10659
+ * model it was made for and does not survive a model change (D738). A custom
10660
+ * / imported model may declare it; without it, the global defaults apply.
10661
+ */
10662
+ defaultClassFloors: record(string(), number().min(0).max(1)).optional(),
10663
+ /**
10664
+ * The inference precision this model's OpenVINO IR needs on an Intel GPU.
10665
+ * Absent ⇒ the device default (f16 on a GPU). Set to `'f32'` for an FP32 IR
10666
+ * that produces invalid output at f16 — measured 2026-10-07 for YOLO26
10667
+ * base IRs (`yolo26s`: 0 true / 146 false positives; `yolo26m*`: NaN
10668
+ * scores) on the Core Ultra iGPU and the N100. Threaded to the pool as
10669
+ * `PoolModelConfig.gpuInferencePrecision`; the pool sets
10670
+ * INFERENCE_PRECISION_HINT on a GPU only. Costs ~60% latency on the GPU.
10671
+ */
10672
+ gpuInferencePrecision: _enum(["f32", "f16"]).optional(),
10673
+ /**
10674
+ * ROOT detectors only: per supplied step (`animal-classifier`, …), the
10675
+ * minimum DETECTION score from which this root's own fine label (species,
10676
+ * vehicle type — D736 root supply) is taken (D741). Below it the detection
10677
+ * keeps its macro class without the fine label. `1` = never take it from
10678
+ * this root. Absent ⇒ no floor beyond the macro floor. The supplied step's
10679
+ * `minConfidence` slider, bound to the ROOT model, overrides it.
10680
+ */
10681
+ suppliedLabelFloors: record(string(), number().min(0).max(1)).optional(),
10682
+ /**
10695
10683
  * When true, the executor produces a landmark-aligned crop (similarity warp
10696
10684
  * onto the canonical template) before this step runs, instead of a plain
10697
10685
  * axis-aligned bbox crop. Required for face-recognition embedders (ArcFace):
@@ -10753,6 +10741,16 @@ var ModelCatalogEntrySchema = object({
10753
10741
  */
10754
10742
  classMap: DetectionCatalogClassMapSchema.optional(),
10755
10743
  /**
10744
+ * The pipeline steps this ROOT detector can supply from its own output
10745
+ * (D730): its labels name a step's effect (`deer` for `animal-classifier`)
10746
+ * or draw a step's box (`license_plate` for `plate-detection`). Computed at
10747
+ * import from THIS model's labelmap by `deriveRootSupplies`, never written
10748
+ * by hand and never assumed per family; a row without it is derived on read
10749
+ * (`rootSuppliesOf`). Whether a camera uses it is the step's own
10750
+ * `useRootModel` flag (`resolveRootSupply`).
10751
+ */
10752
+ suppliesSteps: array(RootStepSupplySchema).readonly().optional(),
10753
+ /**
10756
10754
  * The model's CLIP feature-space contract (text encoder, dimension, vector
10757
10755
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
10758
10756
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -12403,13 +12401,6 @@ var BrokerRtspClientSchema = object({
12403
12401
  lastRtpAt: number(),
12404
12402
  bytesSent: number()
12405
12403
  });
12406
- var BrokerDecodedClientSchema = object({
12407
- tag: string(),
12408
- subscribedAt: number(),
12409
- maxFps: number(),
12410
- framesDelivered: number(),
12411
- framesDropped: number()
12412
- });
12413
12404
  var BrokerAudioClientSchema = object({
12414
12405
  tag: string(),
12415
12406
  subscribedAt: number(),
@@ -12501,7 +12492,6 @@ var BrokerEncodedClientSchema = object({
12501
12492
  });
12502
12493
  var BrokerClientsSchema = object({
12503
12494
  rtsp: array(BrokerRtspClientSchema).readonly(),
12504
- decoded: array(BrokerDecodedClientSchema).readonly(),
12505
12495
  audio: array(BrokerAudioClientSchema).readonly(),
12506
12496
  encoded: array(BrokerEncodedClientSchema).readonly(),
12507
12497
  pipeClients: number(),
@@ -12870,11 +12860,7 @@ method(object({
12870
12860
  auth: "admin"
12871
12861
  }), method(object({ brokerId: string() }), BrokerClientsSchema), method(object({
12872
12862
  brokerId: string(),
12873
- channel: _enum([
12874
- "rtsp",
12875
- "decoded",
12876
- "audio"
12877
- ]),
12863
+ channel: _enum(["rtsp", "audio"]),
12878
12864
  handle: string()
12879
12865
  }), object({ killed: boolean() }), {
12880
12866
  kind: "mutation",
@@ -12909,10 +12895,7 @@ method(object({
12909
12895
  }), method(SubscribeAudioChunksInputSchema, SubscribeAudioChunksResultSchema, { kind: "mutation" }), method(object({
12910
12896
  subscriptionId: string(),
12911
12897
  maxCount: number().int().positive().default(8)
12912
- }), array(DecodedAudioChunkSchema).readonly()), method(object({ subscriptionId: string() }), object({ released: boolean() }), { kind: "mutation" }), method(SubscribeFramesInputSchema, SubscribeFramesResultSchema, { kind: "mutation" }), method(object({
12913
- subscriptionId: string(),
12914
- maxCount: number().int().positive().default(4)
12915
- }), array(FrameHandleSchema).readonly()), method(object({ subscriptionId: string() }), object({ released: boolean() }), { kind: "mutation" }), method(object({
12898
+ }), array(DecodedAudioChunkSchema).readonly()), method(object({ subscriptionId: string() }), object({ released: boolean() }), { kind: "mutation" }), method(object({
12916
12899
  brokerId: string(),
12917
12900
  seconds: number().min(0).max(30)
12918
12901
  }), _void(), {
@@ -14069,54 +14052,12 @@ id: union([string(), number()]) }), {
14069
14052
  kind: "mutation",
14070
14053
  auth: "admin"
14071
14054
  });
14072
- /**
14073
- * shm ring usage stats for a `frameSink: 'shm'` decoder session —
14074
- * exposed via `decoder.getShmStats` so downstream consumers can
14075
- * observe ring pressure (slot count, byte budget, hit/miss ratio).
14076
- */
14077
- var ShmRingStatsSchema = object({
14078
- sessionId: string(),
14079
- slotCount: number().int(),
14080
- slotByteLength: number().int(),
14081
- segmentBytes: number().int(),
14082
- budgetMb: number().int(),
14083
- framesWritten: number().int(),
14084
- getFrameHits: number().int(),
14085
- getFrameMisses: number().int()
14086
- });
14087
- method(object({ codec: string() }), boolean()), method(_void(), object({
14055
+ method(_void(), object({
14088
14056
  id: string(),
14089
14057
  name: string(),
14090
- isPullMode: boolean().optional(),
14091
- priority: number().optional(),
14092
14058
  hwaccel: string().optional(),
14093
14059
  probedBestHwaccel: string().optional()
14094
- })), method(DecoderSessionConfigSchema, object({
14095
- sessionId: string(),
14096
- nodeId: string()
14097
- })), method(object({ sessionId: string() }), _void()), method(object({
14098
- sessionId: string(),
14099
- packet: EncodedPacketSchema
14100
- }), _void()), method(object({
14101
- sessionId: string(),
14102
- url: string()
14103
- }), _void()), method(object({
14104
- sessionId: string(),
14105
- maxCount: number().default(1),
14106
- waitMs: number().optional()
14107
- }), array(DecodedFrameSchema)), method(object({
14108
- sessionId: string(),
14109
- maxCount: number().default(1),
14110
- waitMs: number().optional()
14111
- }), array(FrameHandleSchema)), method(object({ handle: FrameHandleSchema }), DecodedFrameSchema.nullable()), method(object({ sessionId: string() }), ShmRingStatsSchema.nullable()), method(object({
14112
- sessionId: string(),
14113
- config: DecoderSessionConfigSchema.partial()
14114
- }), _void()), method(object({ sessionId: string() }), DecoderStatsSchema), method(_void(), array(object({
14115
- sessionId: string(),
14116
- codec: string(),
14117
- outputFormat: string(),
14118
- createdAtMs: number()
14119
- })).readonly()), method(_void(), object({ backend: string() }), {
14060
+ })), method(_void(), object({ backend: string() }), {
14120
14061
  kind: "mutation",
14121
14062
  auth: "admin"
14122
14063
  });
@@ -14172,7 +14113,7 @@ DeviceType.Camera;
14172
14113
  * This matters here more than anywhere else in the repo, because every provider
14173
14114
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
14174
14115
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
14175
- * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
14116
+ * and `http://admin:hunter2@192.168.60.139/` is a URL a browser accepts. The
14176
14117
  * camera's own page will ask for its own login. That is correct, and pre-
14177
14118
  * filling it is the operator's business, not ours.
14178
14119
  *
@@ -15960,6 +15901,12 @@ method(_void(), array(string()).readonly(), { auth: "admin" }), method(object({
15960
15901
  kind: "mutation",
15961
15902
  auth: "admin"
15962
15903
  });
15904
+ var HUB_ADDRESS_ROLES = [
15905
+ "appConnections",
15906
+ "notificationTaps",
15907
+ "internal",
15908
+ "publicEndpoint"
15909
+ ];
15963
15910
  /**
15964
15911
  * Transport bounds for AI capability methods.
15965
15912
  *
@@ -17156,7 +17103,7 @@ method(object({
17156
17103
  timeoutMs: 6e5
17157
17104
  });
17158
17105
  method(object({
17159
- nodeId: string(),
17106
+ targetNodeId: string(),
17160
17107
  modelId: string(),
17161
17108
  format: _enum(MODEL_FORMATS),
17162
17109
  entry: ModelCatalogEntrySchema
@@ -18543,6 +18490,8 @@ var NcSystemEventKindSchema = _enum([
18543
18490
  "stream-offline",
18544
18491
  "node-online",
18545
18492
  "node-offline",
18493
+ "node-restarting",
18494
+ "node-updating",
18546
18495
  "node-inference-unavailable",
18547
18496
  "detection-blind",
18548
18497
  "addon-crash-loop",
@@ -19641,8 +19590,9 @@ var NcRuleSchema = NcRuleInputSchema.extend({
19641
19590
  disabledTargetIds: array(string()).default([])
19642
19591
  });
19643
19592
  /**
19644
- * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
19645
- * still-true state. `backups-exports` and `alarm` are not sections — a completed
19593
+ * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
19594
+ * report a still-true state. `addons` is the crash-looped addons only and
19595
+ * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
19646
19596
  * job is not an open state, and the alarm stays instant.
19647
19597
  */
19648
19598
  var NcStateSummarySectionIdSchema = _enum([
@@ -19654,6 +19604,7 @@ var NcStateSummarySectionIdSchema = _enum([
19654
19604
  "detection-blind",
19655
19605
  "nodes",
19656
19606
  "addons",
19607
+ "addon-updates",
19657
19608
  "updates"
19658
19609
  ]);
19659
19610
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
@@ -20134,7 +20085,25 @@ var NcAlarmModeDelaysListSchema = array(object({
20134
20085
  * When this mode may be armed. Absent / null = always allowed (same as a
20135
20086
  * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
20136
20087
  */
20137
- schedule: NcScheduleSchema.optional()
20088
+ schedule: NcScheduleSchema.optional(),
20089
+ /**
20090
+ * D706: while this mode's ENTRY DELAY runs, do the alarm rules' own pushes go out (as an
20091
+ * intrusion naming the locations)? Absent = false — the entry-delay notification is the
20092
+ * only one, and the matches ride the triggered notification's mosaic (D705).
20093
+ */
20094
+ notifyDuringEntryDelay: boolean().optional(),
20095
+ /**
20096
+ * D706: notify "watched again" when a sensor this arm bypassed closes and opens again.
20097
+ * Absent = false (logged, not sent). Even when true it is not sent when that same sensor
20098
+ * is the one that starts the entry delay — the entry-delay notification already names it.
20099
+ */
20100
+ notifySensorRewatched: boolean().optional(),
20101
+ /**
20102
+ * D735: notify "ignored" when a sensor this arm bypassed really MOVED while armed (its own
20103
+ * change time is after the arm) and set nothing off. Absent = false (logged, not sent). A
20104
+ * re-sync, a recovery from `unavailable` or a duplicate is never announced, switch or not.
20105
+ */
20106
+ notifySensorIgnored: boolean().optional()
20138
20107
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20139
20108
  var NcAlarmModeDelaysEditListSchema = array(object({
20140
20109
  mode: AlarmArmModeSchema,
@@ -20143,7 +20112,13 @@ var NcAlarmModeDelaysEditListSchema = array(object({
20143
20112
  triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
20144
20113
  postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
20145
20114
  /** Set a schedule, or `null` to clear (mode always allowed again). */
20146
- schedule: NcScheduleSchema.nullable().optional()
20115
+ schedule: NcScheduleSchema.nullable().optional(),
20116
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20117
+ notifyDuringEntryDelay: boolean().nullable().optional(),
20118
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20119
+ notifySensorRewatched: boolean().nullable().optional(),
20120
+ /** D735: set the switch, or `null` to clear it (back to the default, false). */
20121
+ notifySensorIgnored: boolean().nullable().optional()
20147
20122
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20148
20123
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20149
20124
  var NcAlarmNonBlockingEditSchema = object({
@@ -21104,45 +21079,25 @@ Object.freeze(Object.fromEntries([{
21104
21079
  label: "Face recognition model",
21105
21080
  defaultModelId: "auraface-r100",
21106
21081
  indexName: "the enrolled face gallery",
21107
- options: [
21108
- {
21109
- id: "auraface-r100",
21110
- label: "AuraFace R100"
21111
- },
21112
- {
21113
- id: "arcface-r100",
21114
- label: "ArcFace (ResNet34)"
21115
- },
21116
- {
21117
- id: "inception-resnet-v1",
21118
- label: "Inception ResNet V1"
21119
- }
21120
- ]
21082
+ options: [{
21083
+ id: "auraface-r100",
21084
+ label: "AuraFace R100"
21085
+ }]
21121
21086
  }, {
21122
21087
  stepId: "clip-embedding",
21123
21088
  label: "Semantic search model",
21124
- defaultModelId: "mobileclip-s1",
21089
+ defaultModelId: "siglip2-b16-224",
21125
21090
  indexName: "the object semantic-search index",
21126
- options: [
21127
- {
21128
- id: "mobileclip-s1",
21129
- label: "MobileCLIP S1"
21130
- },
21131
- {
21132
- id: "mobileclip-s2",
21133
- label: "MobileCLIP S2"
21134
- },
21135
- {
21136
- id: "siglip2-b16-224",
21137
- label: "SigLIP2 B/16 (Apache-2.0)"
21138
- }
21139
- ]
21091
+ options: [{
21092
+ id: "siglip2-b16-224",
21093
+ label: "SigLIP2 B/16 (Apache-2.0)"
21094
+ }]
21140
21095
  }].map((s) => [s.stepId, s.defaultModelId])));
21141
21096
  var CLUSTER_STEP_SETTING_FIELDS = [{
21142
21097
  stepId: "face-embedding",
21143
21098
  key: "minLandmarkFaceSize",
21144
- label: "Min face size for recognition (detection px)",
21145
- description: "Refuse to embed a face smaller than this IN THE DETECTION FRAME. Applies to every node — the enrolled gallery is one index, and two admission floors would fill it from two policies. 0 disables the gate.",
21099
+ label: "Min face size to embed (detection-frame px)",
21100
+ description: "Faces smaller than this in the small frame the detector sees are not embedded, so they can never be recognised. Below it the face cannot be aligned reliably and a bad embedding matches everyone. Same value on every node. 0 = no limit.",
21146
21101
  type: "slider",
21147
21102
  min: 0,
21148
21103
  max: 64,
@@ -23062,6 +23017,34 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
23062
23017
  timestamp: number()
23063
23018
  });
23064
23019
  /**
23020
+ * A root model's boxes standing in for one crop-kind step's own inference
23021
+ * (D730) — see `runPipeline.suppliedRoot`.
23022
+ */
23023
+ var SuppliedRootOutputSchema = object({
23024
+ stepId: string(),
23025
+ /** The root model that drew the boxes — stamped on the result. */
23026
+ modelId: string(),
23027
+ detections: array(object({
23028
+ /** `[x1, y1, x2, y2]` in the pixels of the call's image. */
23029
+ bbox: tuple([
23030
+ number(),
23031
+ number(),
23032
+ number(),
23033
+ number()
23034
+ ]),
23035
+ score: number(),
23036
+ /**
23037
+ * Five facial landmarks in the same pixels — a face the step's own
23038
+ * detector already re-found inside a root face box (D730), so its
23039
+ * embedder child aligns it exactly as it aligns any detected face.
23040
+ */
23041
+ landmarks: array(object({
23042
+ x: number(),
23043
+ y: number()
23044
+ })).optional()
23045
+ })).min(1)
23046
+ });
23047
+ /**
23065
23048
  * Reference to the frame's retained NATIVE surface + the parent crop's placement
23066
23049
  * within the frame, so the executor can re-cut a leaf child ROI at native
23067
23050
  * resolution on the detail plane. See the `runPipeline` `nativeCropRef` field.
@@ -23109,7 +23092,7 @@ var FrameRefSchema = object({
23109
23092
  timestamp: number(),
23110
23093
  capturedAt: number().optional()
23111
23094
  });
23112
- var ModelFormatSchema$1 = _enum([
23095
+ var ModelFormatSchema$2 = _enum([
23113
23096
  "onnx",
23114
23097
  "coreml",
23115
23098
  "openvino",
@@ -23127,7 +23110,7 @@ var PipelineSlotSchema = _enum([
23127
23110
  var PipelineEngineChoiceSchema = object({
23128
23111
  runtime: literal("python"),
23129
23112
  backend: string(),
23130
- format: ModelFormatSchema$1,
23113
+ format: ModelFormatSchema$2,
23131
23114
  device: string().optional()
23132
23115
  });
23133
23116
  /**
@@ -23166,32 +23149,15 @@ var PipelineDefaultStepSchema = lazy(() => object({
23166
23149
  group: string().optional(),
23167
23150
  settings: record(string(), unknown()).optional()
23168
23151
  }));
23169
- var PipelineTemplateStepSchema = lazy(() => object({
23170
- addonId: string(),
23171
- enabled: boolean(),
23172
- modelId: string(),
23173
- children: array(PipelineTemplateStepSchema).readonly(),
23174
- settings: record(string(), unknown()).optional()
23175
- }));
23176
- var PipelineTemplateSchema$1 = object({
23177
- id: string(),
23178
- name: string(),
23179
- createdAt: string(),
23180
- updatedAt: string(),
23181
- engine: PipelineEngineChoiceSchema,
23182
- steps: array(PipelineTemplateStepSchema).readonly()
23183
- });
23184
23152
  var PipelineModelOptionSchema = object({
23185
23153
  id: string(),
23186
23154
  name: string(),
23187
- formats: record(string(), object({
23188
- downloaded: boolean(),
23189
- sizeMB: number()
23190
- })),
23155
+ formats: record(string(), PipelineModelFormatStatusSchema),
23191
23156
  group: ModelVariantGroupSchema.optional(),
23192
23157
  legacy: boolean().optional(),
23193
23158
  provider: ModelProviderIdSchema.optional(),
23194
- defaultConfidence: number().optional()
23159
+ defaultConfidence: number().optional(),
23160
+ suppliesSteps: array(RootStepSupplySchema).readonly().optional()
23195
23161
  });
23196
23162
  var ConfigFieldBridge = custom();
23197
23163
  var PipelineAddonSchemaSchema = object({
@@ -23353,6 +23319,22 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
23353
23319
  }), {
23354
23320
  kind: "mutation",
23355
23321
  auth: "admin"
23322
+ }), method(object({
23323
+ nodeId: string(),
23324
+ deviceIds: array(number()).readonly().optional(),
23325
+ dryRun: boolean()
23326
+ }), object({
23327
+ entries: array(object({
23328
+ deviceId: number(),
23329
+ keys: array(string()).readonly()
23330
+ })).readonly(),
23331
+ refused: array(object({
23332
+ deviceId: number(),
23333
+ reason: string()
23334
+ })).readonly()
23335
+ }), {
23336
+ kind: "mutation",
23337
+ auth: "admin"
23356
23338
  }), method(object({ nodeId: string() }), object({ unhealthy: array(object({
23357
23339
  /** `<backend>:<device>`, e.g. `openvino:gpu`. */
23358
23340
  deviceKey: string(),
@@ -23378,22 +23360,14 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
23378
23360
  }), method(_void(), PipelineSchemaSchema), method(_void(), array(PipelineDefaultStepSchema).readonly().nullable()), method(_void(), PipelineConfigBridge), method(_void(), ConfigUISchemaBridge), method(object({
23379
23361
  steps: array(PipelineStepInputSchema),
23380
23362
  deviceKey: string().optional()
23381
- }), PipelineValidationResultSchema), method(_void(), array(PipelineTemplateSchema$1).readonly()), method(object({
23382
- name: string(),
23383
- steps: array(PipelineTemplateStepSchema).readonly(),
23384
- engine: PipelineEngineChoiceSchema
23385
- }), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({
23386
- id: string(),
23387
- name: string().optional(),
23388
- steps: array(PipelineTemplateStepSchema).readonly().optional()
23389
- }), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({ id: string() }), _void(), { kind: "mutation" }), method(_void(), InferenceCapabilitiesBridge), method(object({ addonId: string() }), ModelAvailabilityListBridge), method(object({
23363
+ }), PipelineValidationResultSchema), method(_void(), InferenceCapabilitiesBridge), method(object({ addonId: string() }), ModelAvailabilityListBridge), method(object({
23390
23364
  addonId: string(),
23391
23365
  modelId: string(),
23392
- format: ModelFormatSchema$1
23366
+ format: ModelFormatSchema$2
23393
23367
  }), DownloadModelResultSchema, { kind: "mutation" }), method(object({
23394
23368
  addonId: string(),
23395
23369
  modelId: string(),
23396
- format: ModelFormatSchema$1
23370
+ format: ModelFormatSchema$2
23397
23371
  }), object({ success: literal(true) }), { kind: "mutation" }), method(object({
23398
23372
  steps: array(PipelineStepInputSchema).min(1),
23399
23373
  frame: FrameInputSchema.optional(),
@@ -23459,7 +23433,16 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
23459
23433
  * `device-not-servable`), and nothing reaches the camera's live
23460
23434
  * trace stream. Absent ⇒ unchanged behaviour.
23461
23435
  */
23462
- replay: literal(true).optional()
23436
+ replay: literal(true).optional(),
23437
+ /**
23438
+ * Root-supplied detections for the tree's ROOT step (D730). Set by
23439
+ * `runDetailSubtree` when the camera's root model supplies a crop-kind
23440
+ * step (a Frigate+ `license_plate` for `plate-detection`): the step is
23441
+ * NOT inferred, these boxes are its output, and its children (the plate
23442
+ * reader) run on them through their own crop policy. Boxes are in the
23443
+ * PIXELS of the image this call carries. Absent ⇒ the root step runs.
23444
+ */
23445
+ suppliedRoot: SuppliedRootOutputSchema.optional()
23463
23446
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
23464
23447
  steps: array(PipelineStepInputSchema).min(1),
23465
23448
  frames: array(FrameInputSchema).min(1).max(255),
@@ -23541,6 +23524,375 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
23541
23524
  filename: string().optional(),
23542
23525
  settings: record(string(), unknown()).optional()
23543
23526
  }), AudioTestResultSchema, { kind: "mutation" }), method(_void(), ConfigUISchemaNullableBridge);
23527
+ /**
23528
+ * The wire shapes of the Auto tune plan and apply (D745), used by the
23529
+ * `pipeline-orchestrator` cap. The recommender's own types
23530
+ * (`recommend.ts`) are the TS face of the same data; these
23531
+ * schemas are what crosses the cap boundary.
23532
+ */
23533
+ var ModelFormatSchema$1 = _enum(MODEL_FORMATS);
23534
+ /** The operator's range for it. */
23535
+ var MIN_SESSIONS_PER_DEVICE_RANGE = {
23536
+ min: 1,
23537
+ max: 8
23538
+ };
23539
+ var HardwareClassIdSchema = _enum([
23540
+ "intel-core-ultra",
23541
+ "intel-n-series",
23542
+ "apple-m-base",
23543
+ "apple-m-pro",
23544
+ "unknown"
23545
+ ]);
23546
+ var AcceleratorKindSchema = _enum([
23547
+ "intel-npu",
23548
+ "intel-igpu",
23549
+ "x86-cpu",
23550
+ "arm-cpu",
23551
+ "apple-ane",
23552
+ "coral"
23553
+ ]);
23554
+ var RecommendationReasonSchema = discriminatedUnion("kind", [
23555
+ object({
23556
+ kind: literal("capacity"),
23557
+ sessions: number(),
23558
+ minSessions: number()
23559
+ }),
23560
+ object({
23561
+ kind: literal("tie-faster"),
23562
+ over: string(),
23563
+ recallDelta: number()
23564
+ }),
23565
+ object({
23566
+ kind: literal("stepped-down"),
23567
+ from: string(),
23568
+ to: string(),
23569
+ limitedBy: string()
23570
+ }),
23571
+ object({
23572
+ kind: literal("no-fit-lightest"),
23573
+ sessions: number(),
23574
+ minSessions: number()
23575
+ }),
23576
+ object({
23577
+ kind: literal("derived-latency"),
23578
+ modelId: string()
23579
+ }),
23580
+ object({ kind: literal("cpu-device") }),
23581
+ object({ kind: literal("coral-untouched") }),
23582
+ object({ kind: literal("device-disabled") }),
23583
+ object({ kind: literal("device-unavailable") }),
23584
+ object({ kind: literal("node-offline") }),
23585
+ object({ kind: literal("no-hardware-facts") }),
23586
+ object({
23587
+ kind: literal("no-measured-data"),
23588
+ hardwareClass: HardwareClassIdSchema
23589
+ }),
23590
+ object({
23591
+ kind: literal("no-family-build"),
23592
+ format: ModelFormatSchema$1
23593
+ })
23594
+ ]);
23595
+ var DeviceModelChoiceSchema = object({
23596
+ modelId: string(),
23597
+ p50Ms: number(),
23598
+ fps: number(),
23599
+ measured: boolean(),
23600
+ /** Parallel sessions at the camera rate with the headroom kept free: ⌊fps × (1 − headroom) / camera fps⌋. */
23601
+ capacitySessions: number(),
23602
+ personRecall: number()
23603
+ });
23604
+ var DeviceRecommendationSchema = object({
23605
+ deviceKey: string(),
23606
+ accelerator: AcceleratorKindSchema.nullable(),
23607
+ enabled: boolean(),
23608
+ available: boolean(),
23609
+ chosen: DeviceModelChoiceSchema.nullable(),
23610
+ reasons: array(RecommendationReasonSchema).readonly()
23611
+ });
23612
+ var NodeRecommendationSchema = object({
23613
+ nodeId: string(),
23614
+ reachable: boolean(),
23615
+ hardwareClass: HardwareClassIdSchema.nullable(),
23616
+ cpuModel: string().nullable(),
23617
+ skipped: boolean(),
23618
+ acceleratorModelId: string().nullable(),
23619
+ devices: array(DeviceRecommendationSchema).readonly(),
23620
+ reasons: array(RecommendationReasonSchema).readonly()
23621
+ });
23622
+ var ModelPinChangeSchema = object({
23623
+ stepId: string(),
23624
+ before: string().nullable(),
23625
+ after: string().nullable()
23626
+ });
23627
+ var NodeDeviceChangeSchema = object({
23628
+ nodeId: string(),
23629
+ deviceKey: string(),
23630
+ madeExplicit: boolean(),
23631
+ modelPins: array(ModelPinChangeSchema).readonly(),
23632
+ thresholds: array(object({
23633
+ stepId: string(),
23634
+ keys: array(string()).readonly()
23635
+ })).readonly()
23636
+ });
23637
+ var CameraOverrideClearSchema = object({
23638
+ deviceId: number(),
23639
+ source: _enum(["step-override", "wholesale"]),
23640
+ nodeId: string(),
23641
+ deviceKey: string().nullable(),
23642
+ stepId: string(),
23643
+ modelIdBefore: string().nullable(),
23644
+ keys: array(string()).readonly()
23645
+ });
23646
+ var DetectorStoreClearSchema = object({
23647
+ deviceId: number(),
23648
+ keys: array(string()).readonly()
23649
+ });
23650
+ var AutoTuneWarningSchema = discriminatedUnion("kind", [
23651
+ object({
23652
+ kind: literal("detector-store-cluster-wide"),
23653
+ skippedNodes: array(string()).readonly()
23654
+ }),
23655
+ object({
23656
+ kind: literal("detector-store-unreadable"),
23657
+ error: string()
23658
+ }),
23659
+ object({
23660
+ kind: literal("coral-enabled"),
23661
+ nodeId: string(),
23662
+ deviceKey: string()
23663
+ })
23664
+ ]);
23665
+ var AutoTuneOptionsSchema = object({
23666
+ /** Share of each accelerator's throughput kept free (0.3–0.5). */
23667
+ headroom: number().min(.3).max(.5).default(.4),
23668
+ /**
23669
+ * The least number of parallel sessions every device must sustain at the
23670
+ * camera rate with the headroom kept free (D755). The most accurate model
23671
+ * that reaches it wins.
23672
+ */
23673
+ minSessionsPerDevice: number().int().min(MIN_SESSIONS_PER_DEVICE_RANGE.min).max(MIN_SESSIONS_PER_DEVICE_RANGE.max).default(2)
23674
+ });
23675
+ var AutoTunePlanSchema = object({
23676
+ /** Hash of everything the apply will write — the apply refuses a different one. */
23677
+ planHash: string(),
23678
+ family: literal("yolov9"),
23679
+ headroom: number(),
23680
+ minSessionsPerDevice: number(),
23681
+ /** The detection rate a session is counted at (the fastest camera running the pipeline root). */
23682
+ cameraFps: number(),
23683
+ generatedAt: number(),
23684
+ nodes: array(NodeRecommendationSchema).readonly(),
23685
+ nodeChanges: array(NodeDeviceChangeSchema).readonly(),
23686
+ cameraClears: array(CameraOverrideClearSchema).readonly(),
23687
+ detectorStoreClears: array(DetectorStoreClearSchema).readonly(),
23688
+ warnings: array(AutoTuneWarningSchema).readonly()
23689
+ });
23690
+ var AutoTuneApplyInputSchema = object({
23691
+ planHash: string(),
23692
+ headroom: number().min(.3).max(.5).default(.4),
23693
+ minSessionsPerDevice: number().int().min(MIN_SESSIONS_PER_DEVICE_RANGE.min).max(MIN_SESSIONS_PER_DEVICE_RANGE.max).default(2)
23694
+ });
23695
+ var AutoTunePhaseResultSchema = object({
23696
+ phase: _enum([
23697
+ "download",
23698
+ "camera-overrides",
23699
+ "detector-thresholds",
23700
+ "node-models",
23701
+ "redispatch"
23702
+ ]),
23703
+ ok: boolean(),
23704
+ detail: string()
23705
+ });
23706
+ var AutoTuneApplyResultSchema = discriminatedUnion("kind", [
23707
+ object({
23708
+ kind: literal("applied"),
23709
+ planHash: string(),
23710
+ phases: array(AutoTunePhaseResultSchema).readonly()
23711
+ }),
23712
+ object({
23713
+ kind: literal("aborted"),
23714
+ phases: array(AutoTunePhaseResultSchema).readonly()
23715
+ }),
23716
+ object({
23717
+ kind: literal("stale"),
23718
+ plan: AutoTunePlanSchema
23719
+ }),
23720
+ object({
23721
+ kind: literal("refused"),
23722
+ reason: _enum(["apply-in-progress"])
23723
+ })
23724
+ ]);
23725
+ /**
23726
+ * Wire shapes of the Load balancing surface (D748): the session placement
23727
+ * policy, the atomic share write, the observed placement statistics, the
23728
+ * hardware share suggestion and the stale device pins.
23729
+ */
23730
+ /**
23731
+ * How a new detection session picks its node and device.
23732
+ * - `least-loaded` — the historical rule: lowest `attached / weight`, a
23733
+ * constant node order at a tie (D37). An idle node always ties at 0, so a
23734
+ * weight only bites once a node already holds a session.
23735
+ * - `share` — the share of PARALLEL sessions is held to the weights, and a
23736
+ * full or drowning node yields to a free one (D748).
23737
+ */
23738
+ var SessionPlacementPolicySchema = _enum(["least-loaded", "share"]);
23739
+ var LoadBalancingSharesInputSchema = object({
23740
+ /** nodeId → share (> 0). A node left out keeps its weight. */
23741
+ nodes: record(string(), number().positive()).default({}),
23742
+ /** nodeId → deviceKey → share (> 0). A device left out keeps its weight. */
23743
+ devices: record(string(), record(string(), number().positive())).default({})
23744
+ });
23745
+ var PlacementStatsInputSchema = object({
23746
+ /** Window the observed shares are averaged over (default 1 h, max 24 h). */
23747
+ windowMs: number().int().min(6e4).max(1440 * 60 * 1e3).default(3600 * 1e3) });
23748
+ var PlacementDeviceStatsSchema = object({
23749
+ deviceKey: string(),
23750
+ /** Sessions running on this device now. */
23751
+ sessionsNow: number(),
23752
+ /** Sessions started on this device inside the window. */
23753
+ sessionsStarted: number(),
23754
+ /** Time-weighted share of the node's parallel sessions over the window (0–1); null = no session ran. */
23755
+ observedShare: number().nullable()
23756
+ });
23757
+ var PlacementNodeStatsSchema = object({
23758
+ nodeId: string(),
23759
+ sessionsNow: number(),
23760
+ sessionsStarted: number(),
23761
+ /** Time-weighted share of the cluster's parallel sessions over the window (0–1); null = none ran. */
23762
+ observedShare: number().nullable(),
23763
+ /** Most sessions this node ran at once inside the window. */
23764
+ peakSessions: number(),
23765
+ /** Sessions a share election handed elsewhere because this node was full or drowning. */
23766
+ yieldsAway: number(),
23767
+ devices: array(PlacementDeviceStatsSchema).readonly()
23768
+ });
23769
+ /** A camera's device pin that the session path cannot honour. */
23770
+ var StaleDevicePinSchema = object({
23771
+ deviceId: number(),
23772
+ deviceKey: string(),
23773
+ /** `disabled` — the key exists on some node but is not enabled anywhere; `absent` — no node has it. */
23774
+ reason: _enum(["disabled", "absent"])
23775
+ });
23776
+ var PlacementStatsSchema = object({
23777
+ policy: SessionPlacementPolicySchema,
23778
+ windowMs: number(),
23779
+ /** How much of the window was actually observed (the hub keeps it in memory). */
23780
+ observedForMs: number(),
23781
+ sessionsNow: number(),
23782
+ /** Most parallel sessions across the cluster inside the window. */
23783
+ clusterPeakSessions: number(),
23784
+ nodes: array(PlacementNodeStatsSchema).readonly(),
23785
+ stalePins: array(StaleDevicePinSchema).readonly()
23786
+ });
23787
+ /**
23788
+ * Where an automatic share's capacity comes from (D755).
23789
+ * - `hardware` — the static capacity of each device at its Auto tune model:
23790
+ * the measured latency table for the node's hardware class.
23791
+ * - `benchmark` — the node's own measured capacity (node benchmark results).
23792
+ * A node with no results falls back to `hardware`, and says so.
23793
+ */
23794
+ var CapacitySourceSchema = _enum(["hardware", "benchmark"]);
23795
+ /** Why a node under the `benchmark` source was sized from hardware instead. */
23796
+ var CapacityFallbackSchema = _enum(["no-benchmark-results", "partial-benchmark-results"]);
23797
+ var SuggestSharesInputSchema = object({
23798
+ headroom: number().min(.3).max(.5).default(.4),
23799
+ /** Default `hardware`. */
23800
+ source: CapacitySourceSchema.default("hardware")
23801
+ });
23802
+ var SuggestedDeviceShareSchema = object({
23803
+ deviceKey: string(),
23804
+ /** Share of the node (0–100, rounded). */
23805
+ share: number(),
23806
+ modelId: string().nullable(),
23807
+ /** Inferences per second at that model, from the measured table; null when sized by a benchmark. */
23808
+ fps: number().nullable(),
23809
+ /** False for a table cell derived from another chip; true for a measured cell or a benchmark. */
23810
+ measured: boolean(),
23811
+ /**
23812
+ * Advisory session cap: ⌊fps × (1 − headroom) / camera fps⌋ from the table,
23813
+ * or the benchmark's measured max sessions. Never enforced.
23814
+ */
23815
+ suggestedMaxSessions: number().nullable()
23816
+ });
23817
+ var SuggestedNodeShareSchema = object({
23818
+ nodeId: string(),
23819
+ /** Share of the cluster (0–100, rounded); null = node skipped (offline, unknown hardware). */
23820
+ share: number().nullable(),
23821
+ /** Parallel sessions the node sustains at the suggested models with the headroom kept free. */
23822
+ capacitySessions: number(),
23823
+ devices: array(SuggestedDeviceShareSchema).readonly(),
23824
+ skippedReason: string().nullable(),
23825
+ /** What this node's capacity was read from; null when the node is skipped. */
23826
+ capacitySource: CapacitySourceSchema.nullable(),
23827
+ /** Set when the `benchmark` source was asked for and this node used `hardware`. */
23828
+ capacityFallback: CapacityFallbackSchema.nullable()
23829
+ });
23830
+ var SuggestSharesResultSchema = object({
23831
+ headroom: number(),
23832
+ /** The source asked for; each node says what it actually used. */
23833
+ source: CapacitySourceSchema,
23834
+ /** Camera detection rate the capacity is counted in (the fastest camera's fps). */
23835
+ cameraFps: number(),
23836
+ /** The Auto tune capacity floor the models were picked at. */
23837
+ minSessionsPerDevice: number(),
23838
+ nodes: array(SuggestedNodeShareSchema).readonly()
23839
+ });
23840
+ /**
23841
+ * Where the node and device shares come from (D750, D755).
23842
+ * - `hardware` (default) — computed by the system from each node's static
23843
+ * capacity (its accelerators at their Auto tune models, from the measured
23844
+ * latency table), recomputed whenever a node or device joins, leaves, is
23845
+ * switched on or off, or changes model. No load input.
23846
+ * - `benchmark` — the same, from each node's measured capacity (node
23847
+ * benchmark results); a node without results falls back to `hardware`.
23848
+ * - `manual` — the operator's stored sliders.
23849
+ * Either way a node or device that cannot take sessions gives its share to
23850
+ * the others in proportion; the stored values are never rewritten for that.
23851
+ */
23852
+ var ShareSourceSchema = _enum([
23853
+ "hardware",
23854
+ "benchmark",
23855
+ "manual"
23856
+ ]);
23857
+ var SetShareSourceInputSchema = object({ source: ShareSourceSchema });
23858
+ object({
23859
+ nodes: record(string(), number()),
23860
+ devices: record(string(), record(string(), number()))
23861
+ });
23862
+ var EffectiveDeviceShareSchema = object({
23863
+ deviceKey: string(),
23864
+ /** Can take sessions now (enabled, available, can run the root). */
23865
+ eligible: boolean(),
23866
+ /** The share the source assigns, as a percentage of the node's devices. */
23867
+ configuredPct: number(),
23868
+ /** The share actually used, after an ineligible device's share went to the others. */
23869
+ effectivePct: number()
23870
+ });
23871
+ var EffectiveNodeShareSchema = object({
23872
+ nodeId: string(),
23873
+ eligible: boolean(),
23874
+ configuredPct: number(),
23875
+ effectivePct: number(),
23876
+ /** Automatic sources: what this node's share was computed from; null under `manual` or before the first answer. */
23877
+ capacitySource: CapacitySourceSchema.nullable(),
23878
+ /** Automatic `benchmark`: why this node used `hardware` instead. */
23879
+ capacityFallback: CapacityFallbackSchema.nullable(),
23880
+ devices: array(EffectiveDeviceShareSchema).readonly()
23881
+ });
23882
+ var EffectiveSharesSchema = object({
23883
+ source: ShareSourceSchema,
23884
+ policy: SessionPlacementPolicySchema,
23885
+ /** An automatic source with no computed answer yet: the stored sliders are used meanwhile. */
23886
+ autoPending: boolean(),
23887
+ /** When the automatic shares were last computed (ms epoch); null = never. */
23888
+ computedAt: number().nullable(),
23889
+ /** What made the system recompute them last. */
23890
+ trigger: string().nullable(),
23891
+ nodes: array(EffectiveNodeShareSchema).readonly(),
23892
+ /** The relative weights the election reads (before eligibility). */
23893
+ nodeWeights: record(string(), number()),
23894
+ deviceWeights: record(string(), record(string(), number()))
23895
+ });
23544
23896
  object({
23545
23897
  activeCameras: number(),
23546
23898
  throttledCameras: number(),
@@ -23984,6 +24336,22 @@ var MotionSourceEnum = _enum([
23984
24336
  "device-activity"
23985
24337
  ]);
23986
24338
  /**
24339
+ * What opened an on-motion detection SESSION: the motion source that passed the
24340
+ * camera's `motionSources` gate, and what raised it (the camera itself, or a
24341
+ * sensor the operator attached — D672). `sensorName` is the attached sensor's
24342
+ * device name as the orchestrator's camera-sensors resolution last read it;
24343
+ * absent when unknown or when the camera itself triggered.
24344
+ *
24345
+ * Carried on the session attach ONLY so the runner's `DetectionPhaseTransition`
24346
+ * can say what started the session (D672 rule 11, amended 2026-10-06). The
24347
+ * runner never decides anything on it.
24348
+ */
24349
+ var SessionTriggerSchema = object({
24350
+ source: MotionSourceEnum,
24351
+ triggeredBy: MotionTriggeredBySchema,
24352
+ sensorName: string().optional()
24353
+ });
24354
+ /**
23987
24355
  * List of motion sources active on a camera. Empty array is valid:
23988
24356
  * "no source" — happens for battery cams without firmware motion when
23989
24357
  * the operator hasn't opted into the SW analyzer (would hold the
@@ -24235,6 +24603,14 @@ var RunnerCameraConfigSchema = object({
24235
24603
  */
24236
24604
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24237
24605
  /**
24606
+ * What opened this attach, on a SESSION attach only (see
24607
+ * {@link SessionTriggerSchema}). OPTIONAL with no default: absent on a
24608
+ * standing attach, an occupancy burst, a re-dispatch with no motion event
24609
+ * behind it, and every attach from an orchestrator older than the field — the
24610
+ * runner then names no source on the phase event.
24611
+ */
24612
+ sessionTrigger: SessionTriggerSchema.optional(),
24613
+ /**
24238
24614
  * WHICH root detector runs for this camera. The detection counterpart of
24239
24615
  * {@link motionSources}, same shape and same discipline: a per-camera list
24240
24616
  * of sources the system understands, vendor-agnostic, owned here.
@@ -24394,14 +24770,15 @@ var RunnerLocalLoadSchema = object({
24394
24770
  * Per-inference-device live load (multi-device C4). One entry per deviceKey
24395
24771
  * this runner currently has attached cameras on, so the orchestrator's second
24396
24772
  * `balance()` pass (over a node's devices) weights on real per-pool session
24397
- * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
24398
- * per device is 0 until the pool backlog gets a public accessor (follow-up).
24773
+ * counts. Empty on single-device / pre-multi-device runners. There is no
24774
+ * per-device queue depth: the inference pool's backlog has no accessor, and
24775
+ * a field that always read 0 was removed rather than shown as a measurement
24776
+ * (D762).
24399
24777
  */
24400
24778
  devices: array(object({
24401
24779
  deviceKey: string(),
24402
24780
  backend: string(),
24403
- attachedCameras: number(),
24404
- queueDepthTotal: number()
24781
+ attachedCameras: number()
24405
24782
  })).default([]),
24406
24783
  /** Hardware capability flags reported by this node. */
24407
24784
  hardware: object({
@@ -24537,7 +24914,22 @@ method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mu
24537
24914
  */
24538
24915
  cropJpeg: string().optional(),
24539
24916
  parent: DetailParentSchema,
24540
- steps: array(string()).optional()
24917
+ steps: array(string()).optional(),
24918
+ /**
24919
+ * The camera's root model already drew this step's boxes (D730): a
24920
+ * `license_plate` inside the parent vehicle. The named step is NOT
24921
+ * inferred — these FRAME-space boxes are its output — and its
24922
+ * requested children (the plate reader) run on them. Absent ⇒ every
24923
+ * requested step infers as before.
24924
+ */
24925
+ supplied: object({
24926
+ stepId: string(),
24927
+ modelId: string(),
24928
+ boxes: array(object({
24929
+ bbox: NativeCropBboxSchema,
24930
+ score: number()
24931
+ })).min(1)
24932
+ }).optional()
24541
24933
  }), object({ details: array(DetailResultSchema) }).nullable(), { kind: "mutation" }), method(object({
24542
24934
  /** Catalog step id, e.g. `clip-embedding`. */
24543
24935
  stepId: string(),
@@ -24600,14 +24992,6 @@ var CameraPipelineConfigSchema = object({
24600
24992
  settings: record(string(), unknown()).readonly().optional()
24601
24993
  }).nullable().optional()
24602
24994
  });
24603
- var PipelineTemplateSchema = object({
24604
- id: string(),
24605
- name: string(),
24606
- description: string().optional(),
24607
- config: CameraPipelineConfigSchema,
24608
- createdAt: string(),
24609
- updatedAt: string()
24610
- });
24611
24995
  var DeviceStepConfigSchema = object({
24612
24996
  modelId: string().optional(),
24613
24997
  settings: record(string(), unknown()).optional(),
@@ -24681,9 +25065,10 @@ var CameraStepOverridePatchSchema = object({
24681
25065
  modelId: string().optional(),
24682
25066
  settings: record(string(), unknown()).readonly().optional()
24683
25067
  });
25068
+ var CameraStepSettingsSchema = record(string(), record(string(), unknown()).readonly());
24684
25069
  var CameraPipelineSettingsSchema = object({
24685
- pinnedAgentNodeId: string().optional(),
24686
25070
  stepToggles: record(string(), boolean()).optional(),
25071
+ stepSettings: CameraStepSettingsSchema.optional(),
24687
25072
  stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
24688
25073
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
24689
25074
  });
@@ -24716,7 +25101,10 @@ var PipelineAssignmentSchema = object({
24716
25101
  });
24717
25102
  /**
24718
25103
  * Per-agent load summary surfaced to the load balancer + dashboards.
24719
- * Aggregated from each runner's `getLocalLoad` cap call.
25104
+ * Aggregated from each runner's `getLocalLoad` cap call. In the
25105
+ * `getAgentLoad` report, a single-device node's default-pool sessions (no
25106
+ * `deviceKey`) are credited to its one eligible device in `load.devices` —
25107
+ * the default pool IS that device (D745); the balancer's census stays raw.
24720
25108
  */
24721
25109
  var AgentLoadSummarySchema = object({
24722
25110
  nodeId: string(),
@@ -24805,26 +25193,27 @@ var CameraBrokerStatusSchema = object({
24805
25193
  width: number(),
24806
25194
  height: number(),
24807
25195
  subscribers: number(),
24808
- inFps: number(),
24809
- outFps: number()
25196
+ /**
25197
+ * Encoded packets/s the broker receives from the camera. null when the
25198
+ * broker's stats read failed — unknown, never 0 (a 0 here reads as a stall).
25199
+ * There is no output rate: decoding runs in the session decode workers, not
25200
+ * in the broker, so the broker's own decoded-frame rate is 0 on every live
25201
+ * camera and is not served (D758).
25202
+ */
25203
+ inFps: number().nullable()
24810
25204
  })).readonly(),
24811
25205
  webrtcSessions: number(),
24812
25206
  rtspRestream: boolean()
24813
25207
  });
24814
- /** Shared-memory ring statistics within the decoder block. */
24815
- var CameraDecoderShmSchema = object({
24816
- framesWritten: number(),
24817
- getFrameHits: number(),
24818
- getFrameMisses: number(),
24819
- budgetMb: number()
24820
- });
24821
- /** Decoder block — null when the decoder stage is unreachable or inactive. */
24822
- var CameraDecoderStatusSchema = object({
24823
- nodeId: string(),
24824
- formats: array(string()).readonly(),
24825
- sessionCount: number(),
24826
- shm: CameraDecoderShmSchema
24827
- });
25208
+ /**
25209
+ * Decoder block — WHERE decode runs (co-located with the detection node by
25210
+ * construction); null when the camera has no detection node. It carries no
25211
+ * frame counter: the shared-memory plane whose counters it used to serve is
25212
+ * gone, and those fields read 0 forever. Whether frames actually flow is read
25213
+ * from `detection.actualFps` (frames delivered to and processed by the
25214
+ * detector), never from a counter nothing feeds.
25215
+ */
25216
+ var CameraDecoderStatusSchema = object({ nodeId: string() });
24828
25217
  /** Motion block — null when motion detection is not active for this device. */
24829
25218
  var CameraMotionStatusSchema = object({
24830
25219
  enabled: boolean(),
@@ -25181,12 +25570,6 @@ method(object({
25181
25570
  }), object({ success: literal(true) }), {
25182
25571
  kind: "mutation",
25183
25572
  auth: "admin"
25184
- }), method(object({
25185
- agentNodeId: string(),
25186
- detectWeight: number().positive().nullable()
25187
- }), object({ success: literal(true) }), {
25188
- kind: "mutation",
25189
- auth: "admin"
25190
25573
  }), method(object({
25191
25574
  agentNodeId: string(),
25192
25575
  detect: boolean().nullable().optional(),
@@ -25228,6 +25611,15 @@ method(object({
25228
25611
  }), {
25229
25612
  kind: "mutation",
25230
25613
  auth: "admin"
25614
+ }), method(AutoTuneOptionsSchema, AutoTunePlanSchema, { auth: "admin" }), method(AutoTuneApplyInputSchema, AutoTuneApplyResultSchema, {
25615
+ kind: "mutation",
25616
+ auth: "admin"
25617
+ }), method(LoadBalancingSharesInputSchema, object({ success: literal(true) }), {
25618
+ kind: "mutation",
25619
+ auth: "admin"
25620
+ }), method(PlacementStatsInputSchema, PlacementStatsSchema, { auth: "admin" }), method(SuggestSharesInputSchema, SuggestSharesResultSchema, { auth: "admin" }), method(_void(), EffectiveSharesSchema, { auth: "admin" }), method(SetShareSourceInputSchema, object({ success: literal(true) }), {
25621
+ kind: "mutation",
25622
+ auth: "admin"
25231
25623
  }), method(object({ deviceId: number() }), CameraPipelineSettingsSchema.nullable()), method(object({
25232
25624
  deviceId: number(),
25233
25625
  addonId: string(),
@@ -25244,6 +25636,13 @@ method(object({
25244
25636
  }), object({ success: literal(true) }), {
25245
25637
  kind: "mutation",
25246
25638
  auth: "admin"
25639
+ }), method(object({
25640
+ deviceId: number(),
25641
+ addonId: string(),
25642
+ settings: record(string(), unknown()).nullable()
25643
+ }), object({ success: literal(true) }), {
25644
+ kind: "mutation",
25645
+ auth: "admin"
25247
25646
  }), method(object({
25248
25647
  deviceId: number(),
25249
25648
  agentNodeId: string(),
@@ -25267,25 +25666,7 @@ method(object({
25267
25666
  }), method(_void(), DiskReconcileJobSchema, {
25268
25667
  kind: "mutation",
25269
25668
  auth: "admin"
25270
- }), method(_void(), DiskReconcileJobSchema, { auth: "admin" }), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
25271
- name: string(),
25272
- description: string().optional(),
25273
- config: CameraPipelineConfigSchema
25274
- }), PipelineTemplateSchema, {
25275
- kind: "mutation",
25276
- auth: "admin"
25277
- }), method(object({
25278
- id: string(),
25279
- name: string().optional(),
25280
- description: string().optional(),
25281
- config: CameraPipelineConfigSchema.optional()
25282
- }), PipelineTemplateSchema, {
25283
- kind: "mutation",
25284
- auth: "admin"
25285
- }), method(object({ id: string() }), object({ success: literal(true) }), {
25286
- kind: "mutation",
25287
- auth: "admin"
25288
- });
25669
+ }), method(_void(), DiskReconcileJobSchema, { auth: "admin" });
25289
25670
  /**
25290
25671
  * Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
25291
25672
  * `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
@@ -27505,8 +27886,6 @@ var WebrtcStreamChoiceSchema = object({
27505
27886
  ]).nullable(),
27506
27887
  /** Input FPS from the camera (null for adaptive). */
27507
27888
  inputFps: number().nullable(),
27508
- /** Decoded FPS (null for adaptive). */
27509
- decodeFps: number().nullable(),
27510
27889
  /** Bitrate in kbps (null for adaptive). */
27511
27890
  bitrateKbps: number().nullable()
27512
27891
  });
@@ -27783,7 +28162,22 @@ DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), ar
27783
28162
  * field their hints were silently stripped by the schema and the
27784
28163
  * adaptive ladder started blind on the client's display size.
27785
28164
  */
27786
- hints: webrtcClientHintsSchema.optional()
28165
+ hints: webrtcClientHintsSchema.optional(),
28166
+ /**
28167
+ * Talk-back (D771): relay the PEER's audio to the device's speaker
28168
+ * through the `intercom` cap's push-talk triple. When `true` and the
28169
+ * offer lets the peer send audio, the answer's audio is `sendrecv`
28170
+ * and every inbound frame goes to `intercom.pushTalkAudio` for this
28171
+ * `deviceId`; absent/false answers `sendonly`, as for every viewer.
28172
+ *
28173
+ * TRUSTED-CALLER ONLY. Set by the Alexa export for an Echo on a camera
28174
+ * with `intercom`, when the linked user may control that camera. The
28175
+ * hub STRIPS it from every request-bound call (a browser), exactly as
28176
+ * it overwrites `relayOnly` — a viewer's talk permission is the
28177
+ * intercom cap's own surface (share tokens gate it there), and this
28178
+ * flag must not become a second door to the camera's speaker.
28179
+ */
28180
+ talkback: boolean().optional()
27787
28181
  }), object({
27788
28182
  sessionId: string(),
27789
28183
  sdpAnswer: string()
@@ -27838,6 +28232,14 @@ DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), ar
27838
28232
  */
27839
28233
  alive: boolean()
27840
28234
  })), method(object({
28235
+ deviceId: number().int().nonnegative(),
28236
+ sessionId: string(),
28237
+ downlinkMbps: number().nonnegative()
28238
+ }), object({
28239
+ outcome: _enum(["switching", "held"]),
28240
+ tier: CamProfileSchema.nullable(),
28241
+ reason: string()
28242
+ }), { kind: "mutation" }), method(object({
27841
28243
  deviceId: number().int().nonnegative(),
27842
28244
  sessionId: string()
27843
28245
  }), WebrtcSessionDebugSchema, { kind: "query" });
@@ -28077,6 +28479,59 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
28077
28479
  var RestartAddonResultSchema = unknown();
28078
28480
  var InstallPackageResultSchema = unknown();
28079
28481
  var ReloadPackagesResultSchema = unknown();
28482
+ /**
28483
+ * What an uninstall did on ONE node.
28484
+ * - `uninstalled` — removed: runner(s) stopped, caps gone, code deleted.
28485
+ * - `not-installed` — the node did not have it (nothing to do).
28486
+ * - `refused` — protected / bootstrap package; nothing touched.
28487
+ * - `failed` — attempted and did not complete; `error` says why.
28488
+ * - `pending-reconnect` — the node is OFFLINE: its record was pruned so the
28489
+ * back-fill never returns the package, and the stale-addon sweep removes the
28490
+ * copy when the node registers again (only once the hub no longer has it).
28491
+ */
28492
+ var UninstallNodeOutcomeSchema = _enum([
28493
+ "uninstalled",
28494
+ "not-installed",
28495
+ "refused",
28496
+ "failed",
28497
+ "pending-reconnect"
28498
+ ]);
28499
+ var UninstallNodeResultSchema = object({
28500
+ nodeId: string(),
28501
+ outcome: UninstallNodeOutcomeSchema,
28502
+ error: string().optional(),
28503
+ addonIds: array(string()).readonly(),
28504
+ runnersStopped: array(string()).readonly(),
28505
+ warnings: array(string()).readonly()
28506
+ });
28507
+ var UninstallPackageResultSchema = object({
28508
+ /** Every targeted node ended `uninstalled`, `not-installed` or `pending-reconnect`. */
28509
+ success: boolean(),
28510
+ packageName: string(),
28511
+ results: array(UninstallNodeResultSchema).readonly()
28512
+ });
28513
+ /**
28514
+ * `unreachable` lists online agents whose status read FAILED — absence from
28515
+ * `installations` is only "not installed" for a node that answered (D315).
28516
+ */
28517
+ var PackageInstallationsSchema = object({
28518
+ installations: array(object({
28519
+ packageName: string(),
28520
+ nodeId: string(),
28521
+ nodeName: string(),
28522
+ isHub: boolean(),
28523
+ isOnline: boolean(),
28524
+ version: string().nullable(),
28525
+ addonIds: array(string()).readonly(),
28526
+ source: _enum(["live", "recorded"]),
28527
+ /** The hub installs this package too. `false` on an agent row = an orphan. */
28528
+ onHub: boolean()
28529
+ })).readonly(),
28530
+ unreachable: array(object({
28531
+ nodeId: string(),
28532
+ error: string()
28533
+ })).readonly()
28534
+ });
28080
28535
  var BulkUpdateItemStatusSchema = _enum([
28081
28536
  "queued",
28082
28537
  "updating",
@@ -28159,10 +28614,14 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
28159
28614
  }), method(object({ packageName: string() }), InstallPackageResultSchema, {
28160
28615
  kind: "mutation",
28161
28616
  auth: "admin"
28162
- }), method(_void(), boolean()), method(_void(), array(unknown()).readonly()), method(object({ packageName: string() }), unknown(), {
28617
+ }), method(_void(), boolean()), method(_void(), array(unknown()).readonly()), method(object({
28618
+ packageName: string().min(1),
28619
+ nodeId: string().optional(),
28620
+ everywhere: boolean().optional()
28621
+ }), UninstallPackageResultSchema, {
28163
28622
  kind: "mutation",
28164
28623
  auth: "admin"
28165
- }), method(_void(), ReloadPackagesResultSchema, {
28624
+ }), method(object({ packageName: string().optional() }), PackageInstallationsSchema, { auth: "admin" }), method(_void(), ReloadPackagesResultSchema, {
28166
28625
  kind: "mutation",
28167
28626
  auth: "admin"
28168
28627
  }), method(object({ query: string().optional() }), array(SearchResultSchema)), method(object({ nodeId: string().optional() }), array(PackageUpdateSchema).readonly(), { auth: "admin" }), method(object({
@@ -30458,7 +30917,7 @@ var LocalInterfaceSchema = object({
30458
30917
  name: string(),
30459
30918
  family: _enum(["IPv4", "IPv6"]),
30460
30919
  address: string(),
30461
- /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
30920
+ /** CIDR shorthand (e.g. `192.168.10.10/24`). Empty when OS doesn't expose. */
30462
30921
  cidr: string(),
30463
30922
  /** OS netmask. Stable across calls so the SDK can hash on it. */
30464
30923
  netmask: string(),
@@ -30512,7 +30971,9 @@ var ConnectionEndpointSchema = object({
30512
30971
  "lan-ipv4",
30513
30972
  "lan-ipv6",
30514
30973
  "public",
30515
- "loopback"
30974
+ "loopback",
30975
+ "app-link",
30976
+ "custom"
30516
30977
  ]),
30517
30978
  /**
30518
30979
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -30581,15 +31042,27 @@ var GetConnectionEndpointsResultSchema = object({
30581
31042
  localPort: AdvertisedLocalPortSchema
30582
31043
  });
30583
31044
  /**
30584
- * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
30585
- * AUTO (resolved from the candidate ranking at send time); `resolved` reports
30586
- * what AUTO currently picks, so the UI can show the effective value either way.
31045
+ * The address flagged for notification taps (`notificationTaps`). `baseUrl: null` = AUTO, which
31046
+ * since D709 is the CamStack app link; `resolved` reports the effective value,
31047
+ * so the UI can show it either way.
30587
31048
  */
30588
31049
  var NotificationEndpointSchema = object({
30589
31050
  /** The operator's explicit choice, or null for AUTO. */
30590
31051
  baseUrl: string().nullable(),
30591
- /** What the ranking currently resolves to (null when nothing is reachable). */
30592
- resolved: string().nullable()
31052
+ /**
31053
+ * The effective flagged address: the explicit choice, else (AUTO) the
31054
+ * CamStack app link `https://camstack.zentik.app` (D709). A pre-D709 hub
31055
+ * answered the public tunnel / mesh here, or null.
31056
+ */
31057
+ resolved: string().nullable(),
31058
+ /**
31059
+ * The hub origin an app link carries as `hub=` (D709): the hub's best
31060
+ * public HTTPS address — the tunnel, then the mesh (Tailscale MagicDNS) —
31061
+ * picked from this cap's own palette by `pickAppLinkHub`. `null` when the
31062
+ * hub advertises neither; the app link is then minted without `hub=`.
31063
+ * Absent on a pre-D709 hub.
31064
+ */
31065
+ appLinkHub: string().nullable()
30593
31066
  });
30594
31067
  /**
30595
31068
  * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
@@ -30602,6 +31075,72 @@ var ViewerEndpointsSchema = object({
30602
31075
  /** What the ranking currently resolves to (may be empty if nothing is up). */
30603
31076
  resolved: array(string()).readonly()
30604
31077
  });
31078
+ /**
31079
+ * DEPRECATED compatibility shape of `getHubAddresses` (D729 amendment, kept
31080
+ * for addons built against it): `cluster` is the `internal` role, `browser`
31081
+ * the `publicEndpoint` role; `override` is the flagged address.
31082
+ */
31083
+ var HubAddressSnapshotSchema = object({
31084
+ override: string().nullable(),
31085
+ resolved: string().nullable(),
31086
+ source: _enum([
31087
+ "override",
31088
+ "auto",
31089
+ "none"
31090
+ ])
31091
+ });
31092
+ var HubAddressesSchema = object({
31093
+ cluster: HubAddressSnapshotSchema,
31094
+ browser: HubAddressSnapshotSchema
31095
+ });
31096
+ /**
31097
+ * What an address is used for (`hub-address.ts`, D734). `appConnections` is
31098
+ * many-valued; `notificationTaps`, `publicEndpoint` and `internal` are carried
31099
+ * by at most one address.
31100
+ */
31101
+ var HubAddressRoleSchema = _enum(HUB_ADDRESS_ROLES);
31102
+ var RoleSourceSchema = _enum([
31103
+ "flagged",
31104
+ "auto",
31105
+ "none"
31106
+ ]);
31107
+ /** One single-valued role: the flagged address, the one in use, and why. */
31108
+ var HubAddressRoleResolutionSchema = object({
31109
+ /** The address carrying the flag, or null = automatic. */
31110
+ flagged: string().nullable(),
31111
+ /** The address in use, or null when nothing qualifies (never loopback). */
31112
+ resolved: string().nullable(),
31113
+ source: RoleSourceSchema
31114
+ });
31115
+ var HubAppConnectionsResolutionSchema = object({
31116
+ /** The addresses flagged `appConnections`, or empty = automatic. */
31117
+ flagged: array(string()).readonly(),
31118
+ /** What the apps race right now. */
31119
+ resolved: array(string()).readonly(),
31120
+ source: RoleSourceSchema
31121
+ });
31122
+ var HubAddressBookSchema = object({
31123
+ rows: array(ConnectionEndpointSchema.extend({
31124
+ /** In the hub's detected palette right now. */
31125
+ detected: boolean(),
31126
+ /** Entered by the operator (removable). */
31127
+ custom: boolean(),
31128
+ /** The roles explicitly flagged on this address. */
31129
+ flags: array(HubAddressRoleSchema).readonly(),
31130
+ /** The roles this address serves right now — flagged or automatic. */
31131
+ inUse: array(HubAddressRoleSchema).readonly(),
31132
+ /** The roles this address may be flagged with. */
31133
+ eligible: array(HubAddressRoleSchema).readonly()
31134
+ })).readonly(),
31135
+ roles: object({
31136
+ appConnections: HubAppConnectionsResolutionSchema,
31137
+ notificationTaps: HubAddressRoleResolutionSchema,
31138
+ internal: HubAddressRoleResolutionSchema,
31139
+ publicEndpoint: HubAddressRoleResolutionSchema
31140
+ }),
31141
+ /** The `hub=` an app link carries (D709), or null. */
31142
+ appLinkHub: string().nullable()
31143
+ });
30605
31144
  var AllowedAddressesSchema = object({
30606
31145
  /**
30607
31146
  * Allowlist of interface addresses operators have explicitly opted
@@ -30643,8 +31182,29 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
30643
31182
  * Pass `'https'` when the caller is itself loaded over HTTPS
30644
31183
  * to avoid mixed-content blocks in the browser. The public
30645
31184
  * tunnel always emits `https://` regardless. */
30646
- scheme: _enum(["http", "https"]).optional()
30647
- }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
31185
+ scheme: _enum(["http", "https"]).optional(),
31186
+ /** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
31187
+ * an address notification taps can be flagged with, not a hub
31188
+ * route. Default `false`: racers and rankers never see it. */
31189
+ includeAppLink: boolean().optional()
31190
+ }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(object({ scheme: _enum(["http", "https"]).optional() }).optional(), HubAddressBookSchema), method(object({
31191
+ baseUrl: string(),
31192
+ label: string().max(80)
31193
+ }), HubAddressBookSchema, {
31194
+ kind: "mutation",
31195
+ auth: "admin"
31196
+ }), method(object({ baseUrl: string() }), HubAddressBookSchema, {
31197
+ kind: "mutation",
31198
+ auth: "admin"
31199
+ }), method(object({
31200
+ role: HubAddressRoleSchema,
31201
+ baseUrl: string().nullable(),
31202
+ enabled: boolean(),
31203
+ acceptInsecureHttp: boolean().optional()
31204
+ }), HubAddressBookSchema, {
31205
+ kind: "mutation",
31206
+ auth: "admin"
31207
+ }), method(_void(), HubAddressesSchema), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
30648
31208
  kind: "mutation",
30649
31209
  auth: "admin"
30650
31210
  }), method(object({
@@ -30904,7 +31464,7 @@ var MeshPeerSchema = object({
30904
31464
  tags: array(string()).readonly(),
30905
31465
  /** True when the peer advertises itself as an exit-node candidate. */
30906
31466
  exitNodeOption: boolean(),
30907
- /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
31467
+ /** Subnet routes the peer advertises (e.g. `["192.168.10.0/24"]`). */
30908
31468
  advertisedRoutes: array(string()).readonly(),
30909
31469
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
30910
31470
  userLogin: string().nullable(),
@@ -31034,7 +31594,8 @@ object({
31034
31594
  * writes this slice (not even a boot seed), and neither does the runner's
31035
31595
  * phase machine: its phase is "a session is attached" for every on-motion
31036
31596
  * session, not motion, and it now has its own `DetectionPhaseTransition`.
31037
- * A provider's `isDetected` answers from the hub's slice.
31597
+ * A provider's `isDetected` and `getStatus` answer from the hub's slice
31598
+ * (`hubMotionNativeProvider`).
31038
31599
  * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
31039
31600
  * imports) — the provider pushes both edges itself, from the upstream
31040
31601
  * system's own state change. That is the sensor's own fact.
@@ -31848,7 +32409,13 @@ var OsdStatusSchema = object({ overlays: array(object({
31848
32409
  */
31849
32410
  availablePositions: array(OsdPositionEnum).readonly(),
31850
32411
  /** Firmware does not allow editing the `text` field (e.g. timestamp). */
31851
- readOnly: boolean().optional()
32412
+ readOnly: boolean().optional(),
32413
+ /**
32414
+ * Firmware text ceiling for this overlay. Absent = no known limit.
32415
+ * The OSD manager truncates here on every write — never stores its own
32416
+ * copy on the binding.
32417
+ */
32418
+ maxCharacters: number().int().positive().optional()
31852
32419
  })).readonly() });
31853
32420
  var OsdOverlayPatchSchema = object({
31854
32421
  enabled: boolean().optional(),
@@ -31899,7 +32466,9 @@ var OsdTemplateBindingSchema = object({
31899
32466
  valuePath: string().min(1).max(64),
31900
32467
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
31901
32468
  displayUnit: string().max(16).optional(),
31902
- maxDecimals: number().int().min(0).max(4).default(1)
32469
+ maxDecimals: number().int().min(0).max(4).default(1),
32470
+ /** Raw value → display text (same shape as slot binding). Empty string hides. */
32471
+ valueMap: record(string(), string()).optional()
31903
32472
  });
31904
32473
  /**
31905
32474
  * A named template: bindings (alias → leaf field) + a parser that
@@ -31949,18 +32518,11 @@ var OsdSlotBindingSchema = object({
31949
32518
  source: OsdSourceSchema,
31950
32519
  /** `${value}` and `${unit}` are substituted; every occurrence. */
31951
32520
  template: string().max(96).default("${value}"),
31952
- /** Truncate with an ellipsis past this length. Absent = no limit. */
31953
- maxCharacters: number().int().min(4).max(64).optional(),
31954
32521
  /**
31955
32522
  * Decimal places for a numeric value. `0` yields an integer — the
31956
32523
  * documented workaround for firmwares that reject `.` in overlay text.
31957
32524
  */
31958
32525
  maxDecimals: number().int().min(0).max(4).default(1),
31959
- /**
31960
- * Appended via `${unit}` when no unit conversion produces a label.
31961
- * Prefer `source.displayUnit` for converted device-state values.
31962
- */
31963
- unitLabel: string().max(8).optional(),
31964
32526
  /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
31965
32527
  valueMap: record(string(), string()).optional(),
31966
32528
  /** Time windows in which the slot is shown. Absent = always. */
@@ -31969,9 +32531,7 @@ var OsdSlotBindingSchema = object({
31969
32531
  * Display gate, in the notification centre's condition vocabulary.
31970
32532
  * Only the keys reported by `getConditionSupport` are accepted.
31971
32533
  */
31972
- conditions: NcConditionsSchema.optional(),
31973
- /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
31974
- fallbackText: string().max(64).default("")
32534
+ conditions: NcConditionsSchema.optional()
31975
32535
  });
31976
32536
  /** One camera slot, as the operator sees it: firmware truth + our binding. */
31977
32537
  var OsdSlotViewSchema = object({
@@ -36166,6 +36726,16 @@ DeviceType.Camera, method(object({
36166
36726
  package: array(ZoneRuleSchema).readonly()
36167
36727
  });
36168
36728
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
36729
+ Object.freeze({
36730
+ person: .5,
36731
+ vehicle: .5,
36732
+ animal: .5
36733
+ });
36734
+ Object.freeze({
36735
+ person: .65,
36736
+ vehicle: .65,
36737
+ animal: .65
36738
+ });
36169
36739
  /**
36170
36740
  * Accessory device helpers — shared across drivers.
36171
36741
  *
@@ -36340,6 +36910,12 @@ Object.freeze({
36340
36910
  addonId: null,
36341
36911
  access: "view"
36342
36912
  },
36913
+ "addons.listInstallations": {
36914
+ capName: "addons",
36915
+ capScope: "system",
36916
+ addonId: null,
36917
+ access: "view"
36918
+ },
36343
36919
  "addons.listJobs": {
36344
36920
  capName: "addons",
36345
36921
  capScope: "system",
@@ -37522,90 +38098,18 @@ Object.freeze({
37522
38098
  addonId: null,
37523
38099
  access: "create"
37524
38100
  },
37525
- "decoder.createSession": {
37526
- capName: "decoder",
37527
- capScope: "system",
37528
- addonId: null,
37529
- access: "view"
37530
- },
37531
- "decoder.destroySession": {
37532
- capName: "decoder",
37533
- capScope: "system",
37534
- addonId: null,
37535
- access: "delete"
37536
- },
37537
- "decoder.getFrame": {
37538
- capName: "decoder",
37539
- capScope: "system",
37540
- addonId: null,
37541
- access: "view"
37542
- },
37543
38101
  "decoder.getInfo": {
37544
38102
  capName: "decoder",
37545
38103
  capScope: "system",
37546
38104
  addonId: null,
37547
38105
  access: "view"
37548
38106
  },
37549
- "decoder.getShmStats": {
37550
- capName: "decoder",
37551
- capScope: "system",
37552
- addonId: null,
37553
- access: "view"
37554
- },
37555
- "decoder.getStats": {
37556
- capName: "decoder",
37557
- capScope: "system",
37558
- addonId: null,
37559
- access: "view"
37560
- },
37561
- "decoder.listActiveSessions": {
37562
- capName: "decoder",
37563
- capScope: "system",
37564
- addonId: null,
37565
- access: "view"
37566
- },
37567
- "decoder.openStream": {
37568
- capName: "decoder",
37569
- capScope: "system",
37570
- addonId: null,
37571
- access: "view"
37572
- },
37573
- "decoder.pullFrames": {
37574
- capName: "decoder",
37575
- capScope: "system",
37576
- addonId: null,
37577
- access: "view"
37578
- },
37579
- "decoder.pullHandles": {
37580
- capName: "decoder",
37581
- capScope: "system",
37582
- addonId: null,
37583
- access: "view"
37584
- },
37585
- "decoder.pushPacket": {
37586
- capName: "decoder",
37587
- capScope: "system",
37588
- addonId: null,
37589
- access: "view"
37590
- },
37591
38107
  "decoder.reprobeHwaccel": {
37592
38108
  capName: "decoder",
37593
38109
  capScope: "system",
37594
38110
  addonId: null,
37595
38111
  access: "create"
37596
38112
  },
37597
- "decoder.supportsCodec": {
37598
- capName: "decoder",
37599
- capScope: "system",
37600
- addonId: null,
37601
- access: "view"
37602
- },
37603
- "decoder.updateConfig": {
37604
- capName: "decoder",
37605
- capScope: "system",
37606
- addonId: null,
37607
- access: "view"
37608
- },
37609
38113
  "detectionPipeline.applyDeviceSettingsPatch": {
37610
38114
  capName: "detection-pipeline",
37611
38115
  capScope: "device",
@@ -39094,12 +39598,24 @@ Object.freeze({
39094
39598
  addonId: null,
39095
39599
  access: "view"
39096
39600
  },
39601
+ "localNetwork.addCustomAddress": {
39602
+ capName: "local-network",
39603
+ capScope: "system",
39604
+ addonId: null,
39605
+ access: "create"
39606
+ },
39097
39607
  "localNetwork.downloadCa": {
39098
39608
  capName: "local-network",
39099
39609
  capScope: "system",
39100
39610
  addonId: null,
39101
39611
  access: "view"
39102
39612
  },
39613
+ "localNetwork.getAddresses": {
39614
+ capName: "local-network",
39615
+ capScope: "system",
39616
+ addonId: null,
39617
+ access: "view"
39618
+ },
39103
39619
  "localNetwork.getAllowedAddresses": {
39104
39620
  capName: "local-network",
39105
39621
  capScope: "system",
@@ -39112,6 +39628,12 @@ Object.freeze({
39112
39628
  addonId: null,
39113
39629
  access: "view"
39114
39630
  },
39631
+ "localNetwork.getHubAddresses": {
39632
+ capName: "local-network",
39633
+ capScope: "system",
39634
+ addonId: null,
39635
+ access: "view"
39636
+ },
39115
39637
  "localNetwork.getNotificationEndpoint": {
39116
39638
  capName: "local-network",
39117
39639
  capScope: "system",
@@ -39148,6 +39670,12 @@ Object.freeze({
39148
39670
  addonId: null,
39149
39671
  access: "create"
39150
39672
  },
39673
+ "localNetwork.removeCustomAddress": {
39674
+ capName: "local-network",
39675
+ capScope: "system",
39676
+ addonId: null,
39677
+ access: "delete"
39678
+ },
39151
39679
  "localNetwork.resetAllowlistToBestMatch": {
39152
39680
  capName: "local-network",
39153
39681
  capScope: "system",
@@ -39160,6 +39688,12 @@ Object.freeze({
39160
39688
  addonId: null,
39161
39689
  access: "create"
39162
39690
  },
39691
+ "localNetwork.setAddressRole": {
39692
+ capName: "local-network",
39693
+ capScope: "system",
39694
+ addonId: null,
39695
+ access: "create"
39696
+ },
39163
39697
  "localNetwork.setAllowedAddresses": {
39164
39698
  capName: "local-network",
39165
39699
  capScope: "system",
@@ -40654,13 +41188,13 @@ Object.freeze({
40654
41188
  addonId: null,
40655
41189
  access: "delete"
40656
41190
  },
40657
- "pipelineExecutor.deleteModel": {
41191
+ "pipelineExecutor.clearModelBoundDeviceOverrides": {
40658
41192
  capName: "pipeline-executor",
40659
41193
  capScope: "system",
40660
41194
  addonId: null,
40661
41195
  access: "delete"
40662
41196
  },
40663
- "pipelineExecutor.deleteTemplate": {
41197
+ "pipelineExecutor.deleteModel": {
40664
41198
  capName: "pipeline-executor",
40665
41199
  capScope: "system",
40666
41200
  addonId: null,
@@ -40804,12 +41338,6 @@ Object.freeze({
40804
41338
  addonId: null,
40805
41339
  access: "view"
40806
41340
  },
40807
- "pipelineExecutor.listTemplates": {
40808
- capName: "pipeline-executor",
40809
- capScope: "system",
40810
- addonId: null,
40811
- access: "view"
40812
- },
40813
41341
  "pipelineExecutor.rearmInferenceDevice": {
40814
41342
  capName: "pipeline-executor",
40815
41343
  capScope: "system",
@@ -40834,12 +41362,6 @@ Object.freeze({
40834
41362
  addonId: null,
40835
41363
  access: "create"
40836
41364
  },
40837
- "pipelineExecutor.saveTemplate": {
40838
- capName: "pipeline-executor",
40839
- capScope: "system",
40840
- addonId: null,
40841
- access: "create"
40842
- },
40843
41365
  "pipelineExecutor.setVideoPipelineSteps": {
40844
41366
  capName: "pipeline-executor",
40845
41367
  capScope: "system",
@@ -40858,41 +41380,35 @@ Object.freeze({
40858
41380
  addonId: null,
40859
41381
  access: "create"
40860
41382
  },
40861
- "pipelineExecutor.updateTemplate": {
40862
- capName: "pipeline-executor",
40863
- capScope: "system",
40864
- addonId: null,
40865
- access: "create"
40866
- },
40867
41383
  "pipelineExecutor.validatePipeline": {
40868
41384
  capName: "pipeline-executor",
40869
41385
  capScope: "system",
40870
41386
  addonId: null,
40871
41387
  access: "view"
40872
41388
  },
40873
- "pipelineOrchestrator.applyDeviceSettingsPatch": {
41389
+ "pipelineOrchestrator.applyAutoTune": {
40874
41390
  capName: "pipeline-orchestrator",
40875
41391
  capScope: "system",
40876
41392
  addonId: null,
40877
41393
  access: "create"
40878
41394
  },
40879
- "pipelineOrchestrator.assignAudio": {
41395
+ "pipelineOrchestrator.applyDeviceSettingsPatch": {
40880
41396
  capName: "pipeline-orchestrator",
40881
41397
  capScope: "system",
40882
41398
  addonId: null,
40883
41399
  access: "create"
40884
41400
  },
40885
- "pipelineOrchestrator.assignPipeline": {
41401
+ "pipelineOrchestrator.assignAudio": {
40886
41402
  capName: "pipeline-orchestrator",
40887
41403
  capScope: "system",
40888
41404
  addonId: null,
40889
41405
  access: "create"
40890
41406
  },
40891
- "pipelineOrchestrator.deleteTemplate": {
41407
+ "pipelineOrchestrator.assignPipeline": {
40892
41408
  capName: "pipeline-orchestrator",
40893
41409
  capScope: "system",
40894
41410
  addonId: null,
40895
- access: "delete"
41411
+ access: "create"
40896
41412
  },
40897
41413
  "pipelineOrchestrator.getAgentLoad": {
40898
41414
  capName: "pipeline-orchestrator",
@@ -40984,6 +41500,12 @@ Object.freeze({
40984
41500
  addonId: null,
40985
41501
  access: "view"
40986
41502
  },
41503
+ "pipelineOrchestrator.getEffectiveShares": {
41504
+ capName: "pipeline-orchestrator",
41505
+ capScope: "system",
41506
+ addonId: null,
41507
+ access: "view"
41508
+ },
40987
41509
  "pipelineOrchestrator.getGlobalMetrics": {
40988
41510
  capName: "pipeline-orchestrator",
40989
41511
  capScope: "system",
@@ -41020,19 +41542,19 @@ Object.freeze({
41020
41542
  addonId: null,
41021
41543
  access: "view"
41022
41544
  },
41023
- "pipelineOrchestrator.getReconcileFromDiskStatus": {
41545
+ "pipelineOrchestrator.getPlacementStats": {
41024
41546
  capName: "pipeline-orchestrator",
41025
41547
  capScope: "system",
41026
41548
  addonId: null,
41027
41549
  access: "view"
41028
41550
  },
41029
- "pipelineOrchestrator.listAgentSettings": {
41551
+ "pipelineOrchestrator.getReconcileFromDiskStatus": {
41030
41552
  capName: "pipeline-orchestrator",
41031
41553
  capScope: "system",
41032
41554
  addonId: null,
41033
41555
  access: "view"
41034
41556
  },
41035
- "pipelineOrchestrator.listTemplates": {
41557
+ "pipelineOrchestrator.listAgentSettings": {
41036
41558
  capName: "pipeline-orchestrator",
41037
41559
  capScope: "system",
41038
41560
  addonId: null,
@@ -41044,6 +41566,12 @@ Object.freeze({
41044
41566
  addonId: null,
41045
41567
  access: "create"
41046
41568
  },
41569
+ "pipelineOrchestrator.planAutoTune": {
41570
+ capName: "pipeline-orchestrator",
41571
+ capScope: "system",
41572
+ addonId: null,
41573
+ access: "view"
41574
+ },
41047
41575
  "pipelineOrchestrator.rebalance": {
41048
41576
  capName: "pipeline-orchestrator",
41049
41577
  capScope: "system",
@@ -41086,12 +41614,6 @@ Object.freeze({
41086
41614
  addonId: null,
41087
41615
  access: "create"
41088
41616
  },
41089
- "pipelineOrchestrator.saveTemplate": {
41090
- capName: "pipeline-orchestrator",
41091
- capScope: "system",
41092
- addonId: null,
41093
- access: "create"
41094
- },
41095
41617
  "pipelineOrchestrator.setAgentCapabilities": {
41096
41618
  capName: "pipeline-orchestrator",
41097
41619
  capScope: "system",
@@ -41104,12 +41626,6 @@ Object.freeze({
41104
41626
  addonId: null,
41105
41627
  access: "create"
41106
41628
  },
41107
- "pipelineOrchestrator.setAgentDetectWeight": {
41108
- capName: "pipeline-orchestrator",
41109
- capScope: "system",
41110
- addonId: null,
41111
- access: "create"
41112
- },
41113
41629
  "pipelineOrchestrator.setAgentInferenceDevices": {
41114
41630
  capName: "pipeline-orchestrator",
41115
41631
  capScope: "system",
@@ -41146,6 +41662,12 @@ Object.freeze({
41146
41662
  addonId: null,
41147
41663
  access: "create"
41148
41664
  },
41665
+ "pipelineOrchestrator.setCameraStepSettings": {
41666
+ capName: "pipeline-orchestrator",
41667
+ capScope: "system",
41668
+ addonId: null,
41669
+ access: "create"
41670
+ },
41149
41671
  "pipelineOrchestrator.setCameraStepToggle": {
41150
41672
  capName: "pipeline-orchestrator",
41151
41673
  capScope: "system",
@@ -41164,25 +41686,37 @@ Object.freeze({
41164
41686
  addonId: null,
41165
41687
  access: "create"
41166
41688
  },
41689
+ "pipelineOrchestrator.setLoadBalancingShares": {
41690
+ capName: "pipeline-orchestrator",
41691
+ capScope: "system",
41692
+ addonId: null,
41693
+ access: "create"
41694
+ },
41167
41695
  "pipelineOrchestrator.setPipelineDevicePin": {
41168
41696
  capName: "pipeline-orchestrator",
41169
41697
  capScope: "system",
41170
41698
  addonId: null,
41171
41699
  access: "create"
41172
41700
  },
41173
- "pipelineOrchestrator.unassignAudio": {
41701
+ "pipelineOrchestrator.setShareSource": {
41174
41702
  capName: "pipeline-orchestrator",
41175
41703
  capScope: "system",
41176
41704
  addonId: null,
41177
41705
  access: "create"
41178
41706
  },
41179
- "pipelineOrchestrator.unassignPipeline": {
41707
+ "pipelineOrchestrator.suggestShares": {
41708
+ capName: "pipeline-orchestrator",
41709
+ capScope: "system",
41710
+ addonId: null,
41711
+ access: "view"
41712
+ },
41713
+ "pipelineOrchestrator.unassignAudio": {
41180
41714
  capName: "pipeline-orchestrator",
41181
41715
  capScope: "system",
41182
41716
  addonId: null,
41183
41717
  access: "create"
41184
41718
  },
41185
- "pipelineOrchestrator.updateTemplate": {
41719
+ "pipelineOrchestrator.unassignPipeline": {
41186
41720
  capName: "pipeline-orchestrator",
41187
41721
  capScope: "system",
41188
41722
  addonId: null,
@@ -42622,12 +43156,6 @@ Object.freeze({
42622
43156
  addonId: null,
42623
43157
  access: "view"
42624
43158
  },
42625
- "streamBroker.pullFrameHandles": {
42626
- capName: "stream-broker",
42627
- capScope: "system",
42628
- addonId: null,
42629
- access: "view"
42630
- },
42631
43159
  "streamBroker.regenerateRtspToken": {
42632
43160
  capName: "stream-broker",
42633
43161
  capScope: "system",
@@ -42694,12 +43222,6 @@ Object.freeze({
42694
43222
  addonId: null,
42695
43223
  access: "create"
42696
43224
  },
42697
- "streamBroker.subscribeFrames": {
42698
- capName: "stream-broker",
42699
- capScope: "system",
42700
- addonId: null,
42701
- access: "create"
42702
- },
42703
43225
  "streamBroker.unassignProfile": {
42704
43226
  capName: "stream-broker",
42705
43227
  capScope: "system",
@@ -42712,12 +43234,6 @@ Object.freeze({
42712
43234
  addonId: null,
42713
43235
  access: "create"
42714
43236
  },
42715
- "streamBroker.unsubscribeFrames": {
42716
- capName: "stream-broker",
42717
- capScope: "system",
42718
- addonId: null,
42719
- access: "create"
42720
- },
42721
43237
  "streamCatalog.getCatalog": {
42722
43238
  capName: "stream-catalog",
42723
43239
  capScope: "device",
@@ -43414,6 +43930,12 @@ Object.freeze({
43414
43930
  addonId: null,
43415
43931
  access: "create"
43416
43932
  },
43933
+ "webrtcSession.applyDownlinkProbe": {
43934
+ capName: "webrtc-session",
43935
+ capScope: "device",
43936
+ addonId: null,
43937
+ access: "create"
43938
+ },
43417
43939
  "webrtcSession.closeSession": {
43418
43940
  capName: "webrtc-session",
43419
43941
  capScope: "device",
@@ -45225,11 +45747,6 @@ Object.freeze({
45225
45747
  form: "single",
45226
45748
  optional: false
45227
45749
  }],
45228
- "decoder.createSession": [{
45229
- name: "deviceId",
45230
- form: "single",
45231
- optional: true
45232
- }],
45233
45750
  "detectionPipeline.applyDeviceSettingsPatch": [{
45234
45751
  name: "deviceId",
45235
45752
  form: "single",
@@ -46460,6 +46977,11 @@ Object.freeze({
46460
46977
  form: "single",
46461
46978
  optional: false
46462
46979
  }],
46980
+ "pipelineExecutor.clearModelBoundDeviceOverrides": [{
46981
+ name: "deviceIds",
46982
+ form: "array",
46983
+ optional: true
46984
+ }],
46463
46985
  "pipelineExecutor.runPipeline": [{
46464
46986
  name: "deviceId",
46465
46987
  form: "single",
@@ -46565,6 +47087,11 @@ Object.freeze({
46565
47087
  form: "single",
46566
47088
  optional: false
46567
47089
  }],
47090
+ "pipelineOrchestrator.setCameraStepSettings": [{
47091
+ name: "deviceId",
47092
+ form: "single",
47093
+ optional: false
47094
+ }],
46568
47095
  "pipelineOrchestrator.setCameraStepToggle": [{
46569
47096
  name: "deviceId",
46570
47097
  form: "single",
@@ -47336,6 +47863,11 @@ Object.freeze({
47336
47863
  form: "single",
47337
47864
  optional: false
47338
47865
  }],
47866
+ "webrtcSession.applyDownlinkProbe": [{
47867
+ name: "deviceId",
47868
+ form: "single",
47869
+ optional: false
47870
+ }],
47339
47871
  "webrtcSession.closeSession": [{
47340
47872
  name: "deviceId",
47341
47873
  form: "single",
@@ -47565,6 +48097,8 @@ new Map(Object.entries({
47565
48097
  "detection-blind": "device-events",
47566
48098
  "node-online": "system",
47567
48099
  "node-offline": "system",
48100
+ "node-restarting": "system",
48101
+ "node-updating": "system",
47568
48102
  "node-inference-unavailable": "system",
47569
48103
  "addon-crash-loop": "system",
47570
48104
  "addon-update-available": "system",
@@ -47642,18 +48176,21 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
47642
48176
  kinds: [
47643
48177
  "node-offline",
47644
48178
  "node-online",
48179
+ "node-restarting",
47645
48180
  "node-inference-unavailable"
47646
48181
  ]
47647
48182
  },
47648
48183
  {
47649
48184
  id: "addons",
47650
48185
  family: "system",
47651
- label: "Addons",
47652
- kinds: [
47653
- "addon-crash-loop",
47654
- "addon-update-available",
47655
- "addon-updated"
47656
- ]
48186
+ label: "Addons stopped",
48187
+ kinds: ["addon-crash-loop"]
48188
+ },
48189
+ {
48190
+ id: "addon-updates",
48191
+ family: "system",
48192
+ label: "Addon updates",
48193
+ kinds: ["addon-update-available", "addon-updated"]
47657
48194
  },
47658
48195
  {
47659
48196
  id: "updates",
@@ -47661,6 +48198,7 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
47661
48198
  label: "Server & container updates",
47662
48199
  kinds: [
47663
48200
  "server-update-available",
48201
+ "node-updating",
47664
48202
  "server-updated",
47665
48203
  "wrapper-update-available"
47666
48204
  ]
@@ -47808,18 +48346,21 @@ var STATE_SUMMARY_SECTION_VARS = [
47808
48346
  kinds: [
47809
48347
  "node-offline",
47810
48348
  "node-online",
48349
+ "node-restarting",
47811
48350
  "node-inference-unavailable"
47812
48351
  ]
47813
48352
  },
47814
48353
  {
47815
48354
  name: "summaryAddons",
47816
- label: "Summary: addons",
47817
- example: "@camstack/addon-recorder 1.2.3 → 1.2.4",
47818
- kinds: [
47819
- "addon-crash-loop",
47820
- "addon-update-available",
47821
- "addon-updated"
47822
- ]
48355
+ label: "Summary: addons stopped",
48356
+ example: "hub — recorder stopped after repeated crashes",
48357
+ kinds: ["addon-crash-loop"]
48358
+ },
48359
+ {
48360
+ name: "summaryAddonUpdates",
48361
+ label: "Summary: addon updates",
48362
+ example: "hub:\n• @camstack/addon-recorder 1.2.3 → 1.2.4",
48363
+ kinds: ["addon-update-available", "addon-updated"]
47823
48364
  },
47824
48365
  {
47825
48366
  name: "summaryUpdates",
@@ -47827,6 +48368,7 @@ var STATE_SUMMARY_SECTION_VARS = [
47827
48368
  example: "server 1.2.377 → 1.2.378",
47828
48369
  kinds: [
47829
48370
  "server-update-available",
48371
+ "node-updating",
47830
48372
  "server-updated",
47831
48373
  "wrapper-update-available"
47832
48374
  ]
@@ -47859,7 +48401,7 @@ var STATE_SUMMARY_VARS = [
47859
48401
  {
47860
48402
  name: "summarySection",
47861
48403
  label: "Summary: this section",
47862
- description: "The section a per-section summary row is about (D698); on a summary sent as one message, every section it reports, comma-separated.",
48404
+ description: "The section a per-section summary row is about; on a summary sent as one message, every section it reports, comma-separated.",
47863
48405
  example: "Batterie scariche",
47864
48406
  group: "system",
47865
48407
  families: ["rule"],
@@ -47903,6 +48445,7 @@ var STATE_SUMMARY_VARS = [
47903
48445
  [...RULE_BODY_ONLY],
47904
48446
  [...RULE_TEXT],
47905
48447
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
48448
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
47906
48449
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
47907
48450
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
47908
48451
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -47943,6 +48486,8 @@ var STATE_SUMMARY_VARS = [
47943
48486
  [...RULE_TEXT],
47944
48487
  [...RULE_TEXT],
47945
48488
  [...RULE_TEXT],
48489
+ [...RULE_TEXT],
48490
+ [...RULE_TEXT],
47946
48491
  ...STATE_SUMMARY_VARS
47947
48492
  ];
47948
48493
  new Set([
@@ -80781,6 +81326,8 @@ var DEFAULT_CONFIG = {
80781
81326
  embeddedClients: [],
80782
81327
  embeddedAcl: []
80783
81328
  };
81329
+ /** The section that edits `config.brokers`, the same store the broker cap lists. */
81330
+ var EXTERNAL_BROKERS_SECTION_ID = "mqtt-broker-external";
80784
81331
  var MqttBrokerAddon = class extends BaseAddon {
80785
81332
  embeddedRuntime = null;
80786
81333
  /** Per-entry onboard `aedes` runtimes, keyed by `ExternalBrokerEntry.id`. */
@@ -81563,10 +82110,26 @@ var MqttBrokerAddon = class extends BaseAddon {
81563
82110
  }
81564
82111
  });
81565
82112
  }
81566
- globalSettingsSchema() {
82113
+ /**
82114
+ * Under the unified `broker` cap (Connectivity → MQTT Broker) the external
82115
+ * brokers are the CONNECTIONS that page's own panel lists and edits through
82116
+ * `broker.list` / `add` / `setSettings`, all over `config.brokers`. Drawing
82117
+ * the editable array as well would put two "Add broker" editors for ONE
82118
+ * store on one page, so that scope leaves it out; the addon's full page (no
82119
+ * cap) keeps it.
82120
+ */
82121
+ globalSettingsSchema(cap) {
82122
+ const schema = this.fullSettingsSchema();
82123
+ if (cap !== brokerCapability.name) return schema;
82124
+ return {
82125
+ ...schema,
82126
+ sections: schema.sections.filter((s) => s.id !== EXTERNAL_BROKERS_SECTION_ID)
82127
+ };
82128
+ }
82129
+ fullSettingsSchema() {
81567
82130
  return this.schema({ sections: [
81568
82131
  {
81569
- id: "mqtt-broker-external",
82132
+ id: EXTERNAL_BROKERS_SECTION_ID,
81570
82133
  title: "External brokers",
81571
82134
  description: "Brokers running outside CamStack (mosquitto, EMQX, HiveMQ, cloud bridges, …). Passwords are encrypted at rest.",
81572
82135
  columns: 1,