@camstack/addon-admin-ui 1.1.34 → 1.1.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/assets/{AddLocationWizard-Bi0ljsVA.js → AddLocationWizard-fU39g28j.js} +1 -1
  2. package/dist/assets/{AddonCollectionPage-DBF9Z9As.js → AddonCollectionPage-2R4sBcnH.js} +1 -1
  3. package/dist/assets/{Addons-B-__KXJU.js → Addons-OPXB9gcH.js} +1 -1
  4. package/dist/assets/{AdminTabs-BuqsvGrG.js → AdminTabs-DZ8fjA_E.js} +1 -1
  5. package/dist/assets/{BrokerForm-_89nTW-H.js → BrokerForm-DxBh4Ab_.js} +1 -1
  6. package/dist/assets/{Capabilities-ClcXLZXO.js → Capabilities-BowvKc7g.js} +1 -1
  7. package/dist/assets/{CapabilityBadges-D17MpdW-.js → CapabilityBadges-Cb2taM1G.js} +1 -1
  8. package/dist/assets/{Cluster-Duon566q.js → Cluster-Dvu3Qmr3.js} +1 -1
  9. package/dist/assets/{Dashboard-DRCyjJak.js → Dashboard-DwJvs0Hh.js} +1 -1
  10. package/dist/assets/{Data-CeLbKmt6.js → Data-zUHS7p4f.js} +1 -1
  11. package/dist/assets/{DetectionIntelligence-Co-3EN_y.js → DetectionIntelligence-BneZGPL8.js} +1 -1
  12. package/dist/assets/DeviceDetail-D55afT28.js +2 -0
  13. package/dist/assets/{Devices-DanUITRF.js → Devices-BPv3cLJV.js} +1 -1
  14. package/dist/assets/{EmbedPlayerPage-g2S5bdPi.js → EmbedPlayerPage-B-sPclrx.js} +1 -1
  15. package/dist/assets/{FormBuilder-BKE262Ak.js → FormBuilder-BHrYFTqO.js} +1 -1
  16. package/dist/assets/{Identity-CzZXW3_y.js → Identity-4N-nfSAK.js} +1 -1
  17. package/dist/assets/{IntegrationDetail-Cd9xdRi_.js → IntegrationDetail-CASAMzWi.js} +1 -1
  18. package/dist/assets/{Integrations-D3majjXx.js → Integrations-BK8yyBnE.js} +1 -1
  19. package/dist/assets/{Integrations-B4fhe1Gb.js → Integrations-CFNCpTGQ.js} +1 -1
  20. package/dist/assets/{Logs-CgKEHupO.js → Logs-B1uh5BYK.js} +1 -1
  21. package/dist/assets/{MotionZonesSettings-A8_xE3RR.js → MotionZonesSettings-3tt6mBQ0.js} +1 -1
  22. package/dist/assets/{MyAccess-CQ4EIWqU.js → MyAccess-Brl1MiDm.js} +1 -1
  23. package/dist/assets/{Network-BajDLc8U.js → Network-CcZYSjnr.js} +1 -1
  24. package/dist/assets/{NodeAddonsSettingsPanel-G-afOE2k.js → NodeAddonsSettingsPanel-DTTq6Ljf.js} +1 -1
  25. package/dist/assets/{NotificationTargets-DQmAITEb.js → NotificationTargets-Bji4H-RC.js} +1 -1
  26. package/dist/assets/Pipeline-Bj4liIat.js +1 -0
  27. package/dist/assets/{PrivacyMaskSettings-D-Yfij0p.js → PrivacyMaskSettings-CKAT3JFX.js} +1 -1
  28. package/dist/assets/{ProviderIcon-D2GVIM6D.js → ProviderIcon-KQShdlru.js} +1 -1
  29. package/dist/assets/{ScanNetworkModal-CXe1ZhrW.js → ScanNetworkModal-mQF_it2k.js} +1 -1
  30. package/dist/assets/{Settings-duX068YK.js → Settings-Bq1sSX7Z.js} +1 -1
  31. package/dist/assets/{Showroom-tEsQLYvU.js → Showroom-inuhv53W.js} +1 -1
  32. package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-DpZ6S4A1.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-BAi3eQvB.js} +1 -1
  33. package/dist/assets/{build-cluster-graph-DEgurNYu.js → build-cluster-graph-DlOB4sV_.js} +1 -1
  34. package/dist/assets/circle-check-big-Bcoiv1yk.js +1 -0
  35. package/dist/assets/{copy-BZEouQxh.js → copy-C3o1fFh1.js} +1 -1
  36. package/dist/assets/{dist-B5BcBM_J.js → dist-B8dNOlY9.js} +1 -1
  37. package/dist/assets/dist-DRenWL4F.js +7 -0
  38. package/dist/assets/{download-BdD4jpmM.js → download-D2Hdt3_T.js} +1 -1
  39. package/dist/assets/{hostInit-DL0Pq8FG.js → hostInit-BKnQjzgs.js} +1 -1
  40. package/dist/assets/index-CpCNvkGK.js +4 -0
  41. package/dist/assets/index-DO0772OA.css +2 -0
  42. package/dist/assets/{key-round-Co1IZCyf.js → key-round-Jz1W_Dm_.js} +1 -1
  43. package/dist/assets/{mf-entry-bootstrap-0-9f7f6a36.js → mf-entry-bootstrap-0-b853eab9.js} +2 -2
  44. package/dist/assets/{pencil-Ctcgfyao.js → pencil-CFG04wDY.js} +1 -1
  45. package/dist/assets/{player-overlays-D_uAA1FM.js → player-overlays-CpsGl45o.js} +1 -1
  46. package/dist/assets/plus-Bc_u_j_c.js +1 -0
  47. package/dist/assets/{radio-COzWf8RL.js → radio-Bvao3n8m.js} +1 -1
  48. package/dist/assets/{refresh-cw-DPd788Ly.js → refresh-cw-B3eKxMWT.js} +1 -1
  49. package/dist/assets/remoteEntry-xYIBqMy5.js +1 -0
  50. package/dist/assets/{rotate-ccw-D4xWcHzx.js → rotate-ccw-g29vnwke.js} +1 -1
  51. package/dist/assets/rotate-cw-B3yeEqVR.js +1 -0
  52. package/dist/assets/search-ChyM3D_C.js +1 -0
  53. package/dist/assets/{server-DCZCFjSL.js → server-BrIBBG6H.js} +1 -1
  54. package/dist/assets/{sparkles-DL5wzv3h.js → sparkles-ARuuvyj1.js} +1 -1
  55. package/dist/assets/square-BM303wp_.js +1 -0
  56. package/dist/assets/{square-check-big-DXqD6BOi.js → square-check-big-piMyzaVk.js} +1 -1
  57. package/dist/assets/src-BXL7z3gT.js +7 -0
  58. package/dist/assets/src-Dp6qXTLR.js +67 -0
  59. package/dist/assets/{upload-CnDk7r-2.js → upload-CZGhOSU5.js} +1 -1
  60. package/dist/assets/{useDevice-CSvcJkG5.js → useDevice-D09Wge-X.js} +1 -1
  61. package/dist/assets/{useEventInvalidation-D85JeECP.js → useEventInvalidation-NEk-4cPL.js} +1 -1
  62. package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-wsjHIjiy.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-rJ2O9jZ3.js} +2 -2
  63. package/dist/assets/{wifi-DZtU-62o.js → wifi-CyY3elJf.js} +1 -1
  64. package/dist/assets/{zap-C4RnkQsi.js → zap-l_Zh2jBY.js} +1 -1
  65. package/dist/index.html +6 -6
  66. package/dist/server/addon.js +205 -186
  67. package/package.json +1 -1
  68. package/dist/assets/DeviceDetail-BbrCW8vA.js +0 -2
  69. package/dist/assets/Pipeline-CzR4gmRW.js +0 -1
  70. package/dist/assets/circle-check-big-djmpxb6e.js +0 -1
  71. package/dist/assets/dist-BEwW84yT.js +0 -7
  72. package/dist/assets/index-2HwvWrOH.css +0 -2
  73. package/dist/assets/index-BGSe7zm2.js +0 -4
  74. package/dist/assets/plus-BPews3hd.js +0 -1
  75. package/dist/assets/remoteEntry-DUPeCPoh.js +0 -1
  76. package/dist/assets/rotate-cw-DXeseGvV.js +0 -1
  77. package/dist/assets/search-D3qB3OId.js +0 -1
  78. package/dist/assets/square-DaYEm0Ao.js +0 -1
  79. package/dist/assets/src-CSLY6BPe.js +0 -67
  80. package/dist/assets/src-DkLajgHy.js +0 -7
@@ -4629,7 +4629,7 @@ function _instanceof(cls, params = {}) {
4629
4629
  return inst;
4630
4630
  }
4631
4631
  //#endregion
4632
- //#region ../types/dist/sleep-CZDdRBua.mjs
4632
+ //#region ../types/dist/sleep-Cc14_yxc.mjs
4633
4633
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4634
4634
  EventCategory["SystemBoot"] = "system.boot";
4635
4635
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -4815,6 +4815,18 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
4815
4815
  */
4816
4816
  EventCategory["PipelineCameraUpdated"] = "pipeline.camera-updated";
4817
4817
  /**
4818
+ * The cluster camera-source OWNER changed (`clusterRoles.ingestNode`).
4819
+ * Emitted by addon-pipeline-orchestrator whenever it (re)derives node
4820
+ * capabilities — at boot, on agent online/offline, and on an ingest-node
4821
+ * flip. Carries the resolved `ownerNodeId`. The stream-broker consumes it to
4822
+ * keep its ingest-owner-gate decision current WITHOUT a per-`ensureBroker`
4823
+ * cross-process `getIngestOwner` query (push the authority's decision instead
4824
+ * of polling it on the hot path). Idempotent state — re-emitted on every
4825
+ * topology change, so a dropped event self-heals on the next one (plus the
4826
+ * broker's long backstop reconcile query).
4827
+ */
4828
+ EventCategory["PipelineIngestOwnerChanged"] = "pipeline.ingest-owner-changed";
4829
+ /**
4818
4830
  * Periodic snapshot of per-node pipeline-runner load
4819
4831
  * (`RunnerLocalLoad`). Emitted ~1Hz by every runner so UI dashboards
4820
4832
  * 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"),
@@ -6993,8 +7071,8 @@ var RecordingModeSchema = _enum([
6993
7071
  "onAudioThreshold"
6994
7072
  ]);
6995
7073
  /**
6996
- * First-class, authoritative per-camera storage mode — the netta choice the UI
6997
- * reads directly (never inferred from `rules`):
7074
+ * First-class, authoritative per-camera storage mode — the explicit choice the
7075
+ * UI reads directly (never inferred from `rules`):
6998
7076
  * - `off` — not recording.
6999
7077
  * - `events` — record only around triggers (motion / audio threshold),
7000
7078
  * with pre/post-buffer.
@@ -8642,26 +8720,13 @@ DeviceType.Light, method(object({
8642
8720
  percentage: number().min(0).max(100),
8643
8721
  lastChangedAt: number()
8644
8722
  });
8723
+ /** Stream delivery format. (Relocated from the retired `streaming-engine` cap.) */
8645
8724
  var StreamFormatSchema = _enum([
8646
8725
  "webrtc",
8647
8726
  "hls",
8648
8727
  "mjpeg",
8649
8728
  "rtsp"
8650
8729
  ]);
8651
- var StreamInfoSchema = object({
8652
- streamId: string(),
8653
- format: StreamFormatSchema,
8654
- url: string().nullable(),
8655
- active: boolean()
8656
- });
8657
- method(object({
8658
- streamId: string(),
8659
- sourceUrl: string(),
8660
- codec: string().optional()
8661
- }), _void(), { kind: "mutation" }), method(object({ streamId: string() }), _void(), { kind: "mutation" }), method(object({
8662
- streamId: string(),
8663
- format: StreamFormatSchema
8664
- }), string().nullable()), method(_void(), array(StreamInfoSchema));
8665
8730
  var RtspRestreamEntrySchema = object({
8666
8731
  brokerId: string(),
8667
8732
  url: string(),
@@ -9326,7 +9391,7 @@ var ConsumablesStatusSchema = object({
9326
9391
  })),
9327
9392
  lastChangedAt: number()
9328
9393
  });
9329
- 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({
9394
+ Object.values(DeviceType), method(object({
9330
9395
  deviceId: number().int().nonnegative(),
9331
9396
  key: string().min(1)
9332
9397
  }), _void(), {
@@ -10376,7 +10441,6 @@ var PipelineDefaultStepSchema = lazy(() => object({
10376
10441
  enabled: boolean(),
10377
10442
  modelId: string(),
10378
10443
  children: array(PipelineDefaultStepSchema).readonly(),
10379
- engine: PipelineEngineChoiceSchema.optional(),
10380
10444
  group: string().optional(),
10381
10445
  settings: record(string(), unknown()).optional()
10382
10446
  }));
@@ -10401,7 +10465,9 @@ var PipelineModelOptionSchema = object({
10401
10465
  formats: record(string(), object({
10402
10466
  downloaded: boolean(),
10403
10467
  sizeMB: number()
10404
- }))
10468
+ })),
10469
+ group: ModelVariantGroupSchema.optional(),
10470
+ legacy: boolean().optional()
10405
10471
  });
10406
10472
  var ConfigFieldBridge = custom();
10407
10473
  var PipelineAddonSchemaSchema = object({
@@ -10452,15 +10518,42 @@ var EngineProvisioningSchema = object({
10452
10518
  ]),
10453
10519
  progress: number().optional(),
10454
10520
  error: string().optional(),
10455
- nextRetryAt: number().optional()
10521
+ nextRetryAt: number().optional(),
10522
+ /**
10523
+ * Gate A (config-correctness gate at engine change): human-readable
10524
+ * config issues surfaced EAGERLY when the node's engine changes — model
10525
+ * substitutions ("chose X, running Y") and zero-build steps ("no model
10526
+ * has a <format> build"). Additive/optional: informational only, never
10527
+ * enforced here — `assertEngineReady` (readiness) still gates inference.
10528
+ * Absent/empty when the node-default tree resolves cleanly.
10529
+ */
10530
+ configIssues: array(string()).optional()
10456
10531
  });
10457
10532
  var PipelineStepInputSchema = lazy(() => object({
10458
10533
  addonId: string(),
10459
- modelId: string(),
10534
+ modelId: string().optional(),
10460
10535
  enabled: boolean().default(true),
10461
10536
  children: array(PipelineStepInputSchema).optional(),
10462
10537
  settings: record(string(), unknown()).optional()
10463
10538
  }));
10539
+ var ModelSubstitutionSchema = object({
10540
+ addonId: string(),
10541
+ chosen: string(),
10542
+ running: string(),
10543
+ format: string()
10544
+ });
10545
+ var PipelineValidationIssueSchema = object({
10546
+ addonId: string(),
10547
+ kind: _enum(["unknown-addon", "no-format-build"]),
10548
+ detail: string()
10549
+ });
10550
+ var PipelineValidationResultSchema = object({
10551
+ ok: boolean(),
10552
+ issues: array(PipelineValidationIssueSchema).readonly(),
10553
+ substitutions: array(ModelSubstitutionSchema).readonly(),
10554
+ /** The node's `currentEngine.format` this validation ran against. */
10555
+ format: string()
10556
+ });
10464
10557
  var ReferenceImageEntrySchema = object({
10465
10558
  filename: string(),
10466
10559
  stepIds: array(string()).readonly().optional()
@@ -10531,7 +10624,13 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
10531
10624
  })) }), object({ success: literal(true) }), {
10532
10625
  kind: "mutation",
10533
10626
  auth: "admin"
10534
- }), method(_void(), PipelineSchemaSchema), method(_void(), array(PipelineDefaultStepSchema).readonly().nullable()), method(_void(), PipelineConfigBridge), method(_void(), ConfigUISchemaBridge), method(_void(), array(PipelineTemplateSchema$1).readonly()), method(object({
10627
+ }), method(object({ nodeId: string() }), object({
10628
+ success: literal(true),
10629
+ regeneratedModelId: string().nullable()
10630
+ }), {
10631
+ kind: "mutation",
10632
+ auth: "admin"
10633
+ }), 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({
10535
10634
  name: string(),
10536
10635
  steps: array(PipelineTemplateStepSchema).readonly(),
10537
10636
  engine: PipelineEngineChoiceSchema
@@ -10791,6 +10890,13 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
10791
10890
  kind: literal("remote-restream"),
10792
10891
  /** The camera's source-owner node (slice 1: always the hub). */
10793
10892
  ownerNodeId: string(),
10893
+ /**
10894
+ * The owner's LAN-reachable host, resolved by the orchestrator from the
10895
+ * per-node `reachableHost` override (Cluster UI). When present the runner
10896
+ * dials THIS host for the owner's restream, in preference to the
10897
+ * `CAMSTACK_HUB_URL`-derived default. Absent → auto-detect fallback.
10898
+ */
10899
+ ownerReachableHost: string().optional(),
10794
10900
  /** Operator override for the owner host the runner dials. */
10795
10901
  hubHostnameOverride: string().optional()
10796
10902
  })]).describe("Per-camera frame-source mode for the runner (P2c)");
@@ -10799,13 +10905,11 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
10799
10905
  * specific runner instance via `attachCamera`. Carries everything the
10800
10906
  * runner needs to subscribe to the local broker and execute inference.
10801
10907
  *
10802
- * Stateless-pipeline model: the full pipeline content (`engine`, `steps`,
10803
- * optional `audio`) travels with the attach payload. The runner keeps it
10804
- * in RAM for the lifetime of the attach — on rebalance, edit, or
10805
- * restart the orchestrator re-sends the latest snapshot.
10806
- *
10807
- * `engine`/`steps`/`audio` are optional during the additive migration
10808
- * window; once orchestrator + UI are migrated they become required.
10908
+ * Stateless-pipeline model: the pipeline content (`steps`, optional
10909
+ * `audio`) travels with the attach payload. The runner keeps it in RAM
10910
+ * for the lifetime of the attach — on rebalance, edit, or restart the
10911
+ * orchestrator re-sends the latest snapshot. Engine is NOT carried: it is
10912
+ * node-local, resolved by the executing runner at dispatch time.
10809
10913
  */
10810
10914
  var RunnerCameraConfigSchema = object({
10811
10915
  deviceId: number(),
@@ -10856,14 +10960,11 @@ var RunnerCameraConfigSchema = object({
10856
10960
  */
10857
10961
  motionSources: MotionSourcesSchema.default(["analyzer"]),
10858
10962
  pipelineEnabled: boolean().default(true),
10859
- /** Engine choice for video steps (runtime+backend+format). */
10860
- engine: PipelineEngineChoiceSchema.optional(),
10861
10963
  /** Ordered tree of video steps. Absent → runner skips video detection. */
10862
10964
  steps: array(PipelineStepInputSchema).readonly().optional(),
10863
10965
  /** Audio classification branch. `enabled:false` disables, null skips. */
10864
10966
  audio: object({
10865
- engine: PipelineEngineChoiceSchema,
10866
- modelId: string(),
10967
+ modelId: string().optional(),
10867
10968
  enabled: boolean()
10868
10969
  }).nullable().optional(),
10869
10970
  /**
@@ -15089,11 +15190,11 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
15089
15190
  timestamp: number()
15090
15191
  });
15091
15192
  var CameraPipelineConfigSchema = object({
15092
- engine: PipelineEngineChoiceSchema,
15193
+ engine: PipelineEngineChoiceSchema.optional(),
15093
15194
  steps: array(PipelineStepInputSchema).readonly(),
15094
15195
  audio: object({
15095
- engine: PipelineEngineChoiceSchema,
15096
- modelId: string(),
15196
+ engine: PipelineEngineChoiceSchema.optional(),
15197
+ modelId: string().optional(),
15097
15198
  enabled: boolean(),
15098
15199
  settings: record(string(), unknown()).readonly().optional()
15099
15200
  }).nullable().optional()
@@ -15108,7 +15209,7 @@ var PipelineTemplateSchema = object({
15108
15209
  });
15109
15210
  var AgentAddonConfigSchema = object({
15110
15211
  enabled: boolean(),
15111
- modelId: string(),
15212
+ modelId: string().optional(),
15112
15213
  settings: record(string(), unknown()).readonly()
15113
15214
  });
15114
15215
  var AgentPipelineSettingsSchema = object({
@@ -15123,7 +15224,15 @@ var AgentPipelineSettingsSchema = object({
15123
15224
  /** Node is eligible to run audio-analyzer sessions. */
15124
15225
  audio: boolean().optional(),
15125
15226
  /** Node is eligible to be the ingest / source-owner (serve the restream). */
15126
- ingest: boolean().optional()
15227
+ ingest: boolean().optional(),
15228
+ /**
15229
+ * Operator override for the LAN host a cross-node decoder dials to reach
15230
+ * THIS node's restream (Cluster UI). Absent → auto-detect: a remote runner
15231
+ * falls back to its `CAMSTACK_HUB_URL`-derived host (the Moleculer address
15232
+ * it already uses to reach the hub). Set this only when the auto-detected
15233
+ * address is wrong (multi-homed host, NAT, custom interface).
15234
+ */
15235
+ reachableHost: string().optional()
15127
15236
  });
15128
15237
  var CameraPipelineForAgentSchema = object({
15129
15238
  steps: array(PipelineStepInputSchema).readonly(),
@@ -15229,6 +15338,15 @@ var GlobalMetricsSchema = object({
15229
15338
  * capability providers.
15230
15339
  */
15231
15340
  var CapabilityBindingsSchema = record(string(), string());
15341
+ /**
15342
+ * The cluster's single camera-source owner (`clusterRoles.ingestNode`) plus
15343
+ * its LAN-reachable host, if one is registered. See `getIngestOwner`.
15344
+ */
15345
+ var IngestOwnerSchema = object({
15346
+ ownerNodeId: string(),
15347
+ reachableHost: string().optional(),
15348
+ configIssue: string().optional()
15349
+ });
15232
15350
  /** Source block — always present; derives from the stream catalog. */
15233
15351
  var CameraSourceStatusSchema = object({ streams: array(object({
15234
15352
  camStreamId: string(),
@@ -15243,6 +15361,14 @@ var CameraAssignmentStatusSchema = object({
15243
15361
  detectionNodeId: string().nullable(),
15244
15362
  decoderNodeId: string().nullable(),
15245
15363
  audioNodeId: string().nullable(),
15364
+ /**
15365
+ * The node that OWNS this camera's physical source pull (dials the RTSP and
15366
+ * hosts the broker/restream) — the cluster ingest owner today
15367
+ * (`clusterRoles.ingestNode`), per-camera once source assignment lands. Lets
15368
+ * the UI show WHERE a camera is sourced without SSH/logs, and is the node the
15369
+ * broker block below was read from (pinned). Nullable only pre-wiring.
15370
+ */
15371
+ sourceNodeId: string().nullable(),
15246
15372
  pinned: object({
15247
15373
  detection: boolean(),
15248
15374
  decoder: boolean(),
@@ -15375,7 +15501,7 @@ method(object({
15375
15501
  }), object({ success: literal(true) }), {
15376
15502
  kind: "mutation",
15377
15503
  auth: "admin"
15378
- }), method(object({
15504
+ }), method(_void(), IngestOwnerSchema), method(object({
15379
15505
  deviceId: number(),
15380
15506
  nodeId: string()
15381
15507
  }), _void(), {
@@ -15444,6 +15570,12 @@ method(object({
15444
15570
  }), object({ success: literal(true) }), {
15445
15571
  kind: "mutation",
15446
15572
  auth: "admin"
15573
+ }), method(object({
15574
+ agentNodeId: string(),
15575
+ reachableHost: string().nullable()
15576
+ }), object({ success: literal(true) }), {
15577
+ kind: "mutation",
15578
+ auth: "admin"
15447
15579
  }), method(object({ deviceId: number() }), CameraPipelineSettingsSchema.nullable()), method(object({
15448
15580
  deviceId: number(),
15449
15581
  addonId: string(),
@@ -15488,22 +15620,6 @@ method(object({
15488
15620
  kind: "mutation",
15489
15621
  auth: "admin"
15490
15622
  });
15491
- var RegisteredStreamSchema = object({
15492
- streamId: string(),
15493
- label: string().optional(),
15494
- codec: string(),
15495
- type: _enum(["video", "audio"]),
15496
- sourceUrl: string()
15497
- });
15498
- var ExposedResourceSchema = object({
15499
- streamId: string(),
15500
- format: string(),
15501
- value: string()
15502
- });
15503
- method(object({
15504
- deviceId: number(),
15505
- streams: array(RegisteredStreamSchema).readonly()
15506
- }), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), array(ExposedResourceSchema).readonly());
15507
15623
  /**
15508
15624
  * Query filter for settings-store collections.
15509
15625
  */
@@ -15656,9 +15772,9 @@ method(SendEmailInputSchema, SendEmailResultSchema, {
15656
15772
  /**
15657
15773
  * A single device snapshot returned as base64 JPEG/PNG.
15658
15774
  *
15659
- * Shared with the `snapshot-provider` collection cap the orchestrator
15660
- * receives the same shape from each native provider and from the
15661
- * broker-based fallback.
15775
+ * The `SnapshotAddon` wrapper returns this shape whether the frame came from
15776
+ * the device-native provider (onboard capture) or from the stream-broker
15777
+ * prebuffer fallback.
15662
15778
  */
15663
15779
  var SnapshotImageSchema = object({
15664
15780
  base64: string(),
@@ -15690,10 +15806,6 @@ DeviceType.Camera, method(object({
15690
15806
  kind: "mutation",
15691
15807
  auth: "admin"
15692
15808
  });
15693
- method(object({ deviceId: number() }), boolean()), method(object({
15694
- deviceId: number(),
15695
- streamId: string().optional()
15696
- }), SnapshotImageSchema.nullable());
15697
15809
  /**
15698
15810
  * `sso-bridge` — internal hub-only cap that lets SSO-style auth
15699
15811
  * providers (OIDC, SAML, magic-link, …) mint an HMAC-signed token
@@ -16054,9 +16166,10 @@ method(object({
16054
16166
  auth: "admin"
16055
16167
  });
16056
16168
  /**
16057
- * Optional client-side hints sent at session creation to help the
16058
- * provider pick the best native source. All fields are optional —
16059
- * a viewer that knows nothing still gets a sane default.
16169
+ * Optional client-side hints sent at session creation to help the provider
16170
+ * pick the best native source. All fields optional — a viewer that knows
16171
+ * nothing still gets a sane default. (Relocated from the retired `webrtc`
16172
+ * collection cap; this `webrtc-session` cap is the live signaling surface.)
16060
16173
  */
16061
16174
  var webrtcClientHintsSchema = object({
16062
16175
  viewportWidth: number().int().positive().optional(),
@@ -16067,22 +16180,6 @@ var webrtcClientHintsSchema = object({
16067
16180
  /** Hard tier override; takes precedence over scoring when registered. */
16068
16181
  prefersTier: string().optional()
16069
16182
  }).partial();
16070
- method(object({
16071
- streamId: string(),
16072
- sdpOffer: string()
16073
- }), string(), { kind: "mutation" }), method(object({ streamId: string() }), boolean()), method(object({
16074
- streamId: string(),
16075
- codec: string()
16076
- }), _void(), { kind: "mutation" }), method(object({ streamId: string() }), _void(), { kind: "mutation" }), method(object({
16077
- streamId: string(),
16078
- hints: webrtcClientHintsSchema.optional()
16079
- }), object({
16080
- sessionId: string(),
16081
- sdpOffer: string()
16082
- }), { kind: "mutation" }), method(object({
16083
- sessionId: string(),
16084
- sdpAnswer: string()
16085
- }), _void(), { kind: "mutation" }), method(object({ sessionId: string() }), _void(), { kind: "mutation" }), method(object({ streamId: string() }), boolean());
16086
16183
  /**
16087
16184
  * Discriminated target for a WebRTC session. The client sends this
16088
16185
  * structured object instead of building / parsing brokerId strings;
@@ -21125,6 +21222,12 @@ Object.freeze({
21125
21222
  addonId: null,
21126
21223
  access: "create"
21127
21224
  },
21225
+ "pipelineExecutor.resetToDefault": {
21226
+ capName: "pipeline-executor",
21227
+ capScope: "system",
21228
+ addonId: null,
21229
+ access: "delete"
21230
+ },
21128
21231
  "pipelineExecutor.runAudioTest": {
21129
21232
  capName: "pipeline-executor",
21130
21233
  capScope: "system",
@@ -21173,6 +21276,12 @@ Object.freeze({
21173
21276
  addonId: null,
21174
21277
  access: "create"
21175
21278
  },
21279
+ "pipelineExecutor.validatePipeline": {
21280
+ capName: "pipeline-executor",
21281
+ capScope: "system",
21282
+ addonId: null,
21283
+ access: "view"
21284
+ },
21176
21285
  "pipelineOrchestrator.assignAudio": {
21177
21286
  capName: "pipeline-orchestrator",
21178
21287
  capScope: "system",
@@ -21281,6 +21390,12 @@ Object.freeze({
21281
21390
  addonId: null,
21282
21391
  access: "view"
21283
21392
  },
21393
+ "pipelineOrchestrator.getIngestOwner": {
21394
+ capName: "pipeline-orchestrator",
21395
+ capScope: "system",
21396
+ addonId: null,
21397
+ access: "view"
21398
+ },
21284
21399
  "pipelineOrchestrator.getPipelineAssignment": {
21285
21400
  capName: "pipeline-orchestrator",
21286
21401
  capScope: "system",
@@ -21353,6 +21468,12 @@ Object.freeze({
21353
21468
  addonId: null,
21354
21469
  access: "create"
21355
21470
  },
21471
+ "pipelineOrchestrator.setAgentReachableHost": {
21472
+ capName: "pipeline-orchestrator",
21473
+ capScope: "system",
21474
+ addonId: null,
21475
+ access: "create"
21476
+ },
21356
21477
  "pipelineOrchestrator.setCameraPipelineForAgent": {
21357
21478
  capName: "pipeline-orchestrator",
21358
21479
  capScope: "system",
@@ -21683,24 +21804,6 @@ Object.freeze({
21683
21804
  addonId: null,
21684
21805
  access: "create"
21685
21806
  },
21686
- "restreamer.getExposedResources": {
21687
- capName: "restreamer",
21688
- capScope: "system",
21689
- addonId: null,
21690
- access: "view"
21691
- },
21692
- "restreamer.registerDevice": {
21693
- capName: "restreamer",
21694
- capScope: "system",
21695
- addonId: null,
21696
- access: "create"
21697
- },
21698
- "restreamer.unregisterDevice": {
21699
- capName: "restreamer",
21700
- capScope: "system",
21701
- addonId: null,
21702
- access: "delete"
21703
- },
21704
21807
  "scriptRunner.run": {
21705
21808
  capName: "script-runner",
21706
21809
  capScope: "device",
@@ -21803,18 +21906,6 @@ Object.freeze({
21803
21906
  addonId: null,
21804
21907
  access: "create"
21805
21908
  },
21806
- "snapshotProvider.getSnapshot": {
21807
- capName: "snapshot-provider",
21808
- capScope: "system",
21809
- addonId: null,
21810
- access: "view"
21811
- },
21812
- "snapshotProvider.supportsDevice": {
21813
- capName: "snapshot-provider",
21814
- capScope: "system",
21815
- addonId: null,
21816
- access: "view"
21817
- },
21818
21909
  "ssoBridge.signBridgeToken": {
21819
21910
  capName: "sso-bridge",
21820
21911
  capScope: "system",
@@ -22241,30 +22332,6 @@ Object.freeze({
22241
22332
  addonId: null,
22242
22333
  access: "view"
22243
22334
  },
22244
- "streamingEngine.getStreamUrl": {
22245
- capName: "streaming-engine",
22246
- capScope: "system",
22247
- addonId: null,
22248
- access: "view"
22249
- },
22250
- "streamingEngine.listStreams": {
22251
- capName: "streaming-engine",
22252
- capScope: "system",
22253
- addonId: null,
22254
- access: "view"
22255
- },
22256
- "streamingEngine.registerStream": {
22257
- capName: "streaming-engine",
22258
- capScope: "system",
22259
- addonId: null,
22260
- access: "create"
22261
- },
22262
- "streamingEngine.unregisterStream": {
22263
- capName: "streaming-engine",
22264
- capScope: "system",
22265
- addonId: null,
22266
- access: "delete"
22267
- },
22268
22335
  "streamParams.getConfigSchema": {
22269
22336
  capName: "stream-params",
22270
22337
  capScope: "device",
@@ -22631,54 +22698,6 @@ Object.freeze({
22631
22698
  addonId: null,
22632
22699
  access: "create"
22633
22700
  },
22634
- "webrtc.closeSession": {
22635
- capName: "webrtc",
22636
- capScope: "system",
22637
- addonId: null,
22638
- access: "create"
22639
- },
22640
- "webrtc.createSession": {
22641
- capName: "webrtc",
22642
- capScope: "system",
22643
- addonId: null,
22644
- access: "create"
22645
- },
22646
- "webrtc.handleAnswer": {
22647
- capName: "webrtc",
22648
- capScope: "system",
22649
- addonId: null,
22650
- access: "create"
22651
- },
22652
- "webrtc.handleOffer": {
22653
- capName: "webrtc",
22654
- capScope: "system",
22655
- addonId: null,
22656
- access: "create"
22657
- },
22658
- "webrtc.hasAdaptiveBitrate": {
22659
- capName: "webrtc",
22660
- capScope: "system",
22661
- addonId: null,
22662
- access: "view"
22663
- },
22664
- "webrtc.registerStream": {
22665
- capName: "webrtc",
22666
- capScope: "system",
22667
- addonId: null,
22668
- access: "create"
22669
- },
22670
- "webrtc.supportsStream": {
22671
- capName: "webrtc",
22672
- capScope: "system",
22673
- addonId: null,
22674
- access: "view"
22675
- },
22676
- "webrtc.unregisterStream": {
22677
- capName: "webrtc",
22678
- capScope: "system",
22679
- addonId: null,
22680
- access: "delete"
22681
- },
22682
22701
  "webrtcSession.addIceCandidate": {
22683
22702
  capName: "webrtc-session",
22684
22703
  capScope: "device",
@@ -22847,7 +22866,7 @@ var AdminUIAddon = class extends BaseAddon {
22847
22866
  capability: adminUiCapability,
22848
22867
  provider: {
22849
22868
  getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
22850
- getVersion: async () => ({ version: "1.1.34" })
22869
+ getVersion: async () => ({ version: "1.1.36" })
22851
22870
  }
22852
22871
  }];
22853
22872
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-admin-ui",
3
- "version": "1.1.34",
3
+ "version": "1.1.36",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "CamStack Admin UI — Vite frontend build and server-side addon",