@camstack/addon-model-studio 1.0.19 → 1.0.20

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.
@@ -4638,7 +4638,7 @@ function _instanceof(cls, params = {}) {
4638
4638
  return inst;
4639
4639
  }
4640
4640
  //#endregion
4641
- //#region ../types/dist/sleep-CZDdRBua.mjs
4641
+ //#region ../types/dist/sleep-DiQ8xW1M.mjs
4642
4642
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4643
4643
  EventCategory["SystemBoot"] = "system.boot";
4644
4644
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -4824,6 +4824,18 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
4824
4824
  */
4825
4825
  EventCategory["PipelineCameraUpdated"] = "pipeline.camera-updated";
4826
4826
  /**
4827
+ * The cluster camera-source OWNER changed (`clusterRoles.ingestNode`).
4828
+ * Emitted by addon-pipeline-orchestrator whenever it (re)derives node
4829
+ * capabilities — at boot, on agent online/offline, and on an ingest-node
4830
+ * flip. Carries the resolved `ownerNodeId`. The stream-broker consumes it to
4831
+ * keep its ingest-owner-gate decision current WITHOUT a per-`ensureBroker`
4832
+ * cross-process `getIngestOwner` query (push the authority's decision instead
4833
+ * of polling it on the hot path). Idempotent state — re-emitted on every
4834
+ * topology change, so a dropped event self-heals on the next one (plus the
4835
+ * broker's long backstop reconcile query).
4836
+ */
4837
+ EventCategory["PipelineIngestOwnerChanged"] = "pipeline.ingest-owner-changed";
4838
+ /**
4827
4839
  * Periodic snapshot of per-node pipeline-runner load
4828
4840
  * (`RunnerLocalLoad`). Emitted ~1Hz by every runner so UI dashboards
4829
4841
  * subscribe instead of polling `pipelineRunner.getLocalLoad`.
@@ -6903,6 +6915,36 @@ var ModelFormatsSchema = object({
6903
6915
  tflite: ModelFormatEntrySchema.optional(),
6904
6916
  pt: ModelFormatEntrySchema.optional()
6905
6917
  });
6918
+ /**
6919
+ * Variant-selector grouping axes. Shared by the full `ModelCatalogEntry` and by
6920
+ * the reduced `PipelineModelOption` returned in `pipeline.getSchema()` so the
6921
+ * grouped Family→Tier→Variant picker renders identically in the config UI and
6922
+ * in the pipeline/device steppers. The flat `id` stays the source of truth for
6923
+ * resolution/download/persistence; this is a presentation overlay resolved back
6924
+ * to an `id`.
6925
+ */
6926
+ var ModelVariantGroupSchema = object({
6927
+ /** Top-level family, e.g. `yolo26` (later `d-fine`, `rf-detr`). */
6928
+ family: string(),
6929
+ /** Size within the family, e.g. `n` | `s` | `m` | `l`. */
6930
+ tier: string(),
6931
+ /** Quantization axis. Omit ⇒ the fp32 base build. */
6932
+ precision: _enum(["fp32", "int8"]).optional(),
6933
+ /**
6934
+ * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
6935
+ * latency-optimized export (e.g. ReLU-activation variant) — the slot the
6936
+ * future performance variants plug into.
6937
+ */
6938
+ optimization: _enum(["standard", "fast"]).optional(),
6939
+ /**
6940
+ * Input-resolution axis (square input side, px). Omit ⇒ the family's native
6941
+ * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
6942
+ * cheap latency lever — especially on Apple ANE and the Intel N100 — at a
6943
+ * small-object accuracy cost. Mirrors the model's `inputSize` but lifted onto
6944
+ * the group so the selector can offer it as a variant axis.
6945
+ */
6946
+ resolution: number().int().positive().optional()
6947
+ });
6906
6948
  var ModelCatalogEntrySchema = object({
6907
6949
  id: string(),
6908
6950
  name: string(),
@@ -6932,7 +6974,43 @@ var ModelCatalogEntrySchema = object({
6932
6974
  * Auxiliary files required at runtime (labels JSON, charset dict, etc.).
6933
6975
  * Downloaded into the same modelsDir alongside the model file.
6934
6976
  */
6935
- extraFiles: array(ModelExtraFileSchema).readonly().optional()
6977
+ extraFiles: array(ModelExtraFileSchema).readonly().optional(),
6978
+ /**
6979
+ * LEGACY entry — retained in the catalog so a persisted operator selection
6980
+ * still RESOLVES (and can be re-activated), but hidden from the selectable
6981
+ * model list and excluded from the auto format-default pick. Set on the
6982
+ * superseded / consolidated models (older lineages, redundant fp16 IRs) so
6983
+ * the active lineup stays the coherent curated ladder without deleting a
6984
+ * model anyone may still be pinned to. `resolveModelForFormat` keeps honoring
6985
+ * an explicit legacy id that has a build for the node's format.
6986
+ */
6987
+ legacy: boolean().optional(),
6988
+ /**
6989
+ * Measured quality/latency metadata — populated from the benchmark addon on
6990
+ * the real node classes. Absent = not yet measured (most entries today; the
6991
+ * catalog historically carried only `sizeMB`, a poor cross-architecture
6992
+ * speed proxy). `p95LatencyMs` is keyed by node class (e.g. `n100`, `mac`).
6993
+ */
6994
+ metrics: object({
6995
+ map50: number().optional(),
6996
+ p95LatencyMs: record(string(), number()).optional()
6997
+ }).optional(),
6998
+ /**
6999
+ * SPDX-ish license id of the model weights (e.g. `AGPL-3.0` for Ultralytics
7000
+ * YOLO26, `GPL-3.0` for YOLOv9, `Apache-2.0` for D-FINE/RF-DETR). Matters for
7001
+ * the retraining addon and any future commercial distribution.
7002
+ */
7003
+ license: string().optional(),
7004
+ /**
7005
+ * Variant-selector grouping. The UI groups models by `family` + `tier` and
7006
+ * offers `precision` / `optimization` as variant axes WITHIN a tier — so all
7007
+ * of a family's sizes and quantizations collapse into one grouped picker
7008
+ * instead of a flat list of `yolo26s`, `yolo26s-int8`, … Absent ⇒ ungrouped
7009
+ * (legacy / custom models) — never shown in the grouped selector. The flat
7010
+ * `id` stays the source of truth for resolution/download/persistence; grouping
7011
+ * is a presentation overlay resolved back to an `id`.
7012
+ */
7013
+ group: ModelVariantGroupSchema.optional()
6936
7014
  });
6937
7015
  var ConvertTargetSchema = discriminatedUnion("format", [object({
6938
7016
  format: literal("openvino"),
@@ -6994,8 +7072,8 @@ var RecordingModeSchema = _enum([
6994
7072
  "onAudioThreshold"
6995
7073
  ]);
6996
7074
  /**
6997
- * First-class, authoritative per-camera storage mode — the netta choice the UI
6998
- * reads directly (never inferred from `rules`):
7075
+ * First-class, authoritative per-camera storage mode — the explicit choice the
7076
+ * UI reads directly (never inferred from `rules`):
6999
7077
  * - `off` — not recording.
7000
7078
  * - `events` — record only around triggers (motion / audio threshold),
7001
7079
  * with pre/post-buffer.
@@ -8673,26 +8751,13 @@ DeviceType.Light, method(object({
8673
8751
  percentage: number().min(0).max(100),
8674
8752
  lastChangedAt: number()
8675
8753
  });
8754
+ /** Stream delivery format. (Relocated from the retired `streaming-engine` cap.) */
8676
8755
  var StreamFormatSchema = _enum([
8677
8756
  "webrtc",
8678
8757
  "hls",
8679
8758
  "mjpeg",
8680
8759
  "rtsp"
8681
8760
  ]);
8682
- var StreamInfoSchema = object({
8683
- streamId: string(),
8684
- format: StreamFormatSchema,
8685
- url: string().nullable(),
8686
- active: boolean()
8687
- });
8688
- method(object({
8689
- streamId: string(),
8690
- sourceUrl: string(),
8691
- codec: string().optional()
8692
- }), _void(), { kind: "mutation" }), method(object({ streamId: string() }), _void(), { kind: "mutation" }), method(object({
8693
- streamId: string(),
8694
- format: StreamFormatSchema
8695
- }), string().nullable()), method(_void(), array(StreamInfoSchema));
8696
8761
  var RtspRestreamEntrySchema = object({
8697
8762
  brokerId: string(),
8698
8763
  url: string(),
@@ -9357,7 +9422,7 @@ var ConsumablesStatusSchema = object({
9357
9422
  })),
9358
9423
  lastChangedAt: number()
9359
9424
  });
9360
- DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, method(object({
9425
+ Object.values(DeviceType), method(object({
9361
9426
  deviceId: number().int().nonnegative(),
9362
9427
  key: string().min(1)
9363
9428
  }), _void(), {
@@ -10272,7 +10337,7 @@ var BoundingBoxSchema = object({
10272
10337
  w: number(),
10273
10338
  h: number()
10274
10339
  });
10275
- var SpatialDetectionSchema = object({
10340
+ object({
10276
10341
  class: string(),
10277
10342
  originalClass: string(),
10278
10343
  score: number(),
@@ -10407,7 +10472,6 @@ var PipelineDefaultStepSchema = lazy(() => object({
10407
10472
  enabled: boolean(),
10408
10473
  modelId: string(),
10409
10474
  children: array(PipelineDefaultStepSchema).readonly(),
10410
- engine: PipelineEngineChoiceSchema.optional(),
10411
10475
  group: string().optional(),
10412
10476
  settings: record(string(), unknown()).optional()
10413
10477
  }));
@@ -10432,7 +10496,9 @@ var PipelineModelOptionSchema = object({
10432
10496
  formats: record(string(), object({
10433
10497
  downloaded: boolean(),
10434
10498
  sizeMB: number()
10435
- }))
10499
+ })),
10500
+ group: ModelVariantGroupSchema.optional(),
10501
+ legacy: boolean().optional()
10436
10502
  });
10437
10503
  var ConfigFieldBridge = custom();
10438
10504
  var PipelineAddonSchemaSchema = object({
@@ -10462,11 +10528,6 @@ var PipelineSchemaSchema = object({
10462
10528
  selectedEngine: PipelineEngineChoiceSchema,
10463
10529
  slots: array(PipelineSlotSchemaSchema).readonly()
10464
10530
  });
10465
- var DetectorOutputSchema = object({
10466
- detections: array(SpatialDetectionSchema).readonly(),
10467
- inferenceMs: number(),
10468
- modelId: string()
10469
- });
10470
10531
  var EngineProvisioningSchema = object({
10471
10532
  runtimeId: _enum([
10472
10533
  "onnx",
@@ -10483,15 +10544,42 @@ var EngineProvisioningSchema = object({
10483
10544
  ]),
10484
10545
  progress: number().optional(),
10485
10546
  error: string().optional(),
10486
- nextRetryAt: number().optional()
10547
+ nextRetryAt: number().optional(),
10548
+ /**
10549
+ * Gate A (config-correctness gate at engine change): human-readable
10550
+ * config issues surfaced EAGERLY when the node's engine changes — model
10551
+ * substitutions ("chose X, running Y") and zero-build steps ("no model
10552
+ * has a <format> build"). Additive/optional: informational only, never
10553
+ * enforced here — `assertEngineReady` (readiness) still gates inference.
10554
+ * Absent/empty when the node-default tree resolves cleanly.
10555
+ */
10556
+ configIssues: array(string()).optional()
10487
10557
  });
10488
10558
  var PipelineStepInputSchema = lazy(() => object({
10489
10559
  addonId: string(),
10490
- modelId: string(),
10560
+ modelId: string().optional(),
10491
10561
  enabled: boolean().default(true),
10492
10562
  children: array(PipelineStepInputSchema).optional(),
10493
10563
  settings: record(string(), unknown()).optional()
10494
10564
  }));
10565
+ var ModelSubstitutionSchema = object({
10566
+ addonId: string(),
10567
+ chosen: string(),
10568
+ running: string(),
10569
+ format: string()
10570
+ });
10571
+ var PipelineValidationIssueSchema = object({
10572
+ addonId: string(),
10573
+ kind: _enum(["unknown-addon", "no-format-build"]),
10574
+ detail: string()
10575
+ });
10576
+ var PipelineValidationResultSchema = object({
10577
+ ok: boolean(),
10578
+ issues: array(PipelineValidationIssueSchema).readonly(),
10579
+ substitutions: array(ModelSubstitutionSchema).readonly(),
10580
+ /** The node's `currentEngine.format` this validation ran against. */
10581
+ format: string()
10582
+ });
10495
10583
  var ReferenceImageEntrySchema = object({
10496
10584
  filename: string(),
10497
10585
  stepIds: array(string()).readonly().optional()
@@ -10562,7 +10650,13 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
10562
10650
  })) }), object({ success: literal(true) }), {
10563
10651
  kind: "mutation",
10564
10652
  auth: "admin"
10565
- }), method(_void(), PipelineSchemaSchema), method(_void(), array(PipelineDefaultStepSchema).readonly().nullable()), method(_void(), PipelineConfigBridge), method(_void(), ConfigUISchemaBridge), method(_void(), array(PipelineTemplateSchema$1).readonly()), method(object({
10653
+ }), method(object({ nodeId: string() }), object({
10654
+ success: literal(true),
10655
+ clearedDevices: number()
10656
+ }), {
10657
+ kind: "mutation",
10658
+ auth: "admin"
10659
+ }), method(_void(), PipelineSchemaSchema), method(_void(), array(PipelineDefaultStepSchema).readonly().nullable()), method(_void(), PipelineConfigBridge), method(_void(), ConfigUISchemaBridge), method(object({ steps: array(PipelineStepInputSchema) }), PipelineValidationResultSchema), method(_void(), array(PipelineTemplateSchema$1).readonly()), method(object({
10566
10660
  name: string(),
10567
10661
  steps: array(PipelineTemplateStepSchema).readonly(),
10568
10662
  engine: PipelineEngineChoiceSchema
@@ -10579,10 +10673,6 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
10579
10673
  modelId: string(),
10580
10674
  format: ModelFormatSchema$1
10581
10675
  }), object({ success: literal(true) }), { kind: "mutation" }), method(object({
10582
- addonId: string(),
10583
- frame: FrameInputSchema,
10584
- config: record(string(), unknown()).optional()
10585
- }), DetectorOutputSchema), method(object({
10586
10676
  engine: PipelineEngineChoiceSchema.optional(),
10587
10677
  steps: array(PipelineStepInputSchema).min(1),
10588
10678
  frame: FrameInputSchema.optional(),
@@ -10822,6 +10912,13 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
10822
10912
  kind: literal("remote-restream"),
10823
10913
  /** The camera's source-owner node (slice 1: always the hub). */
10824
10914
  ownerNodeId: string(),
10915
+ /**
10916
+ * The owner's LAN-reachable host, resolved by the orchestrator from the
10917
+ * per-node `reachableHost` override (Cluster UI). When present the runner
10918
+ * dials THIS host for the owner's restream, in preference to the
10919
+ * `CAMSTACK_HUB_URL`-derived default. Absent → auto-detect fallback.
10920
+ */
10921
+ ownerReachableHost: string().optional(),
10825
10922
  /** Operator override for the owner host the runner dials. */
10826
10923
  hubHostnameOverride: string().optional()
10827
10924
  })]).describe("Per-camera frame-source mode for the runner (P2c)");
@@ -10830,13 +10927,11 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
10830
10927
  * specific runner instance via `attachCamera`. Carries everything the
10831
10928
  * runner needs to subscribe to the local broker and execute inference.
10832
10929
  *
10833
- * Stateless-pipeline model: the full pipeline content (`engine`, `steps`,
10834
- * optional `audio`) travels with the attach payload. The runner keeps it
10835
- * in RAM for the lifetime of the attach — on rebalance, edit, or
10836
- * restart the orchestrator re-sends the latest snapshot.
10837
- *
10838
- * `engine`/`steps`/`audio` are optional during the additive migration
10839
- * window; once orchestrator + UI are migrated they become required.
10930
+ * Stateless-pipeline model: the pipeline content (`steps`, optional
10931
+ * `audio`) travels with the attach payload. The runner keeps it in RAM
10932
+ * for the lifetime of the attach — on rebalance, edit, or restart the
10933
+ * orchestrator re-sends the latest snapshot. Engine is NOT carried: it is
10934
+ * node-local, resolved by the executing runner at dispatch time.
10840
10935
  */
10841
10936
  var RunnerCameraConfigSchema = object({
10842
10937
  deviceId: number(),
@@ -10887,14 +10982,11 @@ var RunnerCameraConfigSchema = object({
10887
10982
  */
10888
10983
  motionSources: MotionSourcesSchema.default(["analyzer"]),
10889
10984
  pipelineEnabled: boolean().default(true),
10890
- /** Engine choice for video steps (runtime+backend+format). */
10891
- engine: PipelineEngineChoiceSchema.optional(),
10892
10985
  /** Ordered tree of video steps. Absent → runner skips video detection. */
10893
10986
  steps: array(PipelineStepInputSchema).readonly().optional(),
10894
10987
  /** Audio classification branch. `enabled:false` disables, null skips. */
10895
10988
  audio: object({
10896
- engine: PipelineEngineChoiceSchema,
10897
- modelId: string(),
10989
+ modelId: string().optional(),
10898
10990
  enabled: boolean()
10899
10991
  }).nullable().optional(),
10900
10992
  /**
@@ -12275,7 +12367,9 @@ var AddonPageDeclarationSchema$1 = object({
12275
12367
  icon: string(),
12276
12368
  path: string(),
12277
12369
  remoteName: string(),
12278
- bundle: string()
12370
+ bundle: string(),
12371
+ section: string().optional(),
12372
+ sectionLabel: string().optional()
12279
12373
  });
12280
12374
  var AddonPageInfoSchema = object({
12281
12375
  addonId: string(),
@@ -12315,7 +12409,18 @@ var AddonPageDeclarationSchema = object({
12315
12409
  * the static-file route can compute an mtime-based cache-buster URL
12316
12410
  * without a separate filesystem stat.
12317
12411
  */
12318
- bundle: string()
12412
+ bundle: string(),
12413
+ /**
12414
+ * Sidebar section this page docks into. Well-known ids: `'detection'`,
12415
+ * `'cluster'`, `'administration'` — the page renders inside that group.
12416
+ * Any OTHER string creates (or joins) a custom section rendered after
12417
+ * the built-in groups; its label comes from `sectionLabel` (first
12418
+ * declaration wins), falling back to the id. Absent → the legacy
12419
+ * "Addon Pages" group.
12420
+ */
12421
+ section: string().optional(),
12422
+ /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
12423
+ sectionLabel: string().optional()
12319
12424
  });
12320
12425
  var addonPagesSourceCapability = {
12321
12426
  name: "addon-pages-source",
@@ -15159,11 +15264,11 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
15159
15264
  timestamp: number()
15160
15265
  });
15161
15266
  var CameraPipelineConfigSchema = object({
15162
- engine: PipelineEngineChoiceSchema,
15267
+ engine: PipelineEngineChoiceSchema.optional(),
15163
15268
  steps: array(PipelineStepInputSchema).readonly(),
15164
15269
  audio: object({
15165
- engine: PipelineEngineChoiceSchema,
15166
- modelId: string(),
15270
+ engine: PipelineEngineChoiceSchema.optional(),
15271
+ modelId: string().optional(),
15167
15272
  enabled: boolean(),
15168
15273
  settings: record(string(), unknown()).readonly().optional()
15169
15274
  }).nullable().optional()
@@ -15178,7 +15283,7 @@ var PipelineTemplateSchema = object({
15178
15283
  });
15179
15284
  var AgentAddonConfigSchema = object({
15180
15285
  enabled: boolean(),
15181
- modelId: string(),
15286
+ modelId: string().optional(),
15182
15287
  settings: record(string(), unknown()).readonly()
15183
15288
  });
15184
15289
  var AgentPipelineSettingsSchema = object({
@@ -15188,12 +15293,25 @@ var AgentPipelineSettingsSchema = object({
15188
15293
  detectWeight: number().positive().optional(),
15189
15294
  /** Node is eligible to run the detection pipeline (decode + inference). */
15190
15295
  detect: boolean().optional(),
15191
- /** Node is eligible to host decoder sessions. */
15296
+ /**
15297
+ * DEPRECATED AND IGNORED. Decode is always co-located with its frame
15298
+ * consumer, so decode eligibility IS detect eligibility. Kept optional in
15299
+ * the schema ONLY so persisted stores written before the removal still
15300
+ * parse — no code reads it and no write path emits it.
15301
+ */
15192
15302
  decode: boolean().optional(),
15193
15303
  /** Node is eligible to run audio-analyzer sessions. */
15194
15304
  audio: boolean().optional(),
15195
15305
  /** Node is eligible to be the ingest / source-owner (serve the restream). */
15196
- ingest: boolean().optional()
15306
+ ingest: boolean().optional(),
15307
+ /**
15308
+ * Operator override for the LAN host a cross-node decoder dials to reach
15309
+ * THIS node's restream (Cluster UI). Absent → auto-detect: a remote runner
15310
+ * falls back to its `CAMSTACK_HUB_URL`-derived host (the Moleculer address
15311
+ * it already uses to reach the hub). Set this only when the auto-detected
15312
+ * address is wrong (multi-homed host, NAT, custom interface).
15313
+ */
15314
+ reachableHost: string().optional()
15197
15315
  });
15198
15316
  var CameraPipelineForAgentSchema = object({
15199
15317
  steps: array(PipelineStepInputSchema).readonly(),
@@ -15241,25 +15359,6 @@ var PipelineAssignmentSchema = object({
15241
15359
  assignedAt: number()
15242
15360
  });
15243
15361
  /**
15244
- * Decoder placement record. Symmetric to `PipelineAssignmentSchema` but for
15245
- * the decoder-node placement domain (`balanceDecoder` decision: manual pin
15246
- * → co-located with pipeline → capacity).
15247
- */
15248
- var DecoderAssignmentSchema = object({
15249
- deviceId: number(),
15250
- /** Moleculer node id of the decoder provider currently responsible for this camera. */
15251
- decoderNodeId: string(),
15252
- /** True when the assignment was set manually via `assignDecoder`, false when chosen by the balancer. */
15253
- pinned: boolean(),
15254
- /** Why this assignment was made — useful for debugging the decoder balancer. */
15255
- reason: _enum([
15256
- "manual",
15257
- "co-located",
15258
- "capacity",
15259
- "hardware-affinity"
15260
- ])
15261
- });
15262
- /**
15263
15362
  * Per-agent load summary surfaced to the load balancer + dashboards.
15264
15363
  * Aggregated from each runner's `getLocalLoad` cap call.
15265
15364
  */
@@ -15299,6 +15398,15 @@ var GlobalMetricsSchema = object({
15299
15398
  * capability providers.
15300
15399
  */
15301
15400
  var CapabilityBindingsSchema = record(string(), string());
15401
+ /**
15402
+ * The cluster's single camera-source owner (`clusterRoles.ingestNode`) plus
15403
+ * its LAN-reachable host, if one is registered. See `getIngestOwner`.
15404
+ */
15405
+ var IngestOwnerSchema = object({
15406
+ ownerNodeId: string(),
15407
+ reachableHost: string().optional(),
15408
+ configIssue: string().optional()
15409
+ });
15302
15410
  /** Source block — always present; derives from the stream catalog. */
15303
15411
  var CameraSourceStatusSchema = object({ streams: array(object({
15304
15412
  camStreamId: string(),
@@ -15313,6 +15421,14 @@ var CameraAssignmentStatusSchema = object({
15313
15421
  detectionNodeId: string().nullable(),
15314
15422
  decoderNodeId: string().nullable(),
15315
15423
  audioNodeId: string().nullable(),
15424
+ /**
15425
+ * The node that OWNS this camera's physical source pull (dials the RTSP and
15426
+ * hosts the broker/restream) — the cluster ingest owner today
15427
+ * (`clusterRoles.ingestNode`), per-camera once source assignment lands. Lets
15428
+ * the UI show WHERE a camera is sourced without SSH/logs, and is the node the
15429
+ * broker block below was read from (pinned). Nullable only pre-wiring.
15430
+ */
15431
+ sourceNodeId: string().nullable(),
15316
15432
  pinned: object({
15317
15433
  detection: boolean(),
15318
15434
  decoder: boolean(),
@@ -15445,16 +15561,7 @@ method(object({
15445
15561
  }), object({ success: literal(true) }), {
15446
15562
  kind: "mutation",
15447
15563
  auth: "admin"
15448
- }), method(object({
15449
- deviceId: number(),
15450
- nodeId: string()
15451
- }), _void(), {
15452
- kind: "mutation",
15453
- auth: "admin"
15454
- }), method(object({ deviceId: number() }), _void(), {
15455
- kind: "mutation",
15456
- auth: "admin"
15457
- }), method(_void(), array(DecoderAssignmentSchema).readonly()), method(object({
15564
+ }), method(_void(), IngestOwnerSchema), method(object({
15458
15565
  deviceId: number(),
15459
15566
  nodeId: string()
15460
15567
  }), object({ success: literal(true) }), {
@@ -15475,10 +15582,7 @@ method(object({
15475
15582
  nodeId: string(),
15476
15583
  pinned: boolean(),
15477
15584
  assignedAt: number()
15478
- }))), method(object({
15479
- deviceId: number(),
15480
- pipelineNodeId: string().optional()
15481
- }), DecoderAssignmentSchema), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
15585
+ }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
15482
15586
  nodeId: string(),
15483
15587
  settings: AgentPipelineSettingsSchema
15484
15588
  })).readonly()), method(object({
@@ -15508,12 +15612,26 @@ method(object({
15508
15612
  }), method(object({
15509
15613
  agentNodeId: string(),
15510
15614
  detect: boolean().nullable().optional(),
15511
- decode: boolean().nullable().optional(),
15512
15615
  audio: boolean().nullable().optional(),
15513
15616
  ingest: boolean().nullable().optional()
15514
15617
  }), object({ success: literal(true) }), {
15515
15618
  kind: "mutation",
15516
15619
  auth: "admin"
15620
+ }), method(object({
15621
+ agentNodeId: string(),
15622
+ reachableHost: string().nullable()
15623
+ }), object({ success: literal(true) }), {
15624
+ kind: "mutation",
15625
+ auth: "admin"
15626
+ }), method(object({ agentNodeId: string() }), object({
15627
+ success: literal(true),
15628
+ /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
15629
+ effectiveModelId: string().nullable(),
15630
+ /** Number of cameras whose node-scoped overrides were cleared. */
15631
+ clearedCameraOverrides: number()
15632
+ }), {
15633
+ kind: "mutation",
15634
+ auth: "admin"
15517
15635
  }), method(object({ deviceId: number() }), CameraPipelineSettingsSchema.nullable()), method(object({
15518
15636
  deviceId: number(),
15519
15637
  addonId: string(),
@@ -15558,22 +15676,6 @@ method(object({
15558
15676
  kind: "mutation",
15559
15677
  auth: "admin"
15560
15678
  });
15561
- var RegisteredStreamSchema = object({
15562
- streamId: string(),
15563
- label: string().optional(),
15564
- codec: string(),
15565
- type: _enum(["video", "audio"]),
15566
- sourceUrl: string()
15567
- });
15568
- var ExposedResourceSchema = object({
15569
- streamId: string(),
15570
- format: string(),
15571
- value: string()
15572
- });
15573
- method(object({
15574
- deviceId: number(),
15575
- streams: array(RegisteredStreamSchema).readonly()
15576
- }), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), array(ExposedResourceSchema).readonly());
15577
15679
  /**
15578
15680
  * Query filter for settings-store collections.
15579
15681
  */
@@ -15726,9 +15828,9 @@ method(SendEmailInputSchema, SendEmailResultSchema, {
15726
15828
  /**
15727
15829
  * A single device snapshot returned as base64 JPEG/PNG.
15728
15830
  *
15729
- * Shared with the `snapshot-provider` collection cap the orchestrator
15730
- * receives the same shape from each native provider and from the
15731
- * broker-based fallback.
15831
+ * The `SnapshotAddon` wrapper returns this shape whether the frame came from
15832
+ * the device-native provider (onboard capture) or from the stream-broker
15833
+ * prebuffer fallback.
15732
15834
  */
15733
15835
  var SnapshotImageSchema = object({
15734
15836
  base64: string(),
@@ -15760,10 +15862,6 @@ DeviceType.Camera, method(object({
15760
15862
  kind: "mutation",
15761
15863
  auth: "admin"
15762
15864
  });
15763
- method(object({ deviceId: number() }), boolean()), method(object({
15764
- deviceId: number(),
15765
- streamId: string().optional()
15766
- }), SnapshotImageSchema.nullable());
15767
15865
  /**
15768
15866
  * `sso-bridge` — internal hub-only cap that lets SSO-style auth
15769
15867
  * providers (OIDC, SAML, magic-link, …) mint an HMAC-signed token
@@ -16124,9 +16222,10 @@ method(object({
16124
16222
  auth: "admin"
16125
16223
  });
16126
16224
  /**
16127
- * Optional client-side hints sent at session creation to help the
16128
- * provider pick the best native source. All fields are optional —
16129
- * a viewer that knows nothing still gets a sane default.
16225
+ * Optional client-side hints sent at session creation to help the provider
16226
+ * pick the best native source. All fields optional — a viewer that knows
16227
+ * nothing still gets a sane default. (Relocated from the retired `webrtc`
16228
+ * collection cap; this `webrtc-session` cap is the live signaling surface.)
16130
16229
  */
16131
16230
  var webrtcClientHintsSchema = object({
16132
16231
  viewportWidth: number().int().positive().optional(),
@@ -16137,22 +16236,6 @@ var webrtcClientHintsSchema = object({
16137
16236
  /** Hard tier override; takes precedence over scoring when registered. */
16138
16237
  prefersTier: string().optional()
16139
16238
  }).partial();
16140
- method(object({
16141
- streamId: string(),
16142
- sdpOffer: string()
16143
- }), string(), { kind: "mutation" }), method(object({ streamId: string() }), boolean()), method(object({
16144
- streamId: string(),
16145
- codec: string()
16146
- }), _void(), { kind: "mutation" }), method(object({ streamId: string() }), _void(), { kind: "mutation" }), method(object({
16147
- streamId: string(),
16148
- hints: webrtcClientHintsSchema.optional()
16149
- }), object({
16150
- sessionId: string(),
16151
- sdpOffer: string()
16152
- }), { kind: "mutation" }), method(object({
16153
- sessionId: string(),
16154
- sdpAnswer: string()
16155
- }), _void(), { kind: "mutation" }), method(object({ sessionId: string() }), _void(), { kind: "mutation" }), method(object({ streamId: string() }), boolean());
16156
16239
  /**
16157
16240
  * Discriminated target for a WebRTC session. The client sends this
16158
16241
  * structured object instead of building / parsing brokerId strings;
@@ -21033,23 +21116,23 @@ Object.freeze({
21033
21116
  addonId: null,
21034
21117
  access: "create"
21035
21118
  },
21036
- "pipelineExecutor.deleteModel": {
21119
+ "pipelineExecutor.clearDeviceOverrides": {
21037
21120
  capName: "pipeline-executor",
21038
21121
  capScope: "system",
21039
21122
  addonId: null,
21040
21123
  access: "delete"
21041
21124
  },
21042
- "pipelineExecutor.deleteTemplate": {
21125
+ "pipelineExecutor.deleteModel": {
21043
21126
  capName: "pipeline-executor",
21044
21127
  capScope: "system",
21045
21128
  addonId: null,
21046
21129
  access: "delete"
21047
21130
  },
21048
- "pipelineExecutor.detect": {
21131
+ "pipelineExecutor.deleteTemplate": {
21049
21132
  capName: "pipeline-executor",
21050
21133
  capScope: "system",
21051
21134
  addonId: null,
21052
- access: "view"
21135
+ access: "delete"
21053
21136
  },
21054
21137
  "pipelineExecutor.downloadModel": {
21055
21138
  capName: "pipeline-executor",
@@ -21243,13 +21326,13 @@ Object.freeze({
21243
21326
  addonId: null,
21244
21327
  access: "create"
21245
21328
  },
21246
- "pipelineOrchestrator.assignAudio": {
21247
- capName: "pipeline-orchestrator",
21329
+ "pipelineExecutor.validatePipeline": {
21330
+ capName: "pipeline-executor",
21248
21331
  capScope: "system",
21249
21332
  addonId: null,
21250
- access: "create"
21333
+ access: "view"
21251
21334
  },
21252
- "pipelineOrchestrator.assignDecoder": {
21335
+ "pipelineOrchestrator.assignAudio": {
21253
21336
  capName: "pipeline-orchestrator",
21254
21337
  capScope: "system",
21255
21338
  addonId: null,
@@ -21333,19 +21416,13 @@ Object.freeze({
21333
21416
  addonId: null,
21334
21417
  access: "view"
21335
21418
  },
21336
- "pipelineOrchestrator.getDecoderAssignment": {
21419
+ "pipelineOrchestrator.getGlobalMetrics": {
21337
21420
  capName: "pipeline-orchestrator",
21338
21421
  capScope: "system",
21339
21422
  addonId: null,
21340
21423
  access: "view"
21341
21424
  },
21342
- "pipelineOrchestrator.getDecoderAssignments": {
21343
- capName: "pipeline-orchestrator",
21344
- capScope: "system",
21345
- addonId: null,
21346
- access: "view"
21347
- },
21348
- "pipelineOrchestrator.getGlobalMetrics": {
21425
+ "pipelineOrchestrator.getIngestOwner": {
21349
21426
  capName: "pipeline-orchestrator",
21350
21427
  capScope: "system",
21351
21428
  addonId: null,
@@ -21387,6 +21464,12 @@ Object.freeze({
21387
21464
  addonId: null,
21388
21465
  access: "delete"
21389
21466
  },
21467
+ "pipelineOrchestrator.resetNodePipelineDefaults": {
21468
+ capName: "pipeline-orchestrator",
21469
+ capScope: "system",
21470
+ addonId: null,
21471
+ access: "delete"
21472
+ },
21390
21473
  "pipelineOrchestrator.resolvePipeline": {
21391
21474
  capName: "pipeline-orchestrator",
21392
21475
  capScope: "system",
@@ -21423,37 +21506,37 @@ Object.freeze({
21423
21506
  addonId: null,
21424
21507
  access: "create"
21425
21508
  },
21426
- "pipelineOrchestrator.setCameraPipelineForAgent": {
21509
+ "pipelineOrchestrator.setAgentReachableHost": {
21427
21510
  capName: "pipeline-orchestrator",
21428
21511
  capScope: "system",
21429
21512
  addonId: null,
21430
21513
  access: "create"
21431
21514
  },
21432
- "pipelineOrchestrator.setCameraStepOverride": {
21515
+ "pipelineOrchestrator.setCameraPipelineForAgent": {
21433
21516
  capName: "pipeline-orchestrator",
21434
21517
  capScope: "system",
21435
21518
  addonId: null,
21436
21519
  access: "create"
21437
21520
  },
21438
- "pipelineOrchestrator.setCameraStepToggle": {
21521
+ "pipelineOrchestrator.setCameraStepOverride": {
21439
21522
  capName: "pipeline-orchestrator",
21440
21523
  capScope: "system",
21441
21524
  addonId: null,
21442
21525
  access: "create"
21443
21526
  },
21444
- "pipelineOrchestrator.setCapabilityBinding": {
21527
+ "pipelineOrchestrator.setCameraStepToggle": {
21445
21528
  capName: "pipeline-orchestrator",
21446
21529
  capScope: "system",
21447
21530
  addonId: null,
21448
21531
  access: "create"
21449
21532
  },
21450
- "pipelineOrchestrator.unassignAudio": {
21533
+ "pipelineOrchestrator.setCapabilityBinding": {
21451
21534
  capName: "pipeline-orchestrator",
21452
21535
  capScope: "system",
21453
21536
  addonId: null,
21454
21537
  access: "create"
21455
21538
  },
21456
- "pipelineOrchestrator.unassignDecoder": {
21539
+ "pipelineOrchestrator.unassignAudio": {
21457
21540
  capName: "pipeline-orchestrator",
21458
21541
  capScope: "system",
21459
21542
  addonId: null,
@@ -21753,24 +21836,6 @@ Object.freeze({
21753
21836
  addonId: null,
21754
21837
  access: "create"
21755
21838
  },
21756
- "restreamer.getExposedResources": {
21757
- capName: "restreamer",
21758
- capScope: "system",
21759
- addonId: null,
21760
- access: "view"
21761
- },
21762
- "restreamer.registerDevice": {
21763
- capName: "restreamer",
21764
- capScope: "system",
21765
- addonId: null,
21766
- access: "create"
21767
- },
21768
- "restreamer.unregisterDevice": {
21769
- capName: "restreamer",
21770
- capScope: "system",
21771
- addonId: null,
21772
- access: "delete"
21773
- },
21774
21839
  "scriptRunner.run": {
21775
21840
  capName: "script-runner",
21776
21841
  capScope: "device",
@@ -21873,18 +21938,6 @@ Object.freeze({
21873
21938
  addonId: null,
21874
21939
  access: "create"
21875
21940
  },
21876
- "snapshotProvider.getSnapshot": {
21877
- capName: "snapshot-provider",
21878
- capScope: "system",
21879
- addonId: null,
21880
- access: "view"
21881
- },
21882
- "snapshotProvider.supportsDevice": {
21883
- capName: "snapshot-provider",
21884
- capScope: "system",
21885
- addonId: null,
21886
- access: "view"
21887
- },
21888
21941
  "ssoBridge.signBridgeToken": {
21889
21942
  capName: "sso-bridge",
21890
21943
  capScope: "system",
@@ -22311,30 +22364,6 @@ Object.freeze({
22311
22364
  addonId: null,
22312
22365
  access: "view"
22313
22366
  },
22314
- "streamingEngine.getStreamUrl": {
22315
- capName: "streaming-engine",
22316
- capScope: "system",
22317
- addonId: null,
22318
- access: "view"
22319
- },
22320
- "streamingEngine.listStreams": {
22321
- capName: "streaming-engine",
22322
- capScope: "system",
22323
- addonId: null,
22324
- access: "view"
22325
- },
22326
- "streamingEngine.registerStream": {
22327
- capName: "streaming-engine",
22328
- capScope: "system",
22329
- addonId: null,
22330
- access: "create"
22331
- },
22332
- "streamingEngine.unregisterStream": {
22333
- capName: "streaming-engine",
22334
- capScope: "system",
22335
- addonId: null,
22336
- access: "delete"
22337
- },
22338
22367
  "streamParams.getConfigSchema": {
22339
22368
  capName: "stream-params",
22340
22369
  capScope: "device",
@@ -22701,54 +22730,6 @@ Object.freeze({
22701
22730
  addonId: null,
22702
22731
  access: "create"
22703
22732
  },
22704
- "webrtc.closeSession": {
22705
- capName: "webrtc",
22706
- capScope: "system",
22707
- addonId: null,
22708
- access: "create"
22709
- },
22710
- "webrtc.createSession": {
22711
- capName: "webrtc",
22712
- capScope: "system",
22713
- addonId: null,
22714
- access: "create"
22715
- },
22716
- "webrtc.handleAnswer": {
22717
- capName: "webrtc",
22718
- capScope: "system",
22719
- addonId: null,
22720
- access: "create"
22721
- },
22722
- "webrtc.handleOffer": {
22723
- capName: "webrtc",
22724
- capScope: "system",
22725
- addonId: null,
22726
- access: "create"
22727
- },
22728
- "webrtc.hasAdaptiveBitrate": {
22729
- capName: "webrtc",
22730
- capScope: "system",
22731
- addonId: null,
22732
- access: "view"
22733
- },
22734
- "webrtc.registerStream": {
22735
- capName: "webrtc",
22736
- capScope: "system",
22737
- addonId: null,
22738
- access: "create"
22739
- },
22740
- "webrtc.supportsStream": {
22741
- capName: "webrtc",
22742
- capScope: "system",
22743
- addonId: null,
22744
- access: "view"
22745
- },
22746
- "webrtc.unregisterStream": {
22747
- capName: "webrtc",
22748
- capScope: "system",
22749
- addonId: null,
22750
- access: "delete"
22751
- },
22752
22733
  "webrtcSession.addIceCandidate": {
22753
22734
  capName: "webrtc-session",
22754
22735
  capScope: "device",
@@ -23262,7 +23243,8 @@ var ModelStudioAddon = class extends BaseAddon {
23262
23243
  icon: "boxes",
23263
23244
  path: "/addon/model-studio",
23264
23245
  remoteName: "addon_model_studio_page",
23265
- bundle: "remoteEntry.js"
23246
+ bundle: "remoteEntry.js",
23247
+ section: "detection"
23266
23248
  }];
23267
23249
  constructor() {
23268
23250
  super({});