@camstack/addon-mqtt-broker 1.2.119 → 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.
@@ -39,7 +39,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
39
39
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
40
40
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
41
41
  //#endregion
42
- //#region ../types/dist/event-category-BGmz_oxW.mjs
42
+ //#region ../types/dist/event-category-B_0XEcLF.mjs
43
43
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
44
44
  EventCategory["SystemBoot"] = "system.boot";
45
45
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -540,15 +540,6 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
540
540
  EventCategory["AgentWsDisconnected"] = "agent.ws.disconnected";
541
541
  EventCategory["AgentBackupActivated"] = "agent.backup.activated";
542
542
  EventCategory["OrchestrationSettingsUpdated"] = "orchestration.settings-updated";
543
- /**
544
- * Per-agent hwaccel preference changed (user override set, cleared, or
545
- * re-probed). Observability event — decoders pull the current pref at
546
- * `createSession`, so running sessions keep their current backend until
547
- * they rotate naturally (camera add/remove, stream restart). Future
548
- * work can wire a listener in stream-broker that force-rotates live
549
- * sessions; for now this event powers logs + admin-UI toast feedback.
550
- */
551
- EventCategory["PipelineAgentHwaccelChanged"] = "pipeline.agent-hwaccel-changed";
552
543
  EventCategory["MotionAnalysis"] = "detection.motion-analysis";
553
544
  /** All raw motion zones from CCL before minArea filter — for UI debug overlay. */
554
545
  EventCategory["MotionZonesRaw"] = "detection.motion-zones-raw";
@@ -5419,7 +5410,7 @@ var ZodIssueCode = {
5419
5410
  var ZodFirstPartyTypeKind;
5420
5411
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5421
5412
  //#endregion
5422
- //#region ../types/dist/sleep-DXKLNFvA.mjs
5413
+ //#region ../types/dist/sleep-BNeXenvr.mjs
5423
5414
  /**
5424
5415
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5425
5416
  * window to float samples (D455).
@@ -6785,32 +6776,12 @@ object({
6785
6776
  audioCodec: string().optional(),
6786
6777
  metadata: record(string(), unknown()).readonly().optional()
6787
6778
  });
6788
- var EncodedPacketSchema = object({
6789
- type: _enum(["video", "audio"]),
6790
- data: _instanceof(Uint8Array),
6791
- pts: number(),
6792
- dts: number(),
6793
- keyframe: boolean(),
6794
- codec: string()
6795
- });
6796
- var DecodedFrameSchema = object({
6797
- data: _instanceof(Uint8Array),
6798
- width: number(),
6799
- height: number(),
6800
- format: _enum([
6801
- "jpeg",
6802
- "rgb",
6803
- "bgr",
6804
- "yuv420",
6805
- "gray"
6806
- ]),
6807
- timestamp: number()
6808
- });
6809
6779
  /**
6810
6780
  * Wire schema for `FrameHandle` — a zero-pixel, serialisable reference to a
6811
6781
  * frame in a shared-memory ring (Phase 5 / D9). Mirrors the `FrameHandle` TS
6812
- * interface in `interfaces/frame-handle.ts` field-for-field so a decoder cap
6813
- * method (`pullHandles`) can carry handles over tRPC / Moleculer.
6782
+ * interface in `interfaces/frame-handle.ts` field-for-field so a cap method
6783
+ * (the runner's native-crop and pipeline-executor inputs) can carry handles
6784
+ * over tRPC / Moleculer.
6814
6785
  *
6815
6786
  * The `satisfies` assertion below pins this schema to the interface: if a
6816
6787
  * field is added to / removed from `FrameHandle` without a matching schema
@@ -6836,50 +6807,6 @@ var FrameHandleSchema = object({
6836
6807
  slotCount: number().int().positive()
6837
6808
  });
6838
6809
  /**
6839
- * Pixel format a frame-handle subscriber can request from the broker
6840
- * (Phase 5 / D9). The packed, raster subset of `FrameFormat` — the formats a
6841
- * `frameSink: 'shm'` decoder session can write into a `FrameRing` slot.
6842
- * `jpeg` is excluded: a variable-length stream is not a fixed-stride ring
6843
- * payload, and no decoded-frame consumer requests it over the shm plane.
6844
- */
6845
- var FrameHandleFormatSchema = _enum([
6846
- "rgb",
6847
- "bgr",
6848
- "yuv420",
6849
- "gray"
6850
- ]);
6851
- /**
6852
- * Input for `stream-broker.subscribeFrames` (Phase 5 / D9). A consumer asks the
6853
- * broker for a `FrameHandle` stream of one `format`; the broker maintains one
6854
- * shared-memory ring per `(brokerId, format)` actually requested, so a `gray`
6855
- * subscriber (motion) and an `rgb` subscriber (detection) each read the format
6856
- * they asked for with no broker-side conversion.
6857
- */
6858
- var SubscribeFramesInputSchema = object({
6859
- brokerId: string(),
6860
- format: FrameHandleFormatSchema,
6861
- /**
6862
- * Optional reader-side cadence hint in frames per second. The broker does
6863
- * NOT throttle — latest-wins ring reads drop frames implicitly for a slow
6864
- * consumer. The value is echoed back in `SubscribeFramesResult.maxFps` so
6865
- * the consumer can pace its own `pullFrameHandles` polling.
6866
- */
6867
- maxFps: number().positive().optional(),
6868
- /** Short caller-identity tag (`motion`, `detection`, …) for diagnostics. */
6869
- tag: string().optional()
6870
- });
6871
- /**
6872
- * Result of `stream-broker.subscribeFrames`. The consumer then polls
6873
- * `pullFrameHandles({ subscriptionId, maxCount })` and feeds each returned
6874
- * `FrameHandle` to a `FrameRingReader`.
6875
- */
6876
- var SubscribeFramesResultSchema = object({
6877
- /** Opaque id the consumer passes to `pullFrameHandles` / `unsubscribeFrames`. */
6878
- subscriptionId: string(),
6879
- /** Reader-side cadence hint (frames/s) — echoes `SubscribeFramesInput.maxFps`. */
6880
- maxFps: number().nonnegative()
6881
- });
6882
- /**
6883
6810
  * Wire schema for a decoded audio chunk (Phase 5 / D9). Mirrors the
6884
6811
  * `DecodedAudioChunk` TS interface in `interfaces/stream-broker.ts`: PCM
6885
6812
  * sample bytes plus the track parameters a consumer needs to interpret them.
@@ -6887,8 +6814,8 @@ var SubscribeFramesResultSchema = object({
6887
6814
  * Audio chunks are tiny (a ~500ms AudioCodecSession window is a few KB of
6888
6815
  * Float32 PCM), so unlike video frames they ship their bytes INLINE over
6889
6816
  * tRPC / Moleculer — no shared-memory plane. `data` is typed `Uint8Array`
6890
- * (the wire-serialisable supertype of `Buffer`) to match `DecodedFrameSchema`
6891
- * / `EncodedPacketSchema`'s precedent; a `Buffer` is assignable to it.
6817
+ * (the wire-serialisable supertype of `Buffer`); a `Buffer` is assignable to
6818
+ * it.
6892
6819
  */
6893
6820
  var AudioChunkFormatSchema = _enum(AUDIO_CHUNK_FORMATS);
6894
6821
  var DecodedAudioChunkSchema = object({
@@ -6906,11 +6833,10 @@ var DecodedAudioChunkSchema = object({
6906
6833
  format: AudioChunkFormatSchema.optional()
6907
6834
  });
6908
6835
  /**
6909
- * Input for `stream-broker.subscribeAudioChunks` (Phase 5 / D9). The
6910
- * handle-free, ship-bytes-inline analogue of `subscribeFrames`: a consumer
6911
- * asks the broker for the decoded audio-chunk stream of one broker; the
6912
- * broker keeps a per-subscription bounded FIFO queue the consumer drains via
6913
- * `pullAudioChunks`.
6836
+ * Input for `stream-broker.subscribeAudioChunks` (Phase 5 / D9). Audio ships
6837
+ * its bytes inline: a consumer asks the broker for the decoded audio-chunk
6838
+ * stream of one broker; the broker keeps a per-subscription bounded FIFO queue
6839
+ * the consumer drains via `pullAudioChunks`.
6914
6840
  */
6915
6841
  var SubscribeAudioChunksInputSchema = object({
6916
6842
  brokerId: string(),
@@ -6941,9 +6867,7 @@ var BrokerStatsSchema = object({
6941
6867
  "stopped"
6942
6868
  ]),
6943
6869
  inputFps: number(),
6944
- decodeFps: number(),
6945
6870
  encodedSubscribers: number(),
6946
- decodedSubscribers: number(),
6947
6871
  uptimeMs: number(),
6948
6872
  bitrateKbps: number(),
6949
6873
  idrIntervalMs: number(),
@@ -6956,14 +6880,6 @@ var BrokerStatsSchema = object({
6956
6880
  preBufferMs: number(),
6957
6881
  preBufferPackets: number(),
6958
6882
  /**
6959
- * Moleculer node id of the decoder provider currently servicing this
6960
- * stream's decoded subscribers. `null` until the deferred decoder is
6961
- * created (no decoded clients yet, or codec not detected). Surfaces the
6962
- * runtime decoder placement so the UI can show "Decoder: <agent>" without
6963
- * a separate cap call per broker.
6964
- */
6965
- decoderNodeId: string().nullable(),
6966
- /**
6967
6883
  * Detected audio track parameters from the RTSP DESCRIBE / SDP. `null`
6968
6884
  * when the stream has no audio track or the broker is in cold start.
6969
6885
  * `supported = false` means the codec was detected but the local
@@ -10285,70 +10201,6 @@ var StorageLocationDeclarationSchema = object({
10285
10201
  "backup"
10286
10202
  ]).optional()
10287
10203
  });
10288
- var DecoderStatsSchema = object({
10289
- inputFps: number(),
10290
- outputFps: number(),
10291
- avgDecodeTimeMs: number(),
10292
- droppedFrames: number(),
10293
- /**
10294
- * Pull-mode adaptive-fps telemetry (optional — only pull sessions run the
10295
- * lag-driven controller; push sessions omit these). `lagMs` is the EWMA of
10296
- * the decoder's real-time drift (rising = falling behind live); `adaptiveFps`
10297
- * is the current lag-throttled emit rate (≤ `effectiveFps` ceiling).
10298
- */
10299
- lagMs: number().optional(),
10300
- effectiveFps: number().optional(),
10301
- adaptiveFps: number().optional()
10302
- });
10303
- var DecoderSessionConfigSchema = object({
10304
- codec: string(),
10305
- maxFps: number().default(0),
10306
- outputFormat: _enum([
10307
- "jpeg",
10308
- "rgb",
10309
- "bgr",
10310
- "yuv420",
10311
- "gray"
10312
- ]).default("jpeg"),
10313
- scale: number().default(1),
10314
- width: number().optional(),
10315
- height: number().optional(),
10316
- /**
10317
- * Identifier of the camera this decoder session serves. Optional
10318
- * because the cap is generic (any caller could request decode), but
10319
- * stream-broker passes it so decoder logs include `deviceId` for
10320
- * per-camera filtering when diagnosing failures (e.g. node-av
10321
- * sendPacket errors on a single hung camera).
10322
- */
10323
- deviceId: number().int().nonnegative().optional(),
10324
- /**
10325
- * Free-form tag for log scoping. Stream-broker uses
10326
- * `broker:<deviceId>/<profile>`. Decoder session logger surfaces it
10327
- * on every line so `grep tag=broker:5/high` filters one camera
10328
- * profile cleanly.
10329
- */
10330
- tag: string().optional(),
10331
- /**
10332
- * Where the session delivers decoded frames (Phase 5 / D9):
10333
- *
10334
- * - `'callback'` (default) — the legacy pixel path: decoded frames are
10335
- * buffered as `DecodedFrame`s and drained via `pullFrames`.
10336
- * - `'shm'` — the shared-memory frame plane: decoded frames are written
10337
- * into an OS shared-memory ring and drained as zero-pixel
10338
- * `FrameHandle`s via `pullHandles`. A session is one mode or the
10339
- * other — `pullFrames` returns nothing for an `'shm'` session and
10340
- * `pullHandles` returns nothing for a `'callback'` session.
10341
- */
10342
- frameSink: _enum(["callback", "shm"]).default("callback"),
10343
- /**
10344
- * Per-camera decoder DEBUG facility. When `true`, a pull-mode session emits
10345
- * a throttled (~1Hz) structured `decoder debug` line (effective/adaptive fps,
10346
- * real-time lag, dropped-frame delta, avg decode time, hwaccel). Mirrors the
10347
- * stream-broker's `streamingDebug` gate — off by default so production logs
10348
- * stay quiet and the emit path pays zero per-frame cost when disabled.
10349
- */
10350
- debug: boolean().optional()
10351
- });
10352
10204
  /**
10353
10205
  * Per-component log CHANNELS — the gate a hot path consults, and the registry
10354
10206
  * an addon declares its channels in.
@@ -10491,6 +10343,26 @@ var ClipSearchStrictnessSchema = _enum([
10491
10343
  "balanced",
10492
10344
  "strict"
10493
10345
  ]);
10346
+ /** Steps whose effect a root label can BE. */
10347
+ var LABEL_SUPPLY_STEP_IDS = [
10348
+ "animal-classifier",
10349
+ "vehicle-classifier",
10350
+ "package-detection"
10351
+ ];
10352
+ /** Steps whose box a root detection can BE. */
10353
+ var CROP_SUPPLY_STEP_IDS = ["plate-detection", "face-detection"];
10354
+ /**
10355
+ * Steps whose per-detection MASK a root detection can carry (D737). The live
10356
+ * mask step is `segmentation` — a frame-plane refiner that runs its own model
10357
+ * once per detection crop. (`instance-segmentation` is a dormant step id that
10358
+ * no camera tree carries.)
10359
+ */
10360
+ var MASK_SUPPLY_STEP_IDS = ["segmentation"];
10361
+ [
10362
+ ...LABEL_SUPPLY_STEP_IDS,
10363
+ ...CROP_SUPPLY_STEP_IDS,
10364
+ ...MASK_SUPPLY_STEP_IDS
10365
+ ];
10494
10366
  var MODEL_FORMATS = [
10495
10367
  "onnx",
10496
10368
  "coreml",
@@ -10519,7 +10391,53 @@ var ModelFormatEntrySchema = object({
10519
10391
  /** Multi-file payload (directory members or sibling files). */
10520
10392
  files: array(string()).readonly().optional(),
10521
10393
  /** Runtime(s) that can use this format. If omitted, inferred from ModelFormat key */
10522
- runtimes: array(_enum(["python"])).readonly().optional()
10394
+ runtimes: array(_enum(["python"])).readonly().optional(),
10395
+ /**
10396
+ * Content revision of the artefact, for one hosted OFF the CamStack mirror.
10397
+ * A format on the mirror leaves it unset: its revision (the sha256 of its
10398
+ * weight file) comes from the downloader's generated table, kept in step
10399
+ * with the mirror by `scripts/check-hosted-model-revisions.ts` (D744). A
10400
+ * node records the revision it downloaded next to the file
10401
+ * (`<file>.revision`); a copy with no record or a different one is stale
10402
+ * unless its weight file hashes to the revision, and a stale copy is
10403
+ * downloaded again, the old one serving until the new one is complete. No
10404
+ * revision at all ⇒ a file on disk is current, whatever it holds (D743).
10405
+ */
10406
+ revision: string().min(1).optional()
10407
+ });
10408
+ /**
10409
+ * What a node holds for one (model, format) (D746). `current` is a complete
10410
+ * copy at its catalog revision — exactly what `downloaded: true` means.
10411
+ * `stale` is bytes on disk that are not (yet) proven current under D743/D744:
10412
+ * no or a different revision record, or a missing sibling. `missing` is no
10413
+ * copy. `downloaded` alone folds `stale` into "not downloaded", which hid
10414
+ * reclaimable bytes and a copy about to be replaced.
10415
+ */
10416
+ var ModelOnDiskStateSchema = _enum([
10417
+ "current",
10418
+ "stale",
10419
+ "missing"
10420
+ ]);
10421
+ /**
10422
+ * The numeric precision of one format's BUILD (D746) — reported only when the
10423
+ * build states it (file-name token, an INT8 variant, an EdgeTPU compile, a
10424
+ * CamStack Core ML export). Absent means "not stated", never "fp32".
10425
+ */
10426
+ var ModelFormatPrecisionSchema = _enum([
10427
+ "fp32",
10428
+ "fp16",
10429
+ "int8"
10430
+ ]);
10431
+ /**
10432
+ * One format of one model as a node's `pipelineExecutor.getSchema` reports it.
10433
+ * `onDisk` / `precision` are optional for version skew: a runner that predates
10434
+ * them omits them, and a reader falls back to `downloaded`.
10435
+ */
10436
+ var PipelineModelFormatStatusSchema = object({
10437
+ downloaded: boolean(),
10438
+ sizeMB: number(),
10439
+ onDisk: ModelOnDiskStateSchema.optional(),
10440
+ precision: ModelFormatPrecisionSchema.optional()
10523
10441
  });
10524
10442
  /**
10525
10443
  * Extra file that must be downloaded alongside the model (e.g., labels JSON, dict.txt).
@@ -10560,11 +10478,11 @@ var ModelVariantGroupSchema = object({
10560
10478
  /** Quantization axis. Omit ⇒ the fp32 base build. */
10561
10479
  precision: _enum(["fp32", "int8"]).optional(),
10562
10480
  /**
10563
- * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
10564
- * latency-optimized export (e.g. ReLU-activation variant) — the slot the
10565
- * future performance variants plug into.
10481
+ * Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
10482
+ * an alternate training of the same family (Scrypted `relu_test`); chip
10483
+ * label is "Test".
10566
10484
  */
10567
- optimization: _enum(["standard", "fast"]).optional(),
10485
+ optimization: _enum(["standard", "test"]).optional(),
10568
10486
  /**
10569
10487
  * Input-resolution axis (square input side, px). Omit ⇒ the family's native
10570
10488
  * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
@@ -10587,9 +10505,10 @@ var ModelProviderIdSchema = _enum([
10587
10505
  * are per upstream. A persisted custom-model row written when this field was a
10588
10506
  * string still parses — the string is lifted into `{ weights }`.
10589
10507
  *
10590
- * Every licence surface (the admin "Models and licenses" page,
10591
- * `THIRD_PARTY_MODELS.md`, the Hugging Face model table) is GENERATED from
10592
- * these records by `scripts/gen-model-licenses.ts` (D661).
10508
+ * Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
10509
+ * model table) is GENERATED from these records by
10510
+ * `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
10511
+ * `camstack/docs` → `/docs/detection/models`.
10593
10512
  */
10594
10513
  var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { weights: value } : value, object({
10595
10514
  /** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
@@ -10622,6 +10541,46 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
10622
10541
  /** True when the weights or their data forbid commercial use. */
10623
10542
  nonCommercial: boolean().optional()
10624
10543
  }));
10544
+ /**
10545
+ * One step a ROOT detector can supply from its own output (D730) — see
10546
+ * `ModelCatalogEntry.suppliesSteps`.
10547
+ *
10548
+ * - `label`: the root's raw class IS the step's answer. `labelToEffect` maps
10549
+ * the root's label to the step's vocabulary; `uncovered` is the vocabulary
10550
+ * the root cannot produce (shown as unavailable, never a blocker).
10551
+ * - `crop`: the root draws the box the step would have found (`license_plate`
10552
+ * for plate-detection, `face` for face-detection). The box becomes a detail
10553
+ * child of the `parentMacro` detection that contains it — never a track.
10554
+ * - `mask`: the root's decode emits an instance mask with every detection (a
10555
+ * YOLO26-seg root, D737) — the `segmentation` step's result, carried on the
10556
+ * detection in the shape that step produces. Derived from the model's
10557
+ * postprocessor on read, never stored by an import.
10558
+ */
10559
+ var RootStepSupplySchema = discriminatedUnion("kind", [
10560
+ object({
10561
+ kind: literal("label"),
10562
+ stepId: _enum(LABEL_SUPPLY_STEP_IDS),
10563
+ labelToEffect: record(string(), string()),
10564
+ uncovered: array(string()).readonly()
10565
+ }),
10566
+ object({
10567
+ kind: literal("crop"),
10568
+ stepId: _enum(CROP_SUPPLY_STEP_IDS),
10569
+ rootLabels: array(string()).readonly(),
10570
+ parentMacro: _enum(["vehicle", "person"]),
10571
+ childClass: _enum(["plate", "face"]),
10572
+ /**
10573
+ * The root's smaller input side, stamped on read by `rootSuppliesOf` from
10574
+ * the model entry — what a step's `minRootInputPx` gate judges. Never
10575
+ * stored by an import.
10576
+ */
10577
+ rootInputPx: number().int().positive().optional()
10578
+ }),
10579
+ object({
10580
+ kind: literal("mask"),
10581
+ stepId: _enum(MASK_SUPPLY_STEP_IDS)
10582
+ })
10583
+ ]);
10625
10584
  var ModelCatalogEntrySchema = object({
10626
10585
  id: string(),
10627
10586
  name: string(),
@@ -10687,6 +10646,35 @@ var ModelCatalogEntrySchema = object({
10687
10646
  */
10688
10647
  defaultConfidence: number().min(0).max(1).optional(),
10689
10648
  /**
10649
+ * Per-MODEL default of the per-class confidence floors (`minConfidence<Macro>`
10650
+ * on a detector step), keyed by macro class: `{ person: 0.45 }`. A class
10651
+ * absent here runs at the step slider's global default. The same row shape
10652
+ * the floor measurement produces (`model-floors.json`: modelId → floors), so
10653
+ * a measured table is copied in as-is. An operator override is bound to the
10654
+ * model it was made for and does not survive a model change (D738). A custom
10655
+ * / imported model may declare it; without it, the global defaults apply.
10656
+ */
10657
+ defaultClassFloors: record(string(), number().min(0).max(1)).optional(),
10658
+ /**
10659
+ * The inference precision this model's OpenVINO IR needs on an Intel GPU.
10660
+ * Absent ⇒ the device default (f16 on a GPU). Set to `'f32'` for an FP32 IR
10661
+ * that produces invalid output at f16 — measured 2026-10-07 for YOLO26
10662
+ * base IRs (`yolo26s`: 0 true / 146 false positives; `yolo26m*`: NaN
10663
+ * scores) on the Core Ultra iGPU and the N100. Threaded to the pool as
10664
+ * `PoolModelConfig.gpuInferencePrecision`; the pool sets
10665
+ * INFERENCE_PRECISION_HINT on a GPU only. Costs ~60% latency on the GPU.
10666
+ */
10667
+ gpuInferencePrecision: _enum(["f32", "f16"]).optional(),
10668
+ /**
10669
+ * ROOT detectors only: per supplied step (`animal-classifier`, …), the
10670
+ * minimum DETECTION score from which this root's own fine label (species,
10671
+ * vehicle type — D736 root supply) is taken (D741). Below it the detection
10672
+ * keeps its macro class without the fine label. `1` = never take it from
10673
+ * this root. Absent ⇒ no floor beyond the macro floor. The supplied step's
10674
+ * `minConfidence` slider, bound to the ROOT model, overrides it.
10675
+ */
10676
+ suppliedLabelFloors: record(string(), number().min(0).max(1)).optional(),
10677
+ /**
10690
10678
  * When true, the executor produces a landmark-aligned crop (similarity warp
10691
10679
  * onto the canonical template) before this step runs, instead of a plain
10692
10680
  * axis-aligned bbox crop. Required for face-recognition embedders (ArcFace):
@@ -10748,6 +10736,16 @@ var ModelCatalogEntrySchema = object({
10748
10736
  */
10749
10737
  classMap: DetectionCatalogClassMapSchema.optional(),
10750
10738
  /**
10739
+ * The pipeline steps this ROOT detector can supply from its own output
10740
+ * (D730): its labels name a step's effect (`deer` for `animal-classifier`)
10741
+ * or draw a step's box (`license_plate` for `plate-detection`). Computed at
10742
+ * import from THIS model's labelmap by `deriveRootSupplies`, never written
10743
+ * by hand and never assumed per family; a row without it is derived on read
10744
+ * (`rootSuppliesOf`). Whether a camera uses it is the step's own
10745
+ * `useRootModel` flag (`resolveRootSupply`).
10746
+ */
10747
+ suppliesSteps: array(RootStepSupplySchema).readonly().optional(),
10748
+ /**
10751
10749
  * The model's CLIP feature-space contract (text encoder, dimension, vector
10752
10750
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
10753
10751
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -12398,13 +12396,6 @@ var BrokerRtspClientSchema = object({
12398
12396
  lastRtpAt: number(),
12399
12397
  bytesSent: number()
12400
12398
  });
12401
- var BrokerDecodedClientSchema = object({
12402
- tag: string(),
12403
- subscribedAt: number(),
12404
- maxFps: number(),
12405
- framesDelivered: number(),
12406
- framesDropped: number()
12407
- });
12408
12399
  var BrokerAudioClientSchema = object({
12409
12400
  tag: string(),
12410
12401
  subscribedAt: number(),
@@ -12496,7 +12487,6 @@ var BrokerEncodedClientSchema = object({
12496
12487
  });
12497
12488
  var BrokerClientsSchema = object({
12498
12489
  rtsp: array(BrokerRtspClientSchema).readonly(),
12499
- decoded: array(BrokerDecodedClientSchema).readonly(),
12500
12490
  audio: array(BrokerAudioClientSchema).readonly(),
12501
12491
  encoded: array(BrokerEncodedClientSchema).readonly(),
12502
12492
  pipeClients: number(),
@@ -12865,11 +12855,7 @@ method(object({
12865
12855
  auth: "admin"
12866
12856
  }), method(object({ brokerId: string() }), BrokerClientsSchema), method(object({
12867
12857
  brokerId: string(),
12868
- channel: _enum([
12869
- "rtsp",
12870
- "decoded",
12871
- "audio"
12872
- ]),
12858
+ channel: _enum(["rtsp", "audio"]),
12873
12859
  handle: string()
12874
12860
  }), object({ killed: boolean() }), {
12875
12861
  kind: "mutation",
@@ -12904,10 +12890,7 @@ method(object({
12904
12890
  }), method(SubscribeAudioChunksInputSchema, SubscribeAudioChunksResultSchema, { kind: "mutation" }), method(object({
12905
12891
  subscriptionId: string(),
12906
12892
  maxCount: number().int().positive().default(8)
12907
- }), array(DecodedAudioChunkSchema).readonly()), method(object({ subscriptionId: string() }), object({ released: boolean() }), { kind: "mutation" }), method(SubscribeFramesInputSchema, SubscribeFramesResultSchema, { kind: "mutation" }), method(object({
12908
- subscriptionId: string(),
12909
- maxCount: number().int().positive().default(4)
12910
- }), array(FrameHandleSchema).readonly()), method(object({ subscriptionId: string() }), object({ released: boolean() }), { kind: "mutation" }), method(object({
12893
+ }), array(DecodedAudioChunkSchema).readonly()), method(object({ subscriptionId: string() }), object({ released: boolean() }), { kind: "mutation" }), method(object({
12911
12894
  brokerId: string(),
12912
12895
  seconds: number().min(0).max(30)
12913
12896
  }), _void(), {
@@ -14064,54 +14047,12 @@ id: union([string(), number()]) }), {
14064
14047
  kind: "mutation",
14065
14048
  auth: "admin"
14066
14049
  });
14067
- /**
14068
- * shm ring usage stats for a `frameSink: 'shm'` decoder session —
14069
- * exposed via `decoder.getShmStats` so downstream consumers can
14070
- * observe ring pressure (slot count, byte budget, hit/miss ratio).
14071
- */
14072
- var ShmRingStatsSchema = object({
14073
- sessionId: string(),
14074
- slotCount: number().int(),
14075
- slotByteLength: number().int(),
14076
- segmentBytes: number().int(),
14077
- budgetMb: number().int(),
14078
- framesWritten: number().int(),
14079
- getFrameHits: number().int(),
14080
- getFrameMisses: number().int()
14081
- });
14082
- method(object({ codec: string() }), boolean()), method(_void(), object({
14050
+ method(_void(), object({
14083
14051
  id: string(),
14084
14052
  name: string(),
14085
- isPullMode: boolean().optional(),
14086
- priority: number().optional(),
14087
14053
  hwaccel: string().optional(),
14088
14054
  probedBestHwaccel: string().optional()
14089
- })), method(DecoderSessionConfigSchema, object({
14090
- sessionId: string(),
14091
- nodeId: string()
14092
- })), method(object({ sessionId: string() }), _void()), method(object({
14093
- sessionId: string(),
14094
- packet: EncodedPacketSchema
14095
- }), _void()), method(object({
14096
- sessionId: string(),
14097
- url: string()
14098
- }), _void()), method(object({
14099
- sessionId: string(),
14100
- maxCount: number().default(1),
14101
- waitMs: number().optional()
14102
- }), array(DecodedFrameSchema)), method(object({
14103
- sessionId: string(),
14104
- maxCount: number().default(1),
14105
- waitMs: number().optional()
14106
- }), array(FrameHandleSchema)), method(object({ handle: FrameHandleSchema }), DecodedFrameSchema.nullable()), method(object({ sessionId: string() }), ShmRingStatsSchema.nullable()), method(object({
14107
- sessionId: string(),
14108
- config: DecoderSessionConfigSchema.partial()
14109
- }), _void()), method(object({ sessionId: string() }), DecoderStatsSchema), method(_void(), array(object({
14110
- sessionId: string(),
14111
- codec: string(),
14112
- outputFormat: string(),
14113
- createdAtMs: number()
14114
- })).readonly()), method(_void(), object({ backend: string() }), {
14055
+ })), method(_void(), object({ backend: string() }), {
14115
14056
  kind: "mutation",
14116
14057
  auth: "admin"
14117
14058
  });
@@ -14167,7 +14108,7 @@ DeviceType.Camera;
14167
14108
  * This matters here more than anywhere else in the repo, because every provider
14168
14109
  * that knows a device's host knows its PASSWORD too: `{ host, port, username,
14169
14110
  * password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
14170
- * and `http://admin:hunter2@192.168.x.x/` is a URL a browser accepts. The
14111
+ * and `http://admin:hunter2@192.168.60.139/` is a URL a browser accepts. The
14171
14112
  * camera's own page will ask for its own login. That is correct, and pre-
14172
14113
  * filling it is the operator's business, not ours.
14173
14114
  *
@@ -15955,6 +15896,12 @@ method(_void(), array(string()).readonly(), { auth: "admin" }), method(object({
15955
15896
  kind: "mutation",
15956
15897
  auth: "admin"
15957
15898
  });
15899
+ var HUB_ADDRESS_ROLES = [
15900
+ "appConnections",
15901
+ "notificationTaps",
15902
+ "internal",
15903
+ "publicEndpoint"
15904
+ ];
15958
15905
  /**
15959
15906
  * Transport bounds for AI capability methods.
15960
15907
  *
@@ -17151,7 +17098,7 @@ method(object({
17151
17098
  timeoutMs: 6e5
17152
17099
  });
17153
17100
  method(object({
17154
- nodeId: string(),
17101
+ targetNodeId: string(),
17155
17102
  modelId: string(),
17156
17103
  format: _enum(MODEL_FORMATS),
17157
17104
  entry: ModelCatalogEntrySchema
@@ -18538,6 +18485,8 @@ var NcSystemEventKindSchema = _enum([
18538
18485
  "stream-offline",
18539
18486
  "node-online",
18540
18487
  "node-offline",
18488
+ "node-restarting",
18489
+ "node-updating",
18541
18490
  "node-inference-unavailable",
18542
18491
  "detection-blind",
18543
18492
  "addon-crash-loop",
@@ -19636,8 +19585,9 @@ var NcRuleSchema = NcRuleInputSchema.extend({
19636
19585
  disabledTargetIds: array(string()).default([])
19637
19586
  });
19638
19587
  /**
19639
- * The state-summary SECTIONS (D647 / D698): the D637 kind groups that report a
19640
- * still-true state. `backups-exports` and `alarm` are not sections — a completed
19588
+ * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
19589
+ * report a still-true state. `addons` is the crash-looped addons only and
19590
+ * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
19641
19591
  * job is not an open state, and the alarm stays instant.
19642
19592
  */
19643
19593
  var NcStateSummarySectionIdSchema = _enum([
@@ -19649,6 +19599,7 @@ var NcStateSummarySectionIdSchema = _enum([
19649
19599
  "detection-blind",
19650
19600
  "nodes",
19651
19601
  "addons",
19602
+ "addon-updates",
19652
19603
  "updates"
19653
19604
  ]);
19654
19605
  /** One section of a previewed state summary. `unavailable` = its state could not be read. */
@@ -20129,7 +20080,25 @@ var NcAlarmModeDelaysListSchema = array(object({
20129
20080
  * When this mode may be armed. Absent / null = always allowed (same as a
20130
20081
  * rule with no `schedule`). Evaluated with {@link isScheduleActive}.
20131
20082
  */
20132
- schedule: NcScheduleSchema.optional()
20083
+ schedule: NcScheduleSchema.optional(),
20084
+ /**
20085
+ * D706: while this mode's ENTRY DELAY runs, do the alarm rules' own pushes go out (as an
20086
+ * intrusion naming the locations)? Absent = false — the entry-delay notification is the
20087
+ * only one, and the matches ride the triggered notification's mosaic (D705).
20088
+ */
20089
+ notifyDuringEntryDelay: boolean().optional(),
20090
+ /**
20091
+ * D706: notify "watched again" when a sensor this arm bypassed closes and opens again.
20092
+ * Absent = false (logged, not sent). Even when true it is not sent when that same sensor
20093
+ * is the one that starts the entry delay — the entry-delay notification already names it.
20094
+ */
20095
+ notifySensorRewatched: boolean().optional(),
20096
+ /**
20097
+ * D735: notify "ignored" when a sensor this arm bypassed really MOVED while armed (its own
20098
+ * change time is after the arm) and set nothing off. Absent = false (logged, not sent). A
20099
+ * re-sync, a recovery from `unavailable` or a duplicate is never announced, switch or not.
20100
+ */
20101
+ notifySensorIgnored: boolean().optional()
20133
20102
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
20134
20103
  var NcAlarmModeDelaysEditListSchema = array(object({
20135
20104
  mode: AlarmArmModeSchema,
@@ -20138,7 +20107,13 @@ var NcAlarmModeDelaysEditListSchema = array(object({
20138
20107
  triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
20139
20108
  postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
20140
20109
  /** Set a schedule, or `null` to clear (mode always allowed again). */
20141
- schedule: NcScheduleSchema.nullable().optional()
20110
+ schedule: NcScheduleSchema.nullable().optional(),
20111
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20112
+ notifyDuringEntryDelay: boolean().nullable().optional(),
20113
+ /** D706: set the switch, or `null` to clear it (back to the default, false). */
20114
+ notifySensorRewatched: boolean().nullable().optional(),
20115
+ /** D735: set the switch, or `null` to clear it (back to the default, false). */
20116
+ notifySensorIgnored: boolean().nullable().optional()
20142
20117
  })).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
20143
20118
  /** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
20144
20119
  var NcAlarmNonBlockingEditSchema = object({
@@ -21099,45 +21074,25 @@ Object.freeze(Object.fromEntries([{
21099
21074
  label: "Face recognition model",
21100
21075
  defaultModelId: "auraface-r100",
21101
21076
  indexName: "the enrolled face gallery",
21102
- options: [
21103
- {
21104
- id: "auraface-r100",
21105
- label: "AuraFace R100"
21106
- },
21107
- {
21108
- id: "arcface-r100",
21109
- label: "ArcFace (ResNet34)"
21110
- },
21111
- {
21112
- id: "inception-resnet-v1",
21113
- label: "Inception ResNet V1"
21114
- }
21115
- ]
21077
+ options: [{
21078
+ id: "auraface-r100",
21079
+ label: "AuraFace R100"
21080
+ }]
21116
21081
  }, {
21117
21082
  stepId: "clip-embedding",
21118
21083
  label: "Semantic search model",
21119
- defaultModelId: "mobileclip-s1",
21084
+ defaultModelId: "siglip2-b16-224",
21120
21085
  indexName: "the object semantic-search index",
21121
- options: [
21122
- {
21123
- id: "mobileclip-s1",
21124
- label: "MobileCLIP S1"
21125
- },
21126
- {
21127
- id: "mobileclip-s2",
21128
- label: "MobileCLIP S2"
21129
- },
21130
- {
21131
- id: "siglip2-b16-224",
21132
- label: "SigLIP2 B/16 (Apache-2.0)"
21133
- }
21134
- ]
21086
+ options: [{
21087
+ id: "siglip2-b16-224",
21088
+ label: "SigLIP2 B/16 (Apache-2.0)"
21089
+ }]
21135
21090
  }].map((s) => [s.stepId, s.defaultModelId])));
21136
21091
  var CLUSTER_STEP_SETTING_FIELDS = [{
21137
21092
  stepId: "face-embedding",
21138
21093
  key: "minLandmarkFaceSize",
21139
- label: "Min face size for recognition (detection px)",
21140
- 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.",
21094
+ label: "Min face size to embed (detection-frame px)",
21095
+ 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.",
21141
21096
  type: "slider",
21142
21097
  min: 0,
21143
21098
  max: 64,
@@ -23057,6 +23012,34 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
23057
23012
  timestamp: number()
23058
23013
  });
23059
23014
  /**
23015
+ * A root model's boxes standing in for one crop-kind step's own inference
23016
+ * (D730) — see `runPipeline.suppliedRoot`.
23017
+ */
23018
+ var SuppliedRootOutputSchema = object({
23019
+ stepId: string(),
23020
+ /** The root model that drew the boxes — stamped on the result. */
23021
+ modelId: string(),
23022
+ detections: array(object({
23023
+ /** `[x1, y1, x2, y2]` in the pixels of the call's image. */
23024
+ bbox: tuple([
23025
+ number(),
23026
+ number(),
23027
+ number(),
23028
+ number()
23029
+ ]),
23030
+ score: number(),
23031
+ /**
23032
+ * Five facial landmarks in the same pixels — a face the step's own
23033
+ * detector already re-found inside a root face box (D730), so its
23034
+ * embedder child aligns it exactly as it aligns any detected face.
23035
+ */
23036
+ landmarks: array(object({
23037
+ x: number(),
23038
+ y: number()
23039
+ })).optional()
23040
+ })).min(1)
23041
+ });
23042
+ /**
23060
23043
  * Reference to the frame's retained NATIVE surface + the parent crop's placement
23061
23044
  * within the frame, so the executor can re-cut a leaf child ROI at native
23062
23045
  * resolution on the detail plane. See the `runPipeline` `nativeCropRef` field.
@@ -23104,7 +23087,7 @@ var FrameRefSchema = object({
23104
23087
  timestamp: number(),
23105
23088
  capturedAt: number().optional()
23106
23089
  });
23107
- var ModelFormatSchema$1 = _enum([
23090
+ var ModelFormatSchema$2 = _enum([
23108
23091
  "onnx",
23109
23092
  "coreml",
23110
23093
  "openvino",
@@ -23122,7 +23105,7 @@ var PipelineSlotSchema = _enum([
23122
23105
  var PipelineEngineChoiceSchema = object({
23123
23106
  runtime: literal("python"),
23124
23107
  backend: string(),
23125
- format: ModelFormatSchema$1,
23108
+ format: ModelFormatSchema$2,
23126
23109
  device: string().optional()
23127
23110
  });
23128
23111
  /**
@@ -23161,32 +23144,15 @@ var PipelineDefaultStepSchema = lazy(() => object({
23161
23144
  group: string().optional(),
23162
23145
  settings: record(string(), unknown()).optional()
23163
23146
  }));
23164
- var PipelineTemplateStepSchema = lazy(() => object({
23165
- addonId: string(),
23166
- enabled: boolean(),
23167
- modelId: string(),
23168
- children: array(PipelineTemplateStepSchema).readonly(),
23169
- settings: record(string(), unknown()).optional()
23170
- }));
23171
- var PipelineTemplateSchema$1 = object({
23172
- id: string(),
23173
- name: string(),
23174
- createdAt: string(),
23175
- updatedAt: string(),
23176
- engine: PipelineEngineChoiceSchema,
23177
- steps: array(PipelineTemplateStepSchema).readonly()
23178
- });
23179
23147
  var PipelineModelOptionSchema = object({
23180
23148
  id: string(),
23181
23149
  name: string(),
23182
- formats: record(string(), object({
23183
- downloaded: boolean(),
23184
- sizeMB: number()
23185
- })),
23150
+ formats: record(string(), PipelineModelFormatStatusSchema),
23186
23151
  group: ModelVariantGroupSchema.optional(),
23187
23152
  legacy: boolean().optional(),
23188
23153
  provider: ModelProviderIdSchema.optional(),
23189
- defaultConfidence: number().optional()
23154
+ defaultConfidence: number().optional(),
23155
+ suppliesSteps: array(RootStepSupplySchema).readonly().optional()
23190
23156
  });
23191
23157
  var ConfigFieldBridge = custom();
23192
23158
  var PipelineAddonSchemaSchema = object({
@@ -23348,6 +23314,22 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
23348
23314
  }), {
23349
23315
  kind: "mutation",
23350
23316
  auth: "admin"
23317
+ }), method(object({
23318
+ nodeId: string(),
23319
+ deviceIds: array(number()).readonly().optional(),
23320
+ dryRun: boolean()
23321
+ }), object({
23322
+ entries: array(object({
23323
+ deviceId: number(),
23324
+ keys: array(string()).readonly()
23325
+ })).readonly(),
23326
+ refused: array(object({
23327
+ deviceId: number(),
23328
+ reason: string()
23329
+ })).readonly()
23330
+ }), {
23331
+ kind: "mutation",
23332
+ auth: "admin"
23351
23333
  }), method(object({ nodeId: string() }), object({ unhealthy: array(object({
23352
23334
  /** `<backend>:<device>`, e.g. `openvino:gpu`. */
23353
23335
  deviceKey: string(),
@@ -23373,22 +23355,14 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
23373
23355
  }), method(_void(), PipelineSchemaSchema), method(_void(), array(PipelineDefaultStepSchema).readonly().nullable()), method(_void(), PipelineConfigBridge), method(_void(), ConfigUISchemaBridge), method(object({
23374
23356
  steps: array(PipelineStepInputSchema),
23375
23357
  deviceKey: string().optional()
23376
- }), PipelineValidationResultSchema), method(_void(), array(PipelineTemplateSchema$1).readonly()), method(object({
23377
- name: string(),
23378
- steps: array(PipelineTemplateStepSchema).readonly(),
23379
- engine: PipelineEngineChoiceSchema
23380
- }), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({
23381
- id: string(),
23382
- name: string().optional(),
23383
- steps: array(PipelineTemplateStepSchema).readonly().optional()
23384
- }), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({ id: string() }), _void(), { kind: "mutation" }), method(_void(), InferenceCapabilitiesBridge), method(object({ addonId: string() }), ModelAvailabilityListBridge), method(object({
23358
+ }), PipelineValidationResultSchema), method(_void(), InferenceCapabilitiesBridge), method(object({ addonId: string() }), ModelAvailabilityListBridge), method(object({
23385
23359
  addonId: string(),
23386
23360
  modelId: string(),
23387
- format: ModelFormatSchema$1
23361
+ format: ModelFormatSchema$2
23388
23362
  }), DownloadModelResultSchema, { kind: "mutation" }), method(object({
23389
23363
  addonId: string(),
23390
23364
  modelId: string(),
23391
- format: ModelFormatSchema$1
23365
+ format: ModelFormatSchema$2
23392
23366
  }), object({ success: literal(true) }), { kind: "mutation" }), method(object({
23393
23367
  steps: array(PipelineStepInputSchema).min(1),
23394
23368
  frame: FrameInputSchema.optional(),
@@ -23454,7 +23428,16 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
23454
23428
  * `device-not-servable`), and nothing reaches the camera's live
23455
23429
  * trace stream. Absent ⇒ unchanged behaviour.
23456
23430
  */
23457
- replay: literal(true).optional()
23431
+ replay: literal(true).optional(),
23432
+ /**
23433
+ * Root-supplied detections for the tree's ROOT step (D730). Set by
23434
+ * `runDetailSubtree` when the camera's root model supplies a crop-kind
23435
+ * step (a Frigate+ `license_plate` for `plate-detection`): the step is
23436
+ * NOT inferred, these boxes are its output, and its children (the plate
23437
+ * reader) run on them through their own crop policy. Boxes are in the
23438
+ * PIXELS of the image this call carries. Absent ⇒ the root step runs.
23439
+ */
23440
+ suppliedRoot: SuppliedRootOutputSchema.optional()
23458
23441
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
23459
23442
  steps: array(PipelineStepInputSchema).min(1),
23460
23443
  frames: array(FrameInputSchema).min(1).max(255),
@@ -23536,6 +23519,375 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
23536
23519
  filename: string().optional(),
23537
23520
  settings: record(string(), unknown()).optional()
23538
23521
  }), AudioTestResultSchema, { kind: "mutation" }), method(_void(), ConfigUISchemaNullableBridge);
23522
+ /**
23523
+ * The wire shapes of the Auto tune plan and apply (D745), used by the
23524
+ * `pipeline-orchestrator` cap. The recommender's own types
23525
+ * (`recommend.ts`) are the TS face of the same data; these
23526
+ * schemas are what crosses the cap boundary.
23527
+ */
23528
+ var ModelFormatSchema$1 = _enum(MODEL_FORMATS);
23529
+ /** The operator's range for it. */
23530
+ var MIN_SESSIONS_PER_DEVICE_RANGE = {
23531
+ min: 1,
23532
+ max: 8
23533
+ };
23534
+ var HardwareClassIdSchema = _enum([
23535
+ "intel-core-ultra",
23536
+ "intel-n-series",
23537
+ "apple-m-base",
23538
+ "apple-m-pro",
23539
+ "unknown"
23540
+ ]);
23541
+ var AcceleratorKindSchema = _enum([
23542
+ "intel-npu",
23543
+ "intel-igpu",
23544
+ "x86-cpu",
23545
+ "arm-cpu",
23546
+ "apple-ane",
23547
+ "coral"
23548
+ ]);
23549
+ var RecommendationReasonSchema = discriminatedUnion("kind", [
23550
+ object({
23551
+ kind: literal("capacity"),
23552
+ sessions: number(),
23553
+ minSessions: number()
23554
+ }),
23555
+ object({
23556
+ kind: literal("tie-faster"),
23557
+ over: string(),
23558
+ recallDelta: number()
23559
+ }),
23560
+ object({
23561
+ kind: literal("stepped-down"),
23562
+ from: string(),
23563
+ to: string(),
23564
+ limitedBy: string()
23565
+ }),
23566
+ object({
23567
+ kind: literal("no-fit-lightest"),
23568
+ sessions: number(),
23569
+ minSessions: number()
23570
+ }),
23571
+ object({
23572
+ kind: literal("derived-latency"),
23573
+ modelId: string()
23574
+ }),
23575
+ object({ kind: literal("cpu-device") }),
23576
+ object({ kind: literal("coral-untouched") }),
23577
+ object({ kind: literal("device-disabled") }),
23578
+ object({ kind: literal("device-unavailable") }),
23579
+ object({ kind: literal("node-offline") }),
23580
+ object({ kind: literal("no-hardware-facts") }),
23581
+ object({
23582
+ kind: literal("no-measured-data"),
23583
+ hardwareClass: HardwareClassIdSchema
23584
+ }),
23585
+ object({
23586
+ kind: literal("no-family-build"),
23587
+ format: ModelFormatSchema$1
23588
+ })
23589
+ ]);
23590
+ var DeviceModelChoiceSchema = object({
23591
+ modelId: string(),
23592
+ p50Ms: number(),
23593
+ fps: number(),
23594
+ measured: boolean(),
23595
+ /** Parallel sessions at the camera rate with the headroom kept free: ⌊fps × (1 − headroom) / camera fps⌋. */
23596
+ capacitySessions: number(),
23597
+ personRecall: number()
23598
+ });
23599
+ var DeviceRecommendationSchema = object({
23600
+ deviceKey: string(),
23601
+ accelerator: AcceleratorKindSchema.nullable(),
23602
+ enabled: boolean(),
23603
+ available: boolean(),
23604
+ chosen: DeviceModelChoiceSchema.nullable(),
23605
+ reasons: array(RecommendationReasonSchema).readonly()
23606
+ });
23607
+ var NodeRecommendationSchema = object({
23608
+ nodeId: string(),
23609
+ reachable: boolean(),
23610
+ hardwareClass: HardwareClassIdSchema.nullable(),
23611
+ cpuModel: string().nullable(),
23612
+ skipped: boolean(),
23613
+ acceleratorModelId: string().nullable(),
23614
+ devices: array(DeviceRecommendationSchema).readonly(),
23615
+ reasons: array(RecommendationReasonSchema).readonly()
23616
+ });
23617
+ var ModelPinChangeSchema = object({
23618
+ stepId: string(),
23619
+ before: string().nullable(),
23620
+ after: string().nullable()
23621
+ });
23622
+ var NodeDeviceChangeSchema = object({
23623
+ nodeId: string(),
23624
+ deviceKey: string(),
23625
+ madeExplicit: boolean(),
23626
+ modelPins: array(ModelPinChangeSchema).readonly(),
23627
+ thresholds: array(object({
23628
+ stepId: string(),
23629
+ keys: array(string()).readonly()
23630
+ })).readonly()
23631
+ });
23632
+ var CameraOverrideClearSchema = object({
23633
+ deviceId: number(),
23634
+ source: _enum(["step-override", "wholesale"]),
23635
+ nodeId: string(),
23636
+ deviceKey: string().nullable(),
23637
+ stepId: string(),
23638
+ modelIdBefore: string().nullable(),
23639
+ keys: array(string()).readonly()
23640
+ });
23641
+ var DetectorStoreClearSchema = object({
23642
+ deviceId: number(),
23643
+ keys: array(string()).readonly()
23644
+ });
23645
+ var AutoTuneWarningSchema = discriminatedUnion("kind", [
23646
+ object({
23647
+ kind: literal("detector-store-cluster-wide"),
23648
+ skippedNodes: array(string()).readonly()
23649
+ }),
23650
+ object({
23651
+ kind: literal("detector-store-unreadable"),
23652
+ error: string()
23653
+ }),
23654
+ object({
23655
+ kind: literal("coral-enabled"),
23656
+ nodeId: string(),
23657
+ deviceKey: string()
23658
+ })
23659
+ ]);
23660
+ var AutoTuneOptionsSchema = object({
23661
+ /** Share of each accelerator's throughput kept free (0.3–0.5). */
23662
+ headroom: number().min(.3).max(.5).default(.4),
23663
+ /**
23664
+ * The least number of parallel sessions every device must sustain at the
23665
+ * camera rate with the headroom kept free (D755). The most accurate model
23666
+ * that reaches it wins.
23667
+ */
23668
+ minSessionsPerDevice: number().int().min(MIN_SESSIONS_PER_DEVICE_RANGE.min).max(MIN_SESSIONS_PER_DEVICE_RANGE.max).default(2)
23669
+ });
23670
+ var AutoTunePlanSchema = object({
23671
+ /** Hash of everything the apply will write — the apply refuses a different one. */
23672
+ planHash: string(),
23673
+ family: literal("yolov9"),
23674
+ headroom: number(),
23675
+ minSessionsPerDevice: number(),
23676
+ /** The detection rate a session is counted at (the fastest camera running the pipeline root). */
23677
+ cameraFps: number(),
23678
+ generatedAt: number(),
23679
+ nodes: array(NodeRecommendationSchema).readonly(),
23680
+ nodeChanges: array(NodeDeviceChangeSchema).readonly(),
23681
+ cameraClears: array(CameraOverrideClearSchema).readonly(),
23682
+ detectorStoreClears: array(DetectorStoreClearSchema).readonly(),
23683
+ warnings: array(AutoTuneWarningSchema).readonly()
23684
+ });
23685
+ var AutoTuneApplyInputSchema = object({
23686
+ planHash: string(),
23687
+ headroom: number().min(.3).max(.5).default(.4),
23688
+ minSessionsPerDevice: number().int().min(MIN_SESSIONS_PER_DEVICE_RANGE.min).max(MIN_SESSIONS_PER_DEVICE_RANGE.max).default(2)
23689
+ });
23690
+ var AutoTunePhaseResultSchema = object({
23691
+ phase: _enum([
23692
+ "download",
23693
+ "camera-overrides",
23694
+ "detector-thresholds",
23695
+ "node-models",
23696
+ "redispatch"
23697
+ ]),
23698
+ ok: boolean(),
23699
+ detail: string()
23700
+ });
23701
+ var AutoTuneApplyResultSchema = discriminatedUnion("kind", [
23702
+ object({
23703
+ kind: literal("applied"),
23704
+ planHash: string(),
23705
+ phases: array(AutoTunePhaseResultSchema).readonly()
23706
+ }),
23707
+ object({
23708
+ kind: literal("aborted"),
23709
+ phases: array(AutoTunePhaseResultSchema).readonly()
23710
+ }),
23711
+ object({
23712
+ kind: literal("stale"),
23713
+ plan: AutoTunePlanSchema
23714
+ }),
23715
+ object({
23716
+ kind: literal("refused"),
23717
+ reason: _enum(["apply-in-progress"])
23718
+ })
23719
+ ]);
23720
+ /**
23721
+ * Wire shapes of the Load balancing surface (D748): the session placement
23722
+ * policy, the atomic share write, the observed placement statistics, the
23723
+ * hardware share suggestion and the stale device pins.
23724
+ */
23725
+ /**
23726
+ * How a new detection session picks its node and device.
23727
+ * - `least-loaded` — the historical rule: lowest `attached / weight`, a
23728
+ * constant node order at a tie (D37). An idle node always ties at 0, so a
23729
+ * weight only bites once a node already holds a session.
23730
+ * - `share` — the share of PARALLEL sessions is held to the weights, and a
23731
+ * full or drowning node yields to a free one (D748).
23732
+ */
23733
+ var SessionPlacementPolicySchema = _enum(["least-loaded", "share"]);
23734
+ var LoadBalancingSharesInputSchema = object({
23735
+ /** nodeId → share (> 0). A node left out keeps its weight. */
23736
+ nodes: record(string(), number().positive()).default({}),
23737
+ /** nodeId → deviceKey → share (> 0). A device left out keeps its weight. */
23738
+ devices: record(string(), record(string(), number().positive())).default({})
23739
+ });
23740
+ var PlacementStatsInputSchema = object({
23741
+ /** Window the observed shares are averaged over (default 1 h, max 24 h). */
23742
+ windowMs: number().int().min(6e4).max(1440 * 60 * 1e3).default(3600 * 1e3) });
23743
+ var PlacementDeviceStatsSchema = object({
23744
+ deviceKey: string(),
23745
+ /** Sessions running on this device now. */
23746
+ sessionsNow: number(),
23747
+ /** Sessions started on this device inside the window. */
23748
+ sessionsStarted: number(),
23749
+ /** Time-weighted share of the node's parallel sessions over the window (0–1); null = no session ran. */
23750
+ observedShare: number().nullable()
23751
+ });
23752
+ var PlacementNodeStatsSchema = object({
23753
+ nodeId: string(),
23754
+ sessionsNow: number(),
23755
+ sessionsStarted: number(),
23756
+ /** Time-weighted share of the cluster's parallel sessions over the window (0–1); null = none ran. */
23757
+ observedShare: number().nullable(),
23758
+ /** Most sessions this node ran at once inside the window. */
23759
+ peakSessions: number(),
23760
+ /** Sessions a share election handed elsewhere because this node was full or drowning. */
23761
+ yieldsAway: number(),
23762
+ devices: array(PlacementDeviceStatsSchema).readonly()
23763
+ });
23764
+ /** A camera's device pin that the session path cannot honour. */
23765
+ var StaleDevicePinSchema = object({
23766
+ deviceId: number(),
23767
+ deviceKey: string(),
23768
+ /** `disabled` — the key exists on some node but is not enabled anywhere; `absent` — no node has it. */
23769
+ reason: _enum(["disabled", "absent"])
23770
+ });
23771
+ var PlacementStatsSchema = object({
23772
+ policy: SessionPlacementPolicySchema,
23773
+ windowMs: number(),
23774
+ /** How much of the window was actually observed (the hub keeps it in memory). */
23775
+ observedForMs: number(),
23776
+ sessionsNow: number(),
23777
+ /** Most parallel sessions across the cluster inside the window. */
23778
+ clusterPeakSessions: number(),
23779
+ nodes: array(PlacementNodeStatsSchema).readonly(),
23780
+ stalePins: array(StaleDevicePinSchema).readonly()
23781
+ });
23782
+ /**
23783
+ * Where an automatic share's capacity comes from (D755).
23784
+ * - `hardware` — the static capacity of each device at its Auto tune model:
23785
+ * the measured latency table for the node's hardware class.
23786
+ * - `benchmark` — the node's own measured capacity (node benchmark results).
23787
+ * A node with no results falls back to `hardware`, and says so.
23788
+ */
23789
+ var CapacitySourceSchema = _enum(["hardware", "benchmark"]);
23790
+ /** Why a node under the `benchmark` source was sized from hardware instead. */
23791
+ var CapacityFallbackSchema = _enum(["no-benchmark-results", "partial-benchmark-results"]);
23792
+ var SuggestSharesInputSchema = object({
23793
+ headroom: number().min(.3).max(.5).default(.4),
23794
+ /** Default `hardware`. */
23795
+ source: CapacitySourceSchema.default("hardware")
23796
+ });
23797
+ var SuggestedDeviceShareSchema = object({
23798
+ deviceKey: string(),
23799
+ /** Share of the node (0–100, rounded). */
23800
+ share: number(),
23801
+ modelId: string().nullable(),
23802
+ /** Inferences per second at that model, from the measured table; null when sized by a benchmark. */
23803
+ fps: number().nullable(),
23804
+ /** False for a table cell derived from another chip; true for a measured cell or a benchmark. */
23805
+ measured: boolean(),
23806
+ /**
23807
+ * Advisory session cap: ⌊fps × (1 − headroom) / camera fps⌋ from the table,
23808
+ * or the benchmark's measured max sessions. Never enforced.
23809
+ */
23810
+ suggestedMaxSessions: number().nullable()
23811
+ });
23812
+ var SuggestedNodeShareSchema = object({
23813
+ nodeId: string(),
23814
+ /** Share of the cluster (0–100, rounded); null = node skipped (offline, unknown hardware). */
23815
+ share: number().nullable(),
23816
+ /** Parallel sessions the node sustains at the suggested models with the headroom kept free. */
23817
+ capacitySessions: number(),
23818
+ devices: array(SuggestedDeviceShareSchema).readonly(),
23819
+ skippedReason: string().nullable(),
23820
+ /** What this node's capacity was read from; null when the node is skipped. */
23821
+ capacitySource: CapacitySourceSchema.nullable(),
23822
+ /** Set when the `benchmark` source was asked for and this node used `hardware`. */
23823
+ capacityFallback: CapacityFallbackSchema.nullable()
23824
+ });
23825
+ var SuggestSharesResultSchema = object({
23826
+ headroom: number(),
23827
+ /** The source asked for; each node says what it actually used. */
23828
+ source: CapacitySourceSchema,
23829
+ /** Camera detection rate the capacity is counted in (the fastest camera's fps). */
23830
+ cameraFps: number(),
23831
+ /** The Auto tune capacity floor the models were picked at. */
23832
+ minSessionsPerDevice: number(),
23833
+ nodes: array(SuggestedNodeShareSchema).readonly()
23834
+ });
23835
+ /**
23836
+ * Where the node and device shares come from (D750, D755).
23837
+ * - `hardware` (default) — computed by the system from each node's static
23838
+ * capacity (its accelerators at their Auto tune models, from the measured
23839
+ * latency table), recomputed whenever a node or device joins, leaves, is
23840
+ * switched on or off, or changes model. No load input.
23841
+ * - `benchmark` — the same, from each node's measured capacity (node
23842
+ * benchmark results); a node without results falls back to `hardware`.
23843
+ * - `manual` — the operator's stored sliders.
23844
+ * Either way a node or device that cannot take sessions gives its share to
23845
+ * the others in proportion; the stored values are never rewritten for that.
23846
+ */
23847
+ var ShareSourceSchema = _enum([
23848
+ "hardware",
23849
+ "benchmark",
23850
+ "manual"
23851
+ ]);
23852
+ var SetShareSourceInputSchema = object({ source: ShareSourceSchema });
23853
+ object({
23854
+ nodes: record(string(), number()),
23855
+ devices: record(string(), record(string(), number()))
23856
+ });
23857
+ var EffectiveDeviceShareSchema = object({
23858
+ deviceKey: string(),
23859
+ /** Can take sessions now (enabled, available, can run the root). */
23860
+ eligible: boolean(),
23861
+ /** The share the source assigns, as a percentage of the node's devices. */
23862
+ configuredPct: number(),
23863
+ /** The share actually used, after an ineligible device's share went to the others. */
23864
+ effectivePct: number()
23865
+ });
23866
+ var EffectiveNodeShareSchema = object({
23867
+ nodeId: string(),
23868
+ eligible: boolean(),
23869
+ configuredPct: number(),
23870
+ effectivePct: number(),
23871
+ /** Automatic sources: what this node's share was computed from; null under `manual` or before the first answer. */
23872
+ capacitySource: CapacitySourceSchema.nullable(),
23873
+ /** Automatic `benchmark`: why this node used `hardware` instead. */
23874
+ capacityFallback: CapacityFallbackSchema.nullable(),
23875
+ devices: array(EffectiveDeviceShareSchema).readonly()
23876
+ });
23877
+ var EffectiveSharesSchema = object({
23878
+ source: ShareSourceSchema,
23879
+ policy: SessionPlacementPolicySchema,
23880
+ /** An automatic source with no computed answer yet: the stored sliders are used meanwhile. */
23881
+ autoPending: boolean(),
23882
+ /** When the automatic shares were last computed (ms epoch); null = never. */
23883
+ computedAt: number().nullable(),
23884
+ /** What made the system recompute them last. */
23885
+ trigger: string().nullable(),
23886
+ nodes: array(EffectiveNodeShareSchema).readonly(),
23887
+ /** The relative weights the election reads (before eligibility). */
23888
+ nodeWeights: record(string(), number()),
23889
+ deviceWeights: record(string(), record(string(), number()))
23890
+ });
23539
23891
  object({
23540
23892
  activeCameras: number(),
23541
23893
  throttledCameras: number(),
@@ -23979,6 +24331,22 @@ var MotionSourceEnum = _enum([
23979
24331
  "device-activity"
23980
24332
  ]);
23981
24333
  /**
24334
+ * What opened an on-motion detection SESSION: the motion source that passed the
24335
+ * camera's `motionSources` gate, and what raised it (the camera itself, or a
24336
+ * sensor the operator attached — D672). `sensorName` is the attached sensor's
24337
+ * device name as the orchestrator's camera-sensors resolution last read it;
24338
+ * absent when unknown or when the camera itself triggered.
24339
+ *
24340
+ * Carried on the session attach ONLY so the runner's `DetectionPhaseTransition`
24341
+ * can say what started the session (D672 rule 11, amended 2026-10-06). The
24342
+ * runner never decides anything on it.
24343
+ */
24344
+ var SessionTriggerSchema = object({
24345
+ source: MotionSourceEnum,
24346
+ triggeredBy: MotionTriggeredBySchema,
24347
+ sensorName: string().optional()
24348
+ });
24349
+ /**
23982
24350
  * List of motion sources active on a camera. Empty array is valid:
23983
24351
  * "no source" — happens for battery cams without firmware motion when
23984
24352
  * the operator hasn't opted into the SW analyzer (would hold the
@@ -24230,6 +24598,14 @@ var RunnerCameraConfigSchema = object({
24230
24598
  */
24231
24599
  motionSources: MotionSourcesSchema.default(["analyzer"]),
24232
24600
  /**
24601
+ * What opened this attach, on a SESSION attach only (see
24602
+ * {@link SessionTriggerSchema}). OPTIONAL with no default: absent on a
24603
+ * standing attach, an occupancy burst, a re-dispatch with no motion event
24604
+ * behind it, and every attach from an orchestrator older than the field — the
24605
+ * runner then names no source on the phase event.
24606
+ */
24607
+ sessionTrigger: SessionTriggerSchema.optional(),
24608
+ /**
24233
24609
  * WHICH root detector runs for this camera. The detection counterpart of
24234
24610
  * {@link motionSources}, same shape and same discipline: a per-camera list
24235
24611
  * of sources the system understands, vendor-agnostic, owned here.
@@ -24389,14 +24765,15 @@ var RunnerLocalLoadSchema = object({
24389
24765
  * Per-inference-device live load (multi-device C4). One entry per deviceKey
24390
24766
  * this runner currently has attached cameras on, so the orchestrator's second
24391
24767
  * `balance()` pass (over a node's devices) weights on real per-pool session
24392
- * counts. Empty on single-device / pre-multi-device runners. `queueDepthTotal`
24393
- * per device is 0 until the pool backlog gets a public accessor (follow-up).
24768
+ * counts. Empty on single-device / pre-multi-device runners. There is no
24769
+ * per-device queue depth: the inference pool's backlog has no accessor, and
24770
+ * a field that always read 0 was removed rather than shown as a measurement
24771
+ * (D762).
24394
24772
  */
24395
24773
  devices: array(object({
24396
24774
  deviceKey: string(),
24397
24775
  backend: string(),
24398
- attachedCameras: number(),
24399
- queueDepthTotal: number()
24776
+ attachedCameras: number()
24400
24777
  })).default([]),
24401
24778
  /** Hardware capability flags reported by this node. */
24402
24779
  hardware: object({
@@ -24532,7 +24909,22 @@ method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mu
24532
24909
  */
24533
24910
  cropJpeg: string().optional(),
24534
24911
  parent: DetailParentSchema,
24535
- steps: array(string()).optional()
24912
+ steps: array(string()).optional(),
24913
+ /**
24914
+ * The camera's root model already drew this step's boxes (D730): a
24915
+ * `license_plate` inside the parent vehicle. The named step is NOT
24916
+ * inferred — these FRAME-space boxes are its output — and its
24917
+ * requested children (the plate reader) run on them. Absent ⇒ every
24918
+ * requested step infers as before.
24919
+ */
24920
+ supplied: object({
24921
+ stepId: string(),
24922
+ modelId: string(),
24923
+ boxes: array(object({
24924
+ bbox: NativeCropBboxSchema,
24925
+ score: number()
24926
+ })).min(1)
24927
+ }).optional()
24536
24928
  }), object({ details: array(DetailResultSchema) }).nullable(), { kind: "mutation" }), method(object({
24537
24929
  /** Catalog step id, e.g. `clip-embedding`. */
24538
24930
  stepId: string(),
@@ -24595,14 +24987,6 @@ var CameraPipelineConfigSchema = object({
24595
24987
  settings: record(string(), unknown()).readonly().optional()
24596
24988
  }).nullable().optional()
24597
24989
  });
24598
- var PipelineTemplateSchema = object({
24599
- id: string(),
24600
- name: string(),
24601
- description: string().optional(),
24602
- config: CameraPipelineConfigSchema,
24603
- createdAt: string(),
24604
- updatedAt: string()
24605
- });
24606
24990
  var DeviceStepConfigSchema = object({
24607
24991
  modelId: string().optional(),
24608
24992
  settings: record(string(), unknown()).optional(),
@@ -24676,9 +25060,10 @@ var CameraStepOverridePatchSchema = object({
24676
25060
  modelId: string().optional(),
24677
25061
  settings: record(string(), unknown()).readonly().optional()
24678
25062
  });
25063
+ var CameraStepSettingsSchema = record(string(), record(string(), unknown()).readonly());
24679
25064
  var CameraPipelineSettingsSchema = object({
24680
- pinnedAgentNodeId: string().optional(),
24681
25065
  stepToggles: record(string(), boolean()).optional(),
25066
+ stepSettings: CameraStepSettingsSchema.optional(),
24682
25067
  stepOverridesByDevice: record(string(), record(string(), record(string(), CameraStepOverridePatchSchema))).optional(),
24683
25068
  pipelineByAgent: record(string(), CameraPipelineForAgentSchema).optional()
24684
25069
  });
@@ -24711,7 +25096,10 @@ var PipelineAssignmentSchema = object({
24711
25096
  });
24712
25097
  /**
24713
25098
  * Per-agent load summary surfaced to the load balancer + dashboards.
24714
- * Aggregated from each runner's `getLocalLoad` cap call.
25099
+ * Aggregated from each runner's `getLocalLoad` cap call. In the
25100
+ * `getAgentLoad` report, a single-device node's default-pool sessions (no
25101
+ * `deviceKey`) are credited to its one eligible device in `load.devices` —
25102
+ * the default pool IS that device (D745); the balancer's census stays raw.
24715
25103
  */
24716
25104
  var AgentLoadSummarySchema = object({
24717
25105
  nodeId: string(),
@@ -24800,26 +25188,27 @@ var CameraBrokerStatusSchema = object({
24800
25188
  width: number(),
24801
25189
  height: number(),
24802
25190
  subscribers: number(),
24803
- inFps: number(),
24804
- outFps: number()
25191
+ /**
25192
+ * Encoded packets/s the broker receives from the camera. null when the
25193
+ * broker's stats read failed — unknown, never 0 (a 0 here reads as a stall).
25194
+ * There is no output rate: decoding runs in the session decode workers, not
25195
+ * in the broker, so the broker's own decoded-frame rate is 0 on every live
25196
+ * camera and is not served (D758).
25197
+ */
25198
+ inFps: number().nullable()
24805
25199
  })).readonly(),
24806
25200
  webrtcSessions: number(),
24807
25201
  rtspRestream: boolean()
24808
25202
  });
24809
- /** Shared-memory ring statistics within the decoder block. */
24810
- var CameraDecoderShmSchema = object({
24811
- framesWritten: number(),
24812
- getFrameHits: number(),
24813
- getFrameMisses: number(),
24814
- budgetMb: number()
24815
- });
24816
- /** Decoder block — null when the decoder stage is unreachable or inactive. */
24817
- var CameraDecoderStatusSchema = object({
24818
- nodeId: string(),
24819
- formats: array(string()).readonly(),
24820
- sessionCount: number(),
24821
- shm: CameraDecoderShmSchema
24822
- });
25203
+ /**
25204
+ * Decoder block — WHERE decode runs (co-located with the detection node by
25205
+ * construction); null when the camera has no detection node. It carries no
25206
+ * frame counter: the shared-memory plane whose counters it used to serve is
25207
+ * gone, and those fields read 0 forever. Whether frames actually flow is read
25208
+ * from `detection.actualFps` (frames delivered to and processed by the
25209
+ * detector), never from a counter nothing feeds.
25210
+ */
25211
+ var CameraDecoderStatusSchema = object({ nodeId: string() });
24823
25212
  /** Motion block — null when motion detection is not active for this device. */
24824
25213
  var CameraMotionStatusSchema = object({
24825
25214
  enabled: boolean(),
@@ -25176,12 +25565,6 @@ method(object({
25176
25565
  }), object({ success: literal(true) }), {
25177
25566
  kind: "mutation",
25178
25567
  auth: "admin"
25179
- }), method(object({
25180
- agentNodeId: string(),
25181
- detectWeight: number().positive().nullable()
25182
- }), object({ success: literal(true) }), {
25183
- kind: "mutation",
25184
- auth: "admin"
25185
25568
  }), method(object({
25186
25569
  agentNodeId: string(),
25187
25570
  detect: boolean().nullable().optional(),
@@ -25223,6 +25606,15 @@ method(object({
25223
25606
  }), {
25224
25607
  kind: "mutation",
25225
25608
  auth: "admin"
25609
+ }), method(AutoTuneOptionsSchema, AutoTunePlanSchema, { auth: "admin" }), method(AutoTuneApplyInputSchema, AutoTuneApplyResultSchema, {
25610
+ kind: "mutation",
25611
+ auth: "admin"
25612
+ }), method(LoadBalancingSharesInputSchema, object({ success: literal(true) }), {
25613
+ kind: "mutation",
25614
+ auth: "admin"
25615
+ }), method(PlacementStatsInputSchema, PlacementStatsSchema, { auth: "admin" }), method(SuggestSharesInputSchema, SuggestSharesResultSchema, { auth: "admin" }), method(_void(), EffectiveSharesSchema, { auth: "admin" }), method(SetShareSourceInputSchema, object({ success: literal(true) }), {
25616
+ kind: "mutation",
25617
+ auth: "admin"
25226
25618
  }), method(object({ deviceId: number() }), CameraPipelineSettingsSchema.nullable()), method(object({
25227
25619
  deviceId: number(),
25228
25620
  addonId: string(),
@@ -25239,6 +25631,13 @@ method(object({
25239
25631
  }), object({ success: literal(true) }), {
25240
25632
  kind: "mutation",
25241
25633
  auth: "admin"
25634
+ }), method(object({
25635
+ deviceId: number(),
25636
+ addonId: string(),
25637
+ settings: record(string(), unknown()).nullable()
25638
+ }), object({ success: literal(true) }), {
25639
+ kind: "mutation",
25640
+ auth: "admin"
25242
25641
  }), method(object({
25243
25642
  deviceId: number(),
25244
25643
  agentNodeId: string(),
@@ -25262,25 +25661,7 @@ method(object({
25262
25661
  }), method(_void(), DiskReconcileJobSchema, {
25263
25662
  kind: "mutation",
25264
25663
  auth: "admin"
25265
- }), method(_void(), DiskReconcileJobSchema, { auth: "admin" }), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
25266
- name: string(),
25267
- description: string().optional(),
25268
- config: CameraPipelineConfigSchema
25269
- }), PipelineTemplateSchema, {
25270
- kind: "mutation",
25271
- auth: "admin"
25272
- }), method(object({
25273
- id: string(),
25274
- name: string().optional(),
25275
- description: string().optional(),
25276
- config: CameraPipelineConfigSchema.optional()
25277
- }), PipelineTemplateSchema, {
25278
- kind: "mutation",
25279
- auth: "admin"
25280
- }), method(object({ id: string() }), object({ success: literal(true) }), {
25281
- kind: "mutation",
25282
- auth: "admin"
25283
- });
25664
+ }), method(_void(), DiskReconcileJobSchema, { auth: "admin" });
25284
25665
  /**
25285
25666
  * Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
25286
25667
  * `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
@@ -27500,8 +27881,6 @@ var WebrtcStreamChoiceSchema = object({
27500
27881
  ]).nullable(),
27501
27882
  /** Input FPS from the camera (null for adaptive). */
27502
27883
  inputFps: number().nullable(),
27503
- /** Decoded FPS (null for adaptive). */
27504
- decodeFps: number().nullable(),
27505
27884
  /** Bitrate in kbps (null for adaptive). */
27506
27885
  bitrateKbps: number().nullable()
27507
27886
  });
@@ -27778,7 +28157,22 @@ DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), ar
27778
28157
  * field their hints were silently stripped by the schema and the
27779
28158
  * adaptive ladder started blind on the client's display size.
27780
28159
  */
27781
- hints: webrtcClientHintsSchema.optional()
28160
+ hints: webrtcClientHintsSchema.optional(),
28161
+ /**
28162
+ * Talk-back (D771): relay the PEER's audio to the device's speaker
28163
+ * through the `intercom` cap's push-talk triple. When `true` and the
28164
+ * offer lets the peer send audio, the answer's audio is `sendrecv`
28165
+ * and every inbound frame goes to `intercom.pushTalkAudio` for this
28166
+ * `deviceId`; absent/false answers `sendonly`, as for every viewer.
28167
+ *
28168
+ * TRUSTED-CALLER ONLY. Set by the Alexa export for an Echo on a camera
28169
+ * with `intercom`, when the linked user may control that camera. The
28170
+ * hub STRIPS it from every request-bound call (a browser), exactly as
28171
+ * it overwrites `relayOnly` — a viewer's talk permission is the
28172
+ * intercom cap's own surface (share tokens gate it there), and this
28173
+ * flag must not become a second door to the camera's speaker.
28174
+ */
28175
+ talkback: boolean().optional()
27782
28176
  }), object({
27783
28177
  sessionId: string(),
27784
28178
  sdpAnswer: string()
@@ -27833,6 +28227,14 @@ DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), ar
27833
28227
  */
27834
28228
  alive: boolean()
27835
28229
  })), method(object({
28230
+ deviceId: number().int().nonnegative(),
28231
+ sessionId: string(),
28232
+ downlinkMbps: number().nonnegative()
28233
+ }), object({
28234
+ outcome: _enum(["switching", "held"]),
28235
+ tier: CamProfileSchema.nullable(),
28236
+ reason: string()
28237
+ }), { kind: "mutation" }), method(object({
27836
28238
  deviceId: number().int().nonnegative(),
27837
28239
  sessionId: string()
27838
28240
  }), WebrtcSessionDebugSchema, { kind: "query" });
@@ -28072,6 +28474,59 @@ var AddonAutoUpdateSchema = ChannelWithInheritSchema;
28072
28474
  var RestartAddonResultSchema = unknown();
28073
28475
  var InstallPackageResultSchema = unknown();
28074
28476
  var ReloadPackagesResultSchema = unknown();
28477
+ /**
28478
+ * What an uninstall did on ONE node.
28479
+ * - `uninstalled` — removed: runner(s) stopped, caps gone, code deleted.
28480
+ * - `not-installed` — the node did not have it (nothing to do).
28481
+ * - `refused` — protected / bootstrap package; nothing touched.
28482
+ * - `failed` — attempted and did not complete; `error` says why.
28483
+ * - `pending-reconnect` — the node is OFFLINE: its record was pruned so the
28484
+ * back-fill never returns the package, and the stale-addon sweep removes the
28485
+ * copy when the node registers again (only once the hub no longer has it).
28486
+ */
28487
+ var UninstallNodeOutcomeSchema = _enum([
28488
+ "uninstalled",
28489
+ "not-installed",
28490
+ "refused",
28491
+ "failed",
28492
+ "pending-reconnect"
28493
+ ]);
28494
+ var UninstallNodeResultSchema = object({
28495
+ nodeId: string(),
28496
+ outcome: UninstallNodeOutcomeSchema,
28497
+ error: string().optional(),
28498
+ addonIds: array(string()).readonly(),
28499
+ runnersStopped: array(string()).readonly(),
28500
+ warnings: array(string()).readonly()
28501
+ });
28502
+ var UninstallPackageResultSchema = object({
28503
+ /** Every targeted node ended `uninstalled`, `not-installed` or `pending-reconnect`. */
28504
+ success: boolean(),
28505
+ packageName: string(),
28506
+ results: array(UninstallNodeResultSchema).readonly()
28507
+ });
28508
+ /**
28509
+ * `unreachable` lists online agents whose status read FAILED — absence from
28510
+ * `installations` is only "not installed" for a node that answered (D315).
28511
+ */
28512
+ var PackageInstallationsSchema = object({
28513
+ installations: array(object({
28514
+ packageName: string(),
28515
+ nodeId: string(),
28516
+ nodeName: string(),
28517
+ isHub: boolean(),
28518
+ isOnline: boolean(),
28519
+ version: string().nullable(),
28520
+ addonIds: array(string()).readonly(),
28521
+ source: _enum(["live", "recorded"]),
28522
+ /** The hub installs this package too. `false` on an agent row = an orphan. */
28523
+ onHub: boolean()
28524
+ })).readonly(),
28525
+ unreachable: array(object({
28526
+ nodeId: string(),
28527
+ error: string()
28528
+ })).readonly()
28529
+ });
28075
28530
  var BulkUpdateItemStatusSchema = _enum([
28076
28531
  "queued",
28077
28532
  "updating",
@@ -28154,10 +28609,14 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
28154
28609
  }), method(object({ packageName: string() }), InstallPackageResultSchema, {
28155
28610
  kind: "mutation",
28156
28611
  auth: "admin"
28157
- }), method(_void(), boolean()), method(_void(), array(unknown()).readonly()), method(object({ packageName: string() }), unknown(), {
28612
+ }), method(_void(), boolean()), method(_void(), array(unknown()).readonly()), method(object({
28613
+ packageName: string().min(1),
28614
+ nodeId: string().optional(),
28615
+ everywhere: boolean().optional()
28616
+ }), UninstallPackageResultSchema, {
28158
28617
  kind: "mutation",
28159
28618
  auth: "admin"
28160
- }), method(_void(), ReloadPackagesResultSchema, {
28619
+ }), method(object({ packageName: string().optional() }), PackageInstallationsSchema, { auth: "admin" }), method(_void(), ReloadPackagesResultSchema, {
28161
28620
  kind: "mutation",
28162
28621
  auth: "admin"
28163
28622
  }), method(object({ query: string().optional() }), array(SearchResultSchema)), method(object({ nodeId: string().optional() }), array(PackageUpdateSchema).readonly(), { auth: "admin" }), method(object({
@@ -30453,7 +30912,7 @@ var LocalInterfaceSchema = object({
30453
30912
  name: string(),
30454
30913
  family: _enum(["IPv4", "IPv6"]),
30455
30914
  address: string(),
30456
- /** CIDR shorthand (e.g. `192.168.x.x/24`). Empty when OS doesn't expose. */
30915
+ /** CIDR shorthand (e.g. `192.168.10.10/24`). Empty when OS doesn't expose. */
30457
30916
  cidr: string(),
30458
30917
  /** OS netmask. Stable across calls so the SDK can hash on it. */
30459
30918
  netmask: string(),
@@ -30507,7 +30966,9 @@ var ConnectionEndpointSchema = object({
30507
30966
  "lan-ipv4",
30508
30967
  "lan-ipv6",
30509
30968
  "public",
30510
- "loopback"
30969
+ "loopback",
30970
+ "app-link",
30971
+ "custom"
30511
30972
  ]),
30512
30973
  /**
30513
30974
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -30576,15 +31037,27 @@ var GetConnectionEndpointsResultSchema = object({
30576
31037
  localPort: AdvertisedLocalPortSchema
30577
31038
  });
30578
31039
  /**
30579
- * The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
30580
- * AUTO (resolved from the candidate ranking at send time); `resolved` reports
30581
- * what AUTO currently picks, so the UI can show the effective value either way.
31040
+ * The address flagged for notification taps (`notificationTaps`). `baseUrl: null` = AUTO, which
31041
+ * since D709 is the CamStack app link; `resolved` reports the effective value,
31042
+ * so the UI can show it either way.
30582
31043
  */
30583
31044
  var NotificationEndpointSchema = object({
30584
31045
  /** The operator's explicit choice, or null for AUTO. */
30585
31046
  baseUrl: string().nullable(),
30586
- /** What the ranking currently resolves to (null when nothing is reachable). */
30587
- resolved: string().nullable()
31047
+ /**
31048
+ * The effective flagged address: the explicit choice, else (AUTO) the
31049
+ * CamStack app link `https://camstack.zentik.app` (D709). A pre-D709 hub
31050
+ * answered the public tunnel / mesh here, or null.
31051
+ */
31052
+ resolved: string().nullable(),
31053
+ /**
31054
+ * The hub origin an app link carries as `hub=` (D709): the hub's best
31055
+ * public HTTPS address — the tunnel, then the mesh (Tailscale MagicDNS) —
31056
+ * picked from this cap's own palette by `pickAppLinkHub`. `null` when the
31057
+ * hub advertises neither; the app link is then minted without `hub=`.
31058
+ * Absent on a pre-D709 hub.
31059
+ */
31060
+ appLinkHub: string().nullable()
30588
31061
  });
30589
31062
  /**
30590
31063
  * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
@@ -30597,6 +31070,72 @@ var ViewerEndpointsSchema = object({
30597
31070
  /** What the ranking currently resolves to (may be empty if nothing is up). */
30598
31071
  resolved: array(string()).readonly()
30599
31072
  });
31073
+ /**
31074
+ * DEPRECATED compatibility shape of `getHubAddresses` (D729 amendment, kept
31075
+ * for addons built against it): `cluster` is the `internal` role, `browser`
31076
+ * the `publicEndpoint` role; `override` is the flagged address.
31077
+ */
31078
+ var HubAddressSnapshotSchema = object({
31079
+ override: string().nullable(),
31080
+ resolved: string().nullable(),
31081
+ source: _enum([
31082
+ "override",
31083
+ "auto",
31084
+ "none"
31085
+ ])
31086
+ });
31087
+ var HubAddressesSchema = object({
31088
+ cluster: HubAddressSnapshotSchema,
31089
+ browser: HubAddressSnapshotSchema
31090
+ });
31091
+ /**
31092
+ * What an address is used for (`hub-address.ts`, D734). `appConnections` is
31093
+ * many-valued; `notificationTaps`, `publicEndpoint` and `internal` are carried
31094
+ * by at most one address.
31095
+ */
31096
+ var HubAddressRoleSchema = _enum(HUB_ADDRESS_ROLES);
31097
+ var RoleSourceSchema = _enum([
31098
+ "flagged",
31099
+ "auto",
31100
+ "none"
31101
+ ]);
31102
+ /** One single-valued role: the flagged address, the one in use, and why. */
31103
+ var HubAddressRoleResolutionSchema = object({
31104
+ /** The address carrying the flag, or null = automatic. */
31105
+ flagged: string().nullable(),
31106
+ /** The address in use, or null when nothing qualifies (never loopback). */
31107
+ resolved: string().nullable(),
31108
+ source: RoleSourceSchema
31109
+ });
31110
+ var HubAppConnectionsResolutionSchema = object({
31111
+ /** The addresses flagged `appConnections`, or empty = automatic. */
31112
+ flagged: array(string()).readonly(),
31113
+ /** What the apps race right now. */
31114
+ resolved: array(string()).readonly(),
31115
+ source: RoleSourceSchema
31116
+ });
31117
+ var HubAddressBookSchema = object({
31118
+ rows: array(ConnectionEndpointSchema.extend({
31119
+ /** In the hub's detected palette right now. */
31120
+ detected: boolean(),
31121
+ /** Entered by the operator (removable). */
31122
+ custom: boolean(),
31123
+ /** The roles explicitly flagged on this address. */
31124
+ flags: array(HubAddressRoleSchema).readonly(),
31125
+ /** The roles this address serves right now — flagged or automatic. */
31126
+ inUse: array(HubAddressRoleSchema).readonly(),
31127
+ /** The roles this address may be flagged with. */
31128
+ eligible: array(HubAddressRoleSchema).readonly()
31129
+ })).readonly(),
31130
+ roles: object({
31131
+ appConnections: HubAppConnectionsResolutionSchema,
31132
+ notificationTaps: HubAddressRoleResolutionSchema,
31133
+ internal: HubAddressRoleResolutionSchema,
31134
+ publicEndpoint: HubAddressRoleResolutionSchema
31135
+ }),
31136
+ /** The `hub=` an app link carries (D709), or null. */
31137
+ appLinkHub: string().nullable()
31138
+ });
30600
31139
  var AllowedAddressesSchema = object({
30601
31140
  /**
30602
31141
  * Allowlist of interface addresses operators have explicitly opted
@@ -30638,8 +31177,29 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
30638
31177
  * Pass `'https'` when the caller is itself loaded over HTTPS
30639
31178
  * to avoid mixed-content blocks in the browser. The public
30640
31179
  * tunnel always emits `https://` regardless. */
30641
- scheme: _enum(["http", "https"]).optional()
30642
- }), 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, {
31180
+ scheme: _enum(["http", "https"]).optional(),
31181
+ /** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
31182
+ * an address notification taps can be flagged with, not a hub
31183
+ * route. Default `false`: racers and rankers never see it. */
31184
+ includeAppLink: boolean().optional()
31185
+ }), 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({
31186
+ baseUrl: string(),
31187
+ label: string().max(80)
31188
+ }), HubAddressBookSchema, {
31189
+ kind: "mutation",
31190
+ auth: "admin"
31191
+ }), method(object({ baseUrl: string() }), HubAddressBookSchema, {
31192
+ kind: "mutation",
31193
+ auth: "admin"
31194
+ }), method(object({
31195
+ role: HubAddressRoleSchema,
31196
+ baseUrl: string().nullable(),
31197
+ enabled: boolean(),
31198
+ acceptInsecureHttp: boolean().optional()
31199
+ }), HubAddressBookSchema, {
31200
+ kind: "mutation",
31201
+ auth: "admin"
31202
+ }), 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, {
30643
31203
  kind: "mutation",
30644
31204
  auth: "admin"
30645
31205
  }), method(object({
@@ -30899,7 +31459,7 @@ var MeshPeerSchema = object({
30899
31459
  tags: array(string()).readonly(),
30900
31460
  /** True when the peer advertises itself as an exit-node candidate. */
30901
31461
  exitNodeOption: boolean(),
30902
- /** Subnet routes the peer advertises (e.g. `["192.168.x.x/24"]`). */
31462
+ /** Subnet routes the peer advertises (e.g. `["192.168.10.0/24"]`). */
30903
31463
  advertisedRoutes: array(string()).readonly(),
30904
31464
  /** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
30905
31465
  userLogin: string().nullable(),
@@ -31029,7 +31589,8 @@ object({
31029
31589
  * writes this slice (not even a boot seed), and neither does the runner's
31030
31590
  * phase machine: its phase is "a session is attached" for every on-motion
31031
31591
  * session, not motion, and it now has its own `DetectionPhaseTransition`.
31032
- * A provider's `isDetected` answers from the hub's slice.
31592
+ * A provider's `isDetected` and `getStatus` answer from the hub's slice
31593
+ * (`hubMotionNativeProvider`).
31033
31594
  * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
31034
31595
  * imports) — the provider pushes both edges itself, from the upstream
31035
31596
  * system's own state change. That is the sensor's own fact.
@@ -31843,7 +32404,13 @@ var OsdStatusSchema = object({ overlays: array(object({
31843
32404
  */
31844
32405
  availablePositions: array(OsdPositionEnum).readonly(),
31845
32406
  /** Firmware does not allow editing the `text` field (e.g. timestamp). */
31846
- readOnly: boolean().optional()
32407
+ readOnly: boolean().optional(),
32408
+ /**
32409
+ * Firmware text ceiling for this overlay. Absent = no known limit.
32410
+ * The OSD manager truncates here on every write — never stores its own
32411
+ * copy on the binding.
32412
+ */
32413
+ maxCharacters: number().int().positive().optional()
31847
32414
  })).readonly() });
31848
32415
  var OsdOverlayPatchSchema = object({
31849
32416
  enabled: boolean().optional(),
@@ -31894,7 +32461,9 @@ var OsdTemplateBindingSchema = object({
31894
32461
  valuePath: string().min(1).max(64),
31895
32462
  /** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
31896
32463
  displayUnit: string().max(16).optional(),
31897
- maxDecimals: number().int().min(0).max(4).default(1)
32464
+ maxDecimals: number().int().min(0).max(4).default(1),
32465
+ /** Raw value → display text (same shape as slot binding). Empty string hides. */
32466
+ valueMap: record(string(), string()).optional()
31898
32467
  });
31899
32468
  /**
31900
32469
  * A named template: bindings (alias → leaf field) + a parser that
@@ -31944,18 +32513,11 @@ var OsdSlotBindingSchema = object({
31944
32513
  source: OsdSourceSchema,
31945
32514
  /** `${value}` and `${unit}` are substituted; every occurrence. */
31946
32515
  template: string().max(96).default("${value}"),
31947
- /** Truncate with an ellipsis past this length. Absent = no limit. */
31948
- maxCharacters: number().int().min(4).max(64).optional(),
31949
32516
  /**
31950
32517
  * Decimal places for a numeric value. `0` yields an integer — the
31951
32518
  * documented workaround for firmwares that reject `.` in overlay text.
31952
32519
  */
31953
32520
  maxDecimals: number().int().min(0).max(4).default(1),
31954
- /**
31955
- * Appended via `${unit}` when no unit conversion produces a label.
31956
- * Prefer `source.displayUnit` for converted device-state values.
31957
- */
31958
- unitLabel: string().max(8).optional(),
31959
32521
  /** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
31960
32522
  valueMap: record(string(), string()).optional(),
31961
32523
  /** Time windows in which the slot is shown. Absent = always. */
@@ -31964,9 +32526,7 @@ var OsdSlotBindingSchema = object({
31964
32526
  * Display gate, in the notification centre's condition vocabulary.
31965
32527
  * Only the keys reported by `getConditionSupport` are accepted.
31966
32528
  */
31967
- conditions: NcConditionsSchema.optional(),
31968
- /** Rendered when the gate is closed or the value unreadable. Empty = hide. */
31969
- fallbackText: string().max(64).default("")
32529
+ conditions: NcConditionsSchema.optional()
31970
32530
  });
31971
32531
  /** One camera slot, as the operator sees it: firmware truth + our binding. */
31972
32532
  var OsdSlotViewSchema = object({
@@ -36161,6 +36721,16 @@ DeviceType.Camera, method(object({
36161
36721
  package: array(ZoneRuleSchema).readonly()
36162
36722
  });
36163
36723
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
36724
+ Object.freeze({
36725
+ person: .5,
36726
+ vehicle: .5,
36727
+ animal: .5
36728
+ });
36729
+ Object.freeze({
36730
+ person: .65,
36731
+ vehicle: .65,
36732
+ animal: .65
36733
+ });
36164
36734
  /**
36165
36735
  * Accessory device helpers — shared across drivers.
36166
36736
  *
@@ -36335,6 +36905,12 @@ Object.freeze({
36335
36905
  addonId: null,
36336
36906
  access: "view"
36337
36907
  },
36908
+ "addons.listInstallations": {
36909
+ capName: "addons",
36910
+ capScope: "system",
36911
+ addonId: null,
36912
+ access: "view"
36913
+ },
36338
36914
  "addons.listJobs": {
36339
36915
  capName: "addons",
36340
36916
  capScope: "system",
@@ -37517,90 +38093,18 @@ Object.freeze({
37517
38093
  addonId: null,
37518
38094
  access: "create"
37519
38095
  },
37520
- "decoder.createSession": {
37521
- capName: "decoder",
37522
- capScope: "system",
37523
- addonId: null,
37524
- access: "view"
37525
- },
37526
- "decoder.destroySession": {
37527
- capName: "decoder",
37528
- capScope: "system",
37529
- addonId: null,
37530
- access: "delete"
37531
- },
37532
- "decoder.getFrame": {
37533
- capName: "decoder",
37534
- capScope: "system",
37535
- addonId: null,
37536
- access: "view"
37537
- },
37538
38096
  "decoder.getInfo": {
37539
38097
  capName: "decoder",
37540
38098
  capScope: "system",
37541
38099
  addonId: null,
37542
38100
  access: "view"
37543
38101
  },
37544
- "decoder.getShmStats": {
37545
- capName: "decoder",
37546
- capScope: "system",
37547
- addonId: null,
37548
- access: "view"
37549
- },
37550
- "decoder.getStats": {
37551
- capName: "decoder",
37552
- capScope: "system",
37553
- addonId: null,
37554
- access: "view"
37555
- },
37556
- "decoder.listActiveSessions": {
37557
- capName: "decoder",
37558
- capScope: "system",
37559
- addonId: null,
37560
- access: "view"
37561
- },
37562
- "decoder.openStream": {
37563
- capName: "decoder",
37564
- capScope: "system",
37565
- addonId: null,
37566
- access: "view"
37567
- },
37568
- "decoder.pullFrames": {
37569
- capName: "decoder",
37570
- capScope: "system",
37571
- addonId: null,
37572
- access: "view"
37573
- },
37574
- "decoder.pullHandles": {
37575
- capName: "decoder",
37576
- capScope: "system",
37577
- addonId: null,
37578
- access: "view"
37579
- },
37580
- "decoder.pushPacket": {
37581
- capName: "decoder",
37582
- capScope: "system",
37583
- addonId: null,
37584
- access: "view"
37585
- },
37586
38102
  "decoder.reprobeHwaccel": {
37587
38103
  capName: "decoder",
37588
38104
  capScope: "system",
37589
38105
  addonId: null,
37590
38106
  access: "create"
37591
38107
  },
37592
- "decoder.supportsCodec": {
37593
- capName: "decoder",
37594
- capScope: "system",
37595
- addonId: null,
37596
- access: "view"
37597
- },
37598
- "decoder.updateConfig": {
37599
- capName: "decoder",
37600
- capScope: "system",
37601
- addonId: null,
37602
- access: "view"
37603
- },
37604
38108
  "detectionPipeline.applyDeviceSettingsPatch": {
37605
38109
  capName: "detection-pipeline",
37606
38110
  capScope: "device",
@@ -39089,12 +39593,24 @@ Object.freeze({
39089
39593
  addonId: null,
39090
39594
  access: "view"
39091
39595
  },
39596
+ "localNetwork.addCustomAddress": {
39597
+ capName: "local-network",
39598
+ capScope: "system",
39599
+ addonId: null,
39600
+ access: "create"
39601
+ },
39092
39602
  "localNetwork.downloadCa": {
39093
39603
  capName: "local-network",
39094
39604
  capScope: "system",
39095
39605
  addonId: null,
39096
39606
  access: "view"
39097
39607
  },
39608
+ "localNetwork.getAddresses": {
39609
+ capName: "local-network",
39610
+ capScope: "system",
39611
+ addonId: null,
39612
+ access: "view"
39613
+ },
39098
39614
  "localNetwork.getAllowedAddresses": {
39099
39615
  capName: "local-network",
39100
39616
  capScope: "system",
@@ -39107,6 +39623,12 @@ Object.freeze({
39107
39623
  addonId: null,
39108
39624
  access: "view"
39109
39625
  },
39626
+ "localNetwork.getHubAddresses": {
39627
+ capName: "local-network",
39628
+ capScope: "system",
39629
+ addonId: null,
39630
+ access: "view"
39631
+ },
39110
39632
  "localNetwork.getNotificationEndpoint": {
39111
39633
  capName: "local-network",
39112
39634
  capScope: "system",
@@ -39143,6 +39665,12 @@ Object.freeze({
39143
39665
  addonId: null,
39144
39666
  access: "create"
39145
39667
  },
39668
+ "localNetwork.removeCustomAddress": {
39669
+ capName: "local-network",
39670
+ capScope: "system",
39671
+ addonId: null,
39672
+ access: "delete"
39673
+ },
39146
39674
  "localNetwork.resetAllowlistToBestMatch": {
39147
39675
  capName: "local-network",
39148
39676
  capScope: "system",
@@ -39155,6 +39683,12 @@ Object.freeze({
39155
39683
  addonId: null,
39156
39684
  access: "create"
39157
39685
  },
39686
+ "localNetwork.setAddressRole": {
39687
+ capName: "local-network",
39688
+ capScope: "system",
39689
+ addonId: null,
39690
+ access: "create"
39691
+ },
39158
39692
  "localNetwork.setAllowedAddresses": {
39159
39693
  capName: "local-network",
39160
39694
  capScope: "system",
@@ -40649,13 +41183,13 @@ Object.freeze({
40649
41183
  addonId: null,
40650
41184
  access: "delete"
40651
41185
  },
40652
- "pipelineExecutor.deleteModel": {
41186
+ "pipelineExecutor.clearModelBoundDeviceOverrides": {
40653
41187
  capName: "pipeline-executor",
40654
41188
  capScope: "system",
40655
41189
  addonId: null,
40656
41190
  access: "delete"
40657
41191
  },
40658
- "pipelineExecutor.deleteTemplate": {
41192
+ "pipelineExecutor.deleteModel": {
40659
41193
  capName: "pipeline-executor",
40660
41194
  capScope: "system",
40661
41195
  addonId: null,
@@ -40799,12 +41333,6 @@ Object.freeze({
40799
41333
  addonId: null,
40800
41334
  access: "view"
40801
41335
  },
40802
- "pipelineExecutor.listTemplates": {
40803
- capName: "pipeline-executor",
40804
- capScope: "system",
40805
- addonId: null,
40806
- access: "view"
40807
- },
40808
41336
  "pipelineExecutor.rearmInferenceDevice": {
40809
41337
  capName: "pipeline-executor",
40810
41338
  capScope: "system",
@@ -40829,12 +41357,6 @@ Object.freeze({
40829
41357
  addonId: null,
40830
41358
  access: "create"
40831
41359
  },
40832
- "pipelineExecutor.saveTemplate": {
40833
- capName: "pipeline-executor",
40834
- capScope: "system",
40835
- addonId: null,
40836
- access: "create"
40837
- },
40838
41360
  "pipelineExecutor.setVideoPipelineSteps": {
40839
41361
  capName: "pipeline-executor",
40840
41362
  capScope: "system",
@@ -40853,41 +41375,35 @@ Object.freeze({
40853
41375
  addonId: null,
40854
41376
  access: "create"
40855
41377
  },
40856
- "pipelineExecutor.updateTemplate": {
40857
- capName: "pipeline-executor",
40858
- capScope: "system",
40859
- addonId: null,
40860
- access: "create"
40861
- },
40862
41378
  "pipelineExecutor.validatePipeline": {
40863
41379
  capName: "pipeline-executor",
40864
41380
  capScope: "system",
40865
41381
  addonId: null,
40866
41382
  access: "view"
40867
41383
  },
40868
- "pipelineOrchestrator.applyDeviceSettingsPatch": {
41384
+ "pipelineOrchestrator.applyAutoTune": {
40869
41385
  capName: "pipeline-orchestrator",
40870
41386
  capScope: "system",
40871
41387
  addonId: null,
40872
41388
  access: "create"
40873
41389
  },
40874
- "pipelineOrchestrator.assignAudio": {
41390
+ "pipelineOrchestrator.applyDeviceSettingsPatch": {
40875
41391
  capName: "pipeline-orchestrator",
40876
41392
  capScope: "system",
40877
41393
  addonId: null,
40878
41394
  access: "create"
40879
41395
  },
40880
- "pipelineOrchestrator.assignPipeline": {
41396
+ "pipelineOrchestrator.assignAudio": {
40881
41397
  capName: "pipeline-orchestrator",
40882
41398
  capScope: "system",
40883
41399
  addonId: null,
40884
41400
  access: "create"
40885
41401
  },
40886
- "pipelineOrchestrator.deleteTemplate": {
41402
+ "pipelineOrchestrator.assignPipeline": {
40887
41403
  capName: "pipeline-orchestrator",
40888
41404
  capScope: "system",
40889
41405
  addonId: null,
40890
- access: "delete"
41406
+ access: "create"
40891
41407
  },
40892
41408
  "pipelineOrchestrator.getAgentLoad": {
40893
41409
  capName: "pipeline-orchestrator",
@@ -40979,6 +41495,12 @@ Object.freeze({
40979
41495
  addonId: null,
40980
41496
  access: "view"
40981
41497
  },
41498
+ "pipelineOrchestrator.getEffectiveShares": {
41499
+ capName: "pipeline-orchestrator",
41500
+ capScope: "system",
41501
+ addonId: null,
41502
+ access: "view"
41503
+ },
40982
41504
  "pipelineOrchestrator.getGlobalMetrics": {
40983
41505
  capName: "pipeline-orchestrator",
40984
41506
  capScope: "system",
@@ -41015,19 +41537,19 @@ Object.freeze({
41015
41537
  addonId: null,
41016
41538
  access: "view"
41017
41539
  },
41018
- "pipelineOrchestrator.getReconcileFromDiskStatus": {
41540
+ "pipelineOrchestrator.getPlacementStats": {
41019
41541
  capName: "pipeline-orchestrator",
41020
41542
  capScope: "system",
41021
41543
  addonId: null,
41022
41544
  access: "view"
41023
41545
  },
41024
- "pipelineOrchestrator.listAgentSettings": {
41546
+ "pipelineOrchestrator.getReconcileFromDiskStatus": {
41025
41547
  capName: "pipeline-orchestrator",
41026
41548
  capScope: "system",
41027
41549
  addonId: null,
41028
41550
  access: "view"
41029
41551
  },
41030
- "pipelineOrchestrator.listTemplates": {
41552
+ "pipelineOrchestrator.listAgentSettings": {
41031
41553
  capName: "pipeline-orchestrator",
41032
41554
  capScope: "system",
41033
41555
  addonId: null,
@@ -41039,6 +41561,12 @@ Object.freeze({
41039
41561
  addonId: null,
41040
41562
  access: "create"
41041
41563
  },
41564
+ "pipelineOrchestrator.planAutoTune": {
41565
+ capName: "pipeline-orchestrator",
41566
+ capScope: "system",
41567
+ addonId: null,
41568
+ access: "view"
41569
+ },
41042
41570
  "pipelineOrchestrator.rebalance": {
41043
41571
  capName: "pipeline-orchestrator",
41044
41572
  capScope: "system",
@@ -41081,12 +41609,6 @@ Object.freeze({
41081
41609
  addonId: null,
41082
41610
  access: "create"
41083
41611
  },
41084
- "pipelineOrchestrator.saveTemplate": {
41085
- capName: "pipeline-orchestrator",
41086
- capScope: "system",
41087
- addonId: null,
41088
- access: "create"
41089
- },
41090
41612
  "pipelineOrchestrator.setAgentCapabilities": {
41091
41613
  capName: "pipeline-orchestrator",
41092
41614
  capScope: "system",
@@ -41099,12 +41621,6 @@ Object.freeze({
41099
41621
  addonId: null,
41100
41622
  access: "create"
41101
41623
  },
41102
- "pipelineOrchestrator.setAgentDetectWeight": {
41103
- capName: "pipeline-orchestrator",
41104
- capScope: "system",
41105
- addonId: null,
41106
- access: "create"
41107
- },
41108
41624
  "pipelineOrchestrator.setAgentInferenceDevices": {
41109
41625
  capName: "pipeline-orchestrator",
41110
41626
  capScope: "system",
@@ -41141,6 +41657,12 @@ Object.freeze({
41141
41657
  addonId: null,
41142
41658
  access: "create"
41143
41659
  },
41660
+ "pipelineOrchestrator.setCameraStepSettings": {
41661
+ capName: "pipeline-orchestrator",
41662
+ capScope: "system",
41663
+ addonId: null,
41664
+ access: "create"
41665
+ },
41144
41666
  "pipelineOrchestrator.setCameraStepToggle": {
41145
41667
  capName: "pipeline-orchestrator",
41146
41668
  capScope: "system",
@@ -41159,25 +41681,37 @@ Object.freeze({
41159
41681
  addonId: null,
41160
41682
  access: "create"
41161
41683
  },
41684
+ "pipelineOrchestrator.setLoadBalancingShares": {
41685
+ capName: "pipeline-orchestrator",
41686
+ capScope: "system",
41687
+ addonId: null,
41688
+ access: "create"
41689
+ },
41162
41690
  "pipelineOrchestrator.setPipelineDevicePin": {
41163
41691
  capName: "pipeline-orchestrator",
41164
41692
  capScope: "system",
41165
41693
  addonId: null,
41166
41694
  access: "create"
41167
41695
  },
41168
- "pipelineOrchestrator.unassignAudio": {
41696
+ "pipelineOrchestrator.setShareSource": {
41169
41697
  capName: "pipeline-orchestrator",
41170
41698
  capScope: "system",
41171
41699
  addonId: null,
41172
41700
  access: "create"
41173
41701
  },
41174
- "pipelineOrchestrator.unassignPipeline": {
41702
+ "pipelineOrchestrator.suggestShares": {
41703
+ capName: "pipeline-orchestrator",
41704
+ capScope: "system",
41705
+ addonId: null,
41706
+ access: "view"
41707
+ },
41708
+ "pipelineOrchestrator.unassignAudio": {
41175
41709
  capName: "pipeline-orchestrator",
41176
41710
  capScope: "system",
41177
41711
  addonId: null,
41178
41712
  access: "create"
41179
41713
  },
41180
- "pipelineOrchestrator.updateTemplate": {
41714
+ "pipelineOrchestrator.unassignPipeline": {
41181
41715
  capName: "pipeline-orchestrator",
41182
41716
  capScope: "system",
41183
41717
  addonId: null,
@@ -42617,12 +43151,6 @@ Object.freeze({
42617
43151
  addonId: null,
42618
43152
  access: "view"
42619
43153
  },
42620
- "streamBroker.pullFrameHandles": {
42621
- capName: "stream-broker",
42622
- capScope: "system",
42623
- addonId: null,
42624
- access: "view"
42625
- },
42626
43154
  "streamBroker.regenerateRtspToken": {
42627
43155
  capName: "stream-broker",
42628
43156
  capScope: "system",
@@ -42689,12 +43217,6 @@ Object.freeze({
42689
43217
  addonId: null,
42690
43218
  access: "create"
42691
43219
  },
42692
- "streamBroker.subscribeFrames": {
42693
- capName: "stream-broker",
42694
- capScope: "system",
42695
- addonId: null,
42696
- access: "create"
42697
- },
42698
43220
  "streamBroker.unassignProfile": {
42699
43221
  capName: "stream-broker",
42700
43222
  capScope: "system",
@@ -42707,12 +43229,6 @@ Object.freeze({
42707
43229
  addonId: null,
42708
43230
  access: "create"
42709
43231
  },
42710
- "streamBroker.unsubscribeFrames": {
42711
- capName: "stream-broker",
42712
- capScope: "system",
42713
- addonId: null,
42714
- access: "create"
42715
- },
42716
43232
  "streamCatalog.getCatalog": {
42717
43233
  capName: "stream-catalog",
42718
43234
  capScope: "device",
@@ -43409,6 +43925,12 @@ Object.freeze({
43409
43925
  addonId: null,
43410
43926
  access: "create"
43411
43927
  },
43928
+ "webrtcSession.applyDownlinkProbe": {
43929
+ capName: "webrtc-session",
43930
+ capScope: "device",
43931
+ addonId: null,
43932
+ access: "create"
43933
+ },
43412
43934
  "webrtcSession.closeSession": {
43413
43935
  capName: "webrtc-session",
43414
43936
  capScope: "device",
@@ -45220,11 +45742,6 @@ Object.freeze({
45220
45742
  form: "single",
45221
45743
  optional: false
45222
45744
  }],
45223
- "decoder.createSession": [{
45224
- name: "deviceId",
45225
- form: "single",
45226
- optional: true
45227
- }],
45228
45745
  "detectionPipeline.applyDeviceSettingsPatch": [{
45229
45746
  name: "deviceId",
45230
45747
  form: "single",
@@ -46455,6 +46972,11 @@ Object.freeze({
46455
46972
  form: "single",
46456
46973
  optional: false
46457
46974
  }],
46975
+ "pipelineExecutor.clearModelBoundDeviceOverrides": [{
46976
+ name: "deviceIds",
46977
+ form: "array",
46978
+ optional: true
46979
+ }],
46458
46980
  "pipelineExecutor.runPipeline": [{
46459
46981
  name: "deviceId",
46460
46982
  form: "single",
@@ -46560,6 +47082,11 @@ Object.freeze({
46560
47082
  form: "single",
46561
47083
  optional: false
46562
47084
  }],
47085
+ "pipelineOrchestrator.setCameraStepSettings": [{
47086
+ name: "deviceId",
47087
+ form: "single",
47088
+ optional: false
47089
+ }],
46563
47090
  "pipelineOrchestrator.setCameraStepToggle": [{
46564
47091
  name: "deviceId",
46565
47092
  form: "single",
@@ -47331,6 +47858,11 @@ Object.freeze({
47331
47858
  form: "single",
47332
47859
  optional: false
47333
47860
  }],
47861
+ "webrtcSession.applyDownlinkProbe": [{
47862
+ name: "deviceId",
47863
+ form: "single",
47864
+ optional: false
47865
+ }],
47334
47866
  "webrtcSession.closeSession": [{
47335
47867
  name: "deviceId",
47336
47868
  form: "single",
@@ -47560,6 +48092,8 @@ new Map(Object.entries({
47560
48092
  "detection-blind": "device-events",
47561
48093
  "node-online": "system",
47562
48094
  "node-offline": "system",
48095
+ "node-restarting": "system",
48096
+ "node-updating": "system",
47563
48097
  "node-inference-unavailable": "system",
47564
48098
  "addon-crash-loop": "system",
47565
48099
  "addon-update-available": "system",
@@ -47637,18 +48171,21 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
47637
48171
  kinds: [
47638
48172
  "node-offline",
47639
48173
  "node-online",
48174
+ "node-restarting",
47640
48175
  "node-inference-unavailable"
47641
48176
  ]
47642
48177
  },
47643
48178
  {
47644
48179
  id: "addons",
47645
48180
  family: "system",
47646
- label: "Addons",
47647
- kinds: [
47648
- "addon-crash-loop",
47649
- "addon-update-available",
47650
- "addon-updated"
47651
- ]
48181
+ label: "Addons stopped",
48182
+ kinds: ["addon-crash-loop"]
48183
+ },
48184
+ {
48185
+ id: "addon-updates",
48186
+ family: "system",
48187
+ label: "Addon updates",
48188
+ kinds: ["addon-update-available", "addon-updated"]
47652
48189
  },
47653
48190
  {
47654
48191
  id: "updates",
@@ -47656,6 +48193,7 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
47656
48193
  label: "Server & container updates",
47657
48194
  kinds: [
47658
48195
  "server-update-available",
48196
+ "node-updating",
47659
48197
  "server-updated",
47660
48198
  "wrapper-update-available"
47661
48199
  ]
@@ -47803,18 +48341,21 @@ var STATE_SUMMARY_SECTION_VARS = [
47803
48341
  kinds: [
47804
48342
  "node-offline",
47805
48343
  "node-online",
48344
+ "node-restarting",
47806
48345
  "node-inference-unavailable"
47807
48346
  ]
47808
48347
  },
47809
48348
  {
47810
48349
  name: "summaryAddons",
47811
- label: "Summary: addons",
47812
- example: "@camstack/addon-recorder 1.2.3 → 1.2.4",
47813
- kinds: [
47814
- "addon-crash-loop",
47815
- "addon-update-available",
47816
- "addon-updated"
47817
- ]
48350
+ label: "Summary: addons stopped",
48351
+ example: "hub — recorder stopped after repeated crashes",
48352
+ kinds: ["addon-crash-loop"]
48353
+ },
48354
+ {
48355
+ name: "summaryAddonUpdates",
48356
+ label: "Summary: addon updates",
48357
+ example: "hub:\n• @camstack/addon-recorder 1.2.3 → 1.2.4",
48358
+ kinds: ["addon-update-available", "addon-updated"]
47818
48359
  },
47819
48360
  {
47820
48361
  name: "summaryUpdates",
@@ -47822,6 +48363,7 @@ var STATE_SUMMARY_SECTION_VARS = [
47822
48363
  example: "server 1.2.377 → 1.2.378",
47823
48364
  kinds: [
47824
48365
  "server-update-available",
48366
+ "node-updating",
47825
48367
  "server-updated",
47826
48368
  "wrapper-update-available"
47827
48369
  ]
@@ -47854,7 +48396,7 @@ var STATE_SUMMARY_VARS = [
47854
48396
  {
47855
48397
  name: "summarySection",
47856
48398
  label: "Summary: this section",
47857
- description: "The section a per-section summary row is about (D698); on a summary sent as one message, every section it reports, comma-separated.",
48399
+ description: "The section a per-section summary row is about; on a summary sent as one message, every section it reports, comma-separated.",
47858
48400
  example: "Batterie scariche",
47859
48401
  group: "system",
47860
48402
  families: ["rule"],
@@ -47898,6 +48440,7 @@ var STATE_SUMMARY_VARS = [
47898
48440
  [...RULE_BODY_ONLY],
47899
48441
  [...RULE_TEXT],
47900
48442
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
48443
+ ([...RULE_TEXT], [...COMBINED_ALARM]),
47901
48444
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
47902
48445
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
47903
48446
  ([...RULE_TEXT], [...CONSUMABLE]),
@@ -47938,6 +48481,8 @@ var STATE_SUMMARY_VARS = [
47938
48481
  [...RULE_TEXT],
47939
48482
  [...RULE_TEXT],
47940
48483
  [...RULE_TEXT],
48484
+ [...RULE_TEXT],
48485
+ [...RULE_TEXT],
47941
48486
  ...STATE_SUMMARY_VARS
47942
48487
  ];
47943
48488
  new Set([
@@ -80776,6 +81321,8 @@ var DEFAULT_CONFIG = {
80776
81321
  embeddedClients: [],
80777
81322
  embeddedAcl: []
80778
81323
  };
81324
+ /** The section that edits `config.brokers`, the same store the broker cap lists. */
81325
+ var EXTERNAL_BROKERS_SECTION_ID = "mqtt-broker-external";
80779
81326
  var MqttBrokerAddon = class extends BaseAddon {
80780
81327
  embeddedRuntime = null;
80781
81328
  /** Per-entry onboard `aedes` runtimes, keyed by `ExternalBrokerEntry.id`. */
@@ -81558,10 +82105,26 @@ var MqttBrokerAddon = class extends BaseAddon {
81558
82105
  }
81559
82106
  });
81560
82107
  }
81561
- globalSettingsSchema() {
82108
+ /**
82109
+ * Under the unified `broker` cap (Connectivity → MQTT Broker) the external
82110
+ * brokers are the CONNECTIONS that page's own panel lists and edits through
82111
+ * `broker.list` / `add` / `setSettings`, all over `config.brokers`. Drawing
82112
+ * the editable array as well would put two "Add broker" editors for ONE
82113
+ * store on one page, so that scope leaves it out; the addon's full page (no
82114
+ * cap) keeps it.
82115
+ */
82116
+ globalSettingsSchema(cap) {
82117
+ const schema = this.fullSettingsSchema();
82118
+ if (cap !== brokerCapability.name) return schema;
82119
+ return {
82120
+ ...schema,
82121
+ sections: schema.sections.filter((s) => s.id !== EXTERNAL_BROKERS_SECTION_ID)
82122
+ };
82123
+ }
82124
+ fullSettingsSchema() {
81562
82125
  return this.schema({ sections: [
81563
82126
  {
81564
- id: "mqtt-broker-external",
82127
+ id: EXTERNAL_BROKERS_SECTION_ID,
81565
82128
  title: "External brokers",
81566
82129
  description: "Brokers running outside CamStack (mosquitto, EMQX, HiveMQ, cloud bridges, …). Passwords are encrypted at rest.",
81567
82130
  columns: 1,