@camstack/addon-agent-ui 1.1.20 → 1.1.22

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.
package/dist/addon.js CHANGED
@@ -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-BC9Yqte7.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`.
@@ -5338,10 +5350,6 @@ function hydrateField(field, values) {
5338
5350
  };
5339
5351
  }
5340
5352
  const rawValue = storedValue !== void 0 ? storedValue : defaultValue !== void 0 ? defaultValue : null;
5341
- if (field.type === "password") return {
5342
- ...field,
5343
- value: ""
5344
- };
5345
5353
  const value = field.type === "textarea" && field.isJson && rawValue !== null && typeof rawValue === "object" ? JSON.stringify(rawValue, null, 2) : rawValue;
5346
5354
  return {
5347
5355
  ...field,
@@ -6725,18 +6733,33 @@ function method(input, output, options) {
6725
6733
  timeoutMs: options?.timeoutMs
6726
6734
  };
6727
6735
  }
6728
- var StaticDirOutputSchema = object({ staticDir: string() });
6729
- var VersionOutputSchema = object({ version: string() });
6736
+ /**
6737
+ * A wrapper/system-only method: served exclusively by the cap's system-level
6738
+ * provider (`InferProvider`), and OPTIONAL on `InferNativeProvider` so per-device
6739
+ * driver natives don't stub out a wrapper concern (e.g. a cross-device cache
6740
+ * overview). The `systemOnly: true` literal is what `InferNativeProvider` keys on.
6741
+ */
6742
+ function systemMethod(input, output, options) {
6743
+ return {
6744
+ ...method(input, output, options),
6745
+ systemOnly: true
6746
+ };
6747
+ }
6748
+ var StaticDirOutputSchema$1 = object({ staticDir: string() });
6749
+ var VersionOutputSchema$1 = object({ version: string() });
6730
6750
  var adminUiCapability = {
6731
6751
  name: "admin-ui",
6732
6752
  scope: "system",
6733
6753
  mode: "singleton",
6734
6754
  internal: true,
6735
6755
  methods: {
6736
- getStaticDir: method(_void(), StaticDirOutputSchema),
6737
- getVersion: method(_void(), VersionOutputSchema)
6756
+ getStaticDir: method(_void(), StaticDirOutputSchema$1),
6757
+ getVersion: method(_void(), VersionOutputSchema$1)
6738
6758
  }
6739
6759
  };
6760
+ var StaticDirOutputSchema = object({ staticDir: string() });
6761
+ var VersionOutputSchema = object({ version: string() });
6762
+ method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
6740
6763
  /**
6741
6764
  * device-ops — device-scoped cap that unifies the per-IDevice operations
6742
6765
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -6903,6 +6926,36 @@ var ModelFormatsSchema = object({
6903
6926
  tflite: ModelFormatEntrySchema.optional(),
6904
6927
  pt: ModelFormatEntrySchema.optional()
6905
6928
  });
6929
+ /**
6930
+ * Variant-selector grouping axes. Shared by the full `ModelCatalogEntry` and by
6931
+ * the reduced `PipelineModelOption` returned in `pipeline.getSchema()` so the
6932
+ * grouped Family→Tier→Variant picker renders identically in the config UI and
6933
+ * in the pipeline/device steppers. The flat `id` stays the source of truth for
6934
+ * resolution/download/persistence; this is a presentation overlay resolved back
6935
+ * to an `id`.
6936
+ */
6937
+ var ModelVariantGroupSchema = object({
6938
+ /** Top-level family, e.g. `yolo26` (later `d-fine`, `rf-detr`). */
6939
+ family: string(),
6940
+ /** Size within the family, e.g. `n` | `s` | `m` | `l`. */
6941
+ tier: string(),
6942
+ /** Quantization axis. Omit ⇒ the fp32 base build. */
6943
+ precision: _enum(["fp32", "int8"]).optional(),
6944
+ /**
6945
+ * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
6946
+ * latency-optimized export (e.g. ReLU-activation variant) — the slot the
6947
+ * future performance variants plug into.
6948
+ */
6949
+ optimization: _enum(["standard", "fast"]).optional(),
6950
+ /**
6951
+ * Input-resolution axis (square input side, px). Omit ⇒ the family's native
6952
+ * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
6953
+ * cheap latency lever — especially on Apple ANE and the Intel N100 — at a
6954
+ * small-object accuracy cost. Mirrors the model's `inputSize` but lifted onto
6955
+ * the group so the selector can offer it as a variant axis.
6956
+ */
6957
+ resolution: number().int().positive().optional()
6958
+ });
6906
6959
  var ModelCatalogEntrySchema = object({
6907
6960
  id: string(),
6908
6961
  name: string(),
@@ -6932,7 +6985,43 @@ var ModelCatalogEntrySchema = object({
6932
6985
  * Auxiliary files required at runtime (labels JSON, charset dict, etc.).
6933
6986
  * Downloaded into the same modelsDir alongside the model file.
6934
6987
  */
6935
- extraFiles: array(ModelExtraFileSchema).readonly().optional()
6988
+ extraFiles: array(ModelExtraFileSchema).readonly().optional(),
6989
+ /**
6990
+ * LEGACY entry — retained in the catalog so a persisted operator selection
6991
+ * still RESOLVES (and can be re-activated), but hidden from the selectable
6992
+ * model list and excluded from the auto format-default pick. Set on the
6993
+ * superseded / consolidated models (older lineages, redundant fp16 IRs) so
6994
+ * the active lineup stays the coherent curated ladder without deleting a
6995
+ * model anyone may still be pinned to. `resolveModelForFormat` keeps honoring
6996
+ * an explicit legacy id that has a build for the node's format.
6997
+ */
6998
+ legacy: boolean().optional(),
6999
+ /**
7000
+ * Measured quality/latency metadata — populated from the benchmark addon on
7001
+ * the real node classes. Absent = not yet measured (most entries today; the
7002
+ * catalog historically carried only `sizeMB`, a poor cross-architecture
7003
+ * speed proxy). `p95LatencyMs` is keyed by node class (e.g. `n100`, `mac`).
7004
+ */
7005
+ metrics: object({
7006
+ map50: number().optional(),
7007
+ p95LatencyMs: record(string(), number()).optional()
7008
+ }).optional(),
7009
+ /**
7010
+ * SPDX-ish license id of the model weights (e.g. `AGPL-3.0` for Ultralytics
7011
+ * YOLO26, `GPL-3.0` for YOLOv9, `Apache-2.0` for D-FINE/RF-DETR). Matters for
7012
+ * the retraining addon and any future commercial distribution.
7013
+ */
7014
+ license: string().optional(),
7015
+ /**
7016
+ * Variant-selector grouping. The UI groups models by `family` + `tier` and
7017
+ * offers `precision` / `optimization` as variant axes WITHIN a tier — so all
7018
+ * of a family's sizes and quantizations collapse into one grouped picker
7019
+ * instead of a flat list of `yolo26s`, `yolo26s-int8`, … Absent ⇒ ungrouped
7020
+ * (legacy / custom models) — never shown in the grouped selector. The flat
7021
+ * `id` stays the source of truth for resolution/download/persistence; grouping
7022
+ * is a presentation overlay resolved back to an `id`.
7023
+ */
7024
+ group: ModelVariantGroupSchema.optional()
6936
7025
  });
6937
7026
  var ConvertTargetSchema = discriminatedUnion("format", [object({
6938
7027
  format: literal("openvino"),
@@ -6993,8 +7082,8 @@ var RecordingModeSchema = _enum([
6993
7082
  "onAudioThreshold"
6994
7083
  ]);
6995
7084
  /**
6996
- * First-class, authoritative per-camera storage mode — the netta choice the UI
6997
- * reads directly (never inferred from `rules`):
7085
+ * First-class, authoritative per-camera storage mode — the explicit choice the
7086
+ * UI reads directly (never inferred from `rules`):
6998
7087
  * - `off` — not recording.
6999
7088
  * - `events` — record only around triggers (motion / audio threshold),
7000
7089
  * with pre/post-buffer.
@@ -8642,26 +8731,13 @@ DeviceType.Light, method(object({
8642
8731
  percentage: number().min(0).max(100),
8643
8732
  lastChangedAt: number()
8644
8733
  });
8734
+ /** Stream delivery format. (Relocated from the retired `streaming-engine` cap.) */
8645
8735
  var StreamFormatSchema = _enum([
8646
8736
  "webrtc",
8647
8737
  "hls",
8648
8738
  "mjpeg",
8649
8739
  "rtsp"
8650
8740
  ]);
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
8741
  var RtspRestreamEntrySchema = object({
8666
8742
  brokerId: string(),
8667
8743
  url: string(),
@@ -9326,7 +9402,7 @@ var ConsumablesStatusSchema = object({
9326
9402
  })),
9327
9403
  lastChangedAt: number()
9328
9404
  });
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({
9405
+ Object.values(DeviceType), method(object({
9330
9406
  deviceId: number().int().nonnegative(),
9331
9407
  key: string().min(1)
9332
9408
  }), _void(), {
@@ -10241,7 +10317,7 @@ var BoundingBoxSchema = object({
10241
10317
  w: number(),
10242
10318
  h: number()
10243
10319
  });
10244
- var SpatialDetectionSchema = object({
10320
+ object({
10245
10321
  class: string(),
10246
10322
  originalClass: string(),
10247
10323
  score: number(),
@@ -10376,7 +10452,6 @@ var PipelineDefaultStepSchema = lazy(() => object({
10376
10452
  enabled: boolean(),
10377
10453
  modelId: string(),
10378
10454
  children: array(PipelineDefaultStepSchema).readonly(),
10379
- engine: PipelineEngineChoiceSchema.optional(),
10380
10455
  group: string().optional(),
10381
10456
  settings: record(string(), unknown()).optional()
10382
10457
  }));
@@ -10401,7 +10476,9 @@ var PipelineModelOptionSchema = object({
10401
10476
  formats: record(string(), object({
10402
10477
  downloaded: boolean(),
10403
10478
  sizeMB: number()
10404
- }))
10479
+ })),
10480
+ group: ModelVariantGroupSchema.optional(),
10481
+ legacy: boolean().optional()
10405
10482
  });
10406
10483
  var ConfigFieldBridge = custom();
10407
10484
  var PipelineAddonSchemaSchema = object({
@@ -10415,6 +10492,7 @@ var PipelineAddonSchemaSchema = object({
10415
10492
  defaultModelId: string(),
10416
10493
  defaultModelIdByFormat: record(string(), string()).optional(),
10417
10494
  enabledByDefault: boolean().optional(),
10495
+ backfillIntoExistingOverrides: boolean().optional(),
10418
10496
  defaultConfidence: number(),
10419
10497
  group: string().optional(),
10420
10498
  configSchema: array(ConfigFieldBridge).readonly().optional()
@@ -10431,11 +10509,6 @@ var PipelineSchemaSchema = object({
10431
10509
  selectedEngine: PipelineEngineChoiceSchema,
10432
10510
  slots: array(PipelineSlotSchemaSchema).readonly()
10433
10511
  });
10434
- var DetectorOutputSchema = object({
10435
- detections: array(SpatialDetectionSchema).readonly(),
10436
- inferenceMs: number(),
10437
- modelId: string()
10438
- });
10439
10512
  var EngineProvisioningSchema = object({
10440
10513
  runtimeId: _enum([
10441
10514
  "onnx",
@@ -10452,15 +10525,42 @@ var EngineProvisioningSchema = object({
10452
10525
  ]),
10453
10526
  progress: number().optional(),
10454
10527
  error: string().optional(),
10455
- nextRetryAt: number().optional()
10528
+ nextRetryAt: number().optional(),
10529
+ /**
10530
+ * Gate A (config-correctness gate at engine change): human-readable
10531
+ * config issues surfaced EAGERLY when the node's engine changes — model
10532
+ * substitutions ("chose X, running Y") and zero-build steps ("no model
10533
+ * has a <format> build"). Additive/optional: informational only, never
10534
+ * enforced here — `assertEngineReady` (readiness) still gates inference.
10535
+ * Absent/empty when the node-default tree resolves cleanly.
10536
+ */
10537
+ configIssues: array(string()).optional()
10456
10538
  });
10457
10539
  var PipelineStepInputSchema = lazy(() => object({
10458
10540
  addonId: string(),
10459
- modelId: string(),
10541
+ modelId: string().optional(),
10460
10542
  enabled: boolean().default(true),
10461
10543
  children: array(PipelineStepInputSchema).optional(),
10462
10544
  settings: record(string(), unknown()).optional()
10463
10545
  }));
10546
+ var ModelSubstitutionSchema = object({
10547
+ addonId: string(),
10548
+ chosen: string(),
10549
+ running: string(),
10550
+ format: string()
10551
+ });
10552
+ var PipelineValidationIssueSchema = object({
10553
+ addonId: string(),
10554
+ kind: _enum(["unknown-addon", "no-format-build"]),
10555
+ detail: string()
10556
+ });
10557
+ var PipelineValidationResultSchema = object({
10558
+ ok: boolean(),
10559
+ issues: array(PipelineValidationIssueSchema).readonly(),
10560
+ substitutions: array(ModelSubstitutionSchema).readonly(),
10561
+ /** The node's `currentEngine.format` this validation ran against. */
10562
+ format: string()
10563
+ });
10464
10564
  var ReferenceImageEntrySchema = object({
10465
10565
  filename: string(),
10466
10566
  stepIds: array(string()).readonly().optional()
@@ -10531,7 +10631,13 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
10531
10631
  })) }), object({ success: literal(true) }), {
10532
10632
  kind: "mutation",
10533
10633
  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({
10634
+ }), method(object({ nodeId: string() }), object({
10635
+ success: literal(true),
10636
+ clearedDevices: number()
10637
+ }), {
10638
+ kind: "mutation",
10639
+ auth: "admin"
10640
+ }), 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
10641
  name: string(),
10536
10642
  steps: array(PipelineTemplateStepSchema).readonly(),
10537
10643
  engine: PipelineEngineChoiceSchema
@@ -10548,10 +10654,6 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
10548
10654
  modelId: string(),
10549
10655
  format: ModelFormatSchema$1
10550
10656
  }), object({ success: literal(true) }), { kind: "mutation" }), method(object({
10551
- addonId: string(),
10552
- frame: FrameInputSchema,
10553
- config: record(string(), unknown()).optional()
10554
- }), DetectorOutputSchema), method(object({
10555
10657
  engine: PipelineEngineChoiceSchema.optional(),
10556
10658
  steps: array(PipelineStepInputSchema).min(1),
10557
10659
  frame: FrameInputSchema.optional(),
@@ -10697,6 +10799,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(ZoneSchema).read
10697
10799
  auth: "admin"
10698
10800
  }), object({ zones: array(ZoneSchema).readonly() });
10699
10801
  /**
10802
+ * A bounding box in NORMALIZED [0,1] frame coordinates for `getNativeCrop`. The
10803
+ * decode worker resolves it against the RETAINED native frame's real pixel dims,
10804
+ * so the caller supplies only the detection-res bbox divided by the detection
10805
+ * dims — no native resolution to plumb.
10806
+ */
10807
+ var NativeCropBboxSchema = object({
10808
+ x: number(),
10809
+ y: number(),
10810
+ w: number(),
10811
+ h: number()
10812
+ });
10813
+ /** Result of a best-effort native-resolution crop (`getNativeCrop`). */
10814
+ var NativeCropResultSchema = object({
10815
+ /** Packed rgb (24-bit) pixels of the crop. */
10816
+ bytes: _instanceof(Uint8Array),
10817
+ width: number().int().positive(),
10818
+ height: number().int().positive()
10819
+ });
10820
+ /**
10700
10821
  * Per-camera tunable ranges + defaults. Single source of truth used
10701
10822
  * by both the Zod data schema (validation + default fallback) and
10702
10823
  * the device settings UI (slider min/max/step). Touch one place and
@@ -10791,6 +10912,13 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
10791
10912
  kind: literal("remote-restream"),
10792
10913
  /** The camera's source-owner node (slice 1: always the hub). */
10793
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(),
10794
10922
  /** Operator override for the owner host the runner dials. */
10795
10923
  hubHostnameOverride: string().optional()
10796
10924
  })]).describe("Per-camera frame-source mode for the runner (P2c)");
@@ -10799,13 +10927,11 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
10799
10927
  * specific runner instance via `attachCamera`. Carries everything the
10800
10928
  * runner needs to subscribe to the local broker and execute inference.
10801
10929
  *
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.
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.
10809
10935
  */
10810
10936
  var RunnerCameraConfigSchema = object({
10811
10937
  deviceId: number(),
@@ -10856,14 +10982,11 @@ var RunnerCameraConfigSchema = object({
10856
10982
  */
10857
10983
  motionSources: MotionSourcesSchema.default(["analyzer"]),
10858
10984
  pipelineEnabled: boolean().default(true),
10859
- /** Engine choice for video steps (runtime+backend+format). */
10860
- engine: PipelineEngineChoiceSchema.optional(),
10861
10985
  /** Ordered tree of video steps. Absent → runner skips video detection. */
10862
10986
  steps: array(PipelineStepInputSchema).readonly().optional(),
10863
10987
  /** Audio classification branch. `enabled:false` disables, null skips. */
10864
10988
  audio: object({
10865
- engine: PipelineEngineChoiceSchema,
10866
- modelId: string(),
10989
+ modelId: string().optional(),
10867
10990
  enabled: boolean()
10868
10991
  }).nullable().optional(),
10869
10992
  /**
@@ -10950,7 +11073,11 @@ var RunnerLocalMetricsSchema = object({
10950
11073
  avgInferenceTimeMs: number(),
10951
11074
  queueDepth: number()
10952
11075
  });
10953
- method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number()).readonly());
11076
+ method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number()).readonly()), method(object({
11077
+ handle: FrameHandleSchema,
11078
+ bbox: NativeCropBboxSchema,
11079
+ maxWidth: number().int().positive().optional()
11080
+ }), NativeCropResultSchema.nullable());
10954
11081
  object({
10955
11082
  detected: boolean(),
10956
11083
  /** Ms epoch of the last detected-true observation. Null if never detected. */
@@ -12244,7 +12371,9 @@ var AddonPageDeclarationSchema$1 = object({
12244
12371
  icon: string(),
12245
12372
  path: string(),
12246
12373
  remoteName: string(),
12247
- bundle: string()
12374
+ bundle: string(),
12375
+ section: string().optional(),
12376
+ sectionLabel: string().optional()
12248
12377
  });
12249
12378
  var AddonPageInfoSchema = object({
12250
12379
  addonId: string(),
@@ -12284,7 +12413,18 @@ var AddonPageDeclarationSchema = object({
12284
12413
  * the static-file route can compute an mtime-based cache-buster URL
12285
12414
  * without a separate filesystem stat.
12286
12415
  */
12287
- bundle: string()
12416
+ bundle: string(),
12417
+ /**
12418
+ * Sidebar section this page docks into. Well-known ids: `'detection'`,
12419
+ * `'cluster'`, `'administration'` — the page renders inside that group.
12420
+ * Any OTHER string creates (or joins) a custom section rendered after
12421
+ * the built-in groups; its label comes from `sectionLabel` (first
12422
+ * declaration wins), falling back to the id. Absent → the legacy
12423
+ * "Addon Pages" group.
12424
+ */
12425
+ section: string().optional(),
12426
+ /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
12427
+ sectionLabel: string().optional()
12288
12428
  });
12289
12429
  method(_void(), array(AddonPageDeclarationSchema).readonly());
12290
12430
  var AddonHttpRouteSchema = object({
@@ -12500,6 +12640,17 @@ var WidgetMetadataSchema = object({
12500
12640
  deviceContext: boolean().default(false),
12501
12641
  integrationContext: boolean().default(false)
12502
12642
  }),
12643
+ /**
12644
+ * Loadable BEFORE authentication. The normal widget registry listing
12645
+ * (`addon-widgets.listWidgets`) is auth-gated, so a pre-auth surface
12646
+ * (the login page) cannot discover a widget through it. A widget that
12647
+ * declares `preAuth: true` marks itself as safe to mount on a pre-auth
12648
+ * screen — it is surfaced through the PUBLIC `auth.listLoginMethods`
12649
+ * login-method contribution channel (see `login-method.cap.ts`) rather
12650
+ * than the authenticated registry, and its bundle is served by the
12651
+ * public `/api/addon-widgets/:addonId/*` static route. Defaults false.
12652
+ */
12653
+ preAuth: boolean().optional().default(false),
12503
12654
  /** Dashboard placement HINTS (operator can override per instance). */
12504
12655
  defaultSize: WidgetSizeEnum.default("md"),
12505
12656
  allowedSizes: array(WidgetSizeEnum).readonly().default([
@@ -12801,6 +12952,66 @@ method(object({
12801
12952
  password: string()
12802
12953
  }), AuthResultSchema.nullable(), { kind: "mutation" }), method(object({ state: string() }), string()), method(record(string(), string()), AuthResultSchema, { kind: "mutation" }), method(object({ token: string() }), AuthResultSchema.nullable());
12803
12954
  /**
12955
+ * `login-method` — collection cap through which auth addons contribute
12956
+ * their pre-auth login surfaces to the login page. This is the SINGLE,
12957
+ * generic mechanism that supersedes the dead `auth.listProviders` reader:
12958
+ * every auth addon (OIDC, magic-link, WebAuthn/passkey) registers a
12959
+ * `login-method` provider and the PUBLIC `auth.listLoginMethods`
12960
+ * procedure aggregates them for the unauthenticated login page.
12961
+ *
12962
+ * A contribution is a discriminated union on `kind`:
12963
+ *
12964
+ * - `redirect` — a declarative button. The login page renders a generic
12965
+ * button that navigates to `startUrl` (an addon-owned HTTP route).
12966
+ * Covers OIDC (`/addon/auth-oidc/<id>/start`) and magic-link with
12967
+ * ZERO shell-side JS. A future SSO addon plugs in the same way — the
12968
+ * login page needs NO change.
12969
+ *
12970
+ * - `widget` — a Module-Federation widget the login page mounts (via
12971
+ * `loadRemoteBundle`) for an in-page ceremony. Covers the passkey
12972
+ * login ceremony, which must run `@simplewebauthn/browser` INSIDE the
12973
+ * addon bundle. The referenced widget also declares `preAuth: true` in
12974
+ * its `addon-widgets-source` catalog entry. `auth.listLoginMethods`
12975
+ * stamps a public `bundleUrl` from `addonId` + `bundle`.
12976
+ *
12977
+ * Every contribution carries a `stage`:
12978
+ * - `primary` — shown on the first credentials screen (OIDC /
12979
+ * magic-link buttons; a future usernameless passkey).
12980
+ * - `second-factor` — shown AFTER the password leg, gated on the
12981
+ * returned `factors` (passkey-as-2FA today).
12982
+ *
12983
+ * `mount: skip` — the cap is read server-side by the core auth router
12984
+ * (`registry.getCollection('login-method')`), never mounted as its own
12985
+ * tRPC router.
12986
+ */
12987
+ /** When a login method renders in the two-phase login flow. */
12988
+ var LoginStageEnum = _enum(["primary", "second-factor"]);
12989
+ /** One login-method contribution — redirect button OR pre-auth widget. */
12990
+ var LoginMethodContributionSchema = discriminatedUnion("kind", [object({
12991
+ kind: literal("redirect"),
12992
+ /** Stable id within the login-method set (e.g. `auth-oidc/google`). */
12993
+ id: string(),
12994
+ /** Operator-facing button label. */
12995
+ label: string(),
12996
+ /** lucide-react icon name. */
12997
+ icon: string().optional(),
12998
+ /** Addon-owned HTTP route the button navigates to (GET). */
12999
+ startUrl: string(),
13000
+ stage: LoginStageEnum
13001
+ }), object({
13002
+ kind: literal("widget"),
13003
+ /** Stable id within the login-method set (e.g. `auth-webauthn/passkey-login`). */
13004
+ id: string(),
13005
+ /** Owning addon id — drives the public bundle URL + the MF namespace. */
13006
+ addonId: string(),
13007
+ /** Bundle filename inside the addon's dist dir (`remoteEntry.js`). */
13008
+ bundle: string(),
13009
+ /** MF remote descriptor — `{ remoteName, exposedModule, componentKey }`. */
13010
+ remote: WidgetRemoteSchema,
13011
+ stage: LoginStageEnum
13012
+ })]);
13013
+ method(_void(), array(LoginMethodContributionSchema).readonly());
13014
+ /**
12804
13015
  * Orchestrator-side destination metadata. The orchestrator computes
12805
13016
  * `id = <addonId>:<subId>` from its provider lookup so consumers
12806
13017
  * (admin UI, restore flow) see one canonical key.
@@ -14904,7 +15115,17 @@ var TrackSchema = object({
14904
15115
  /** Cumulative normalized distance travelled (0..1 units = full frame width). */
14905
15116
  totalDistance: number(),
14906
15117
  state: TrackStateSchema,
14907
- active: boolean()
15118
+ active: boolean(),
15119
+ /** Deterministic key-event importance score in [0,1] (server-computed at
15120
+ * track expiry, recomputed on late label). Absent on legacy rows written
15121
+ * before scoring shipped — consumers degrade to absence / compute-on-read. */
15122
+ importance: number().optional(),
15123
+ /** Id of the track's highest-confidence ObjectEvent (its representative
15124
+ * "best" frame). Absent when the track produced no object events. */
15125
+ bestEventId: string().optional(),
15126
+ /** Tag of the importance sub-signal that dominated the score
15127
+ * (identity|dwell|proximity|class|confidence|travel|zone). */
15128
+ importanceReason: string().optional()
14908
15129
  });
14909
15130
  var BaseEventFields = {
14910
15131
  id: string(),
@@ -14969,8 +15190,18 @@ var ObjectEventSchema = object({
14969
15190
  frameHeight: number().optional(),
14970
15191
  /** MediaStore key for the crop attached to this event (if any). */
14971
15192
  mediaKey: string().optional(),
15193
+ /** Design B: MediaStore key of the track's native-resolution key frame (the
15194
+ * best-detection full frame). Resolve via the event-media data-plane
15195
+ * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`) for a detail view that
15196
+ * draws `bbox` over the native frame. Absent on legacy rows / non-decoded
15197
+ * sources — consumers fall back to `mediaKey` (the tight crop). */
15198
+ keyFrameMediaKey: string().optional(),
14972
15199
  /** Populated by B5 (recording playback URL for this event). */
14973
- mediaUrl: string().optional()
15200
+ mediaUrl: string().optional(),
15201
+ /** The parent track's key-event importance [0,1], propagated to every object
15202
+ * event of the track (so an event row can be sorted by importance without a
15203
+ * track join). Absent on legacy rows / before the track was scored. */
15204
+ importance: number().optional()
14974
15205
  });
14975
15206
  var AudioEventSchema = object({
14976
15207
  ...BaseEventFields,
@@ -14994,7 +15225,8 @@ var MediaFileKindEnum = _enum([
14994
15225
  "fullFrame",
14995
15226
  "fullFrameBoxed",
14996
15227
  "faceCrop",
14997
- "plateCrop"
15228
+ "plateCrop",
15229
+ "keyFrame"
14998
15230
  ]);
14999
15231
  var MediaFileSchema = object({
15000
15232
  key: string(),
@@ -15015,6 +15247,32 @@ var DeviceEventQueryInput = object({
15015
15247
  projection: _enum(["full", "slim"]).optional()
15016
15248
  });
15017
15249
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
15250
+ var KeyEventQueryInput = object({
15251
+ deviceId: number(),
15252
+ /** Window lower bound (track firstSeen ≥ since). */
15253
+ since: number(),
15254
+ /** Window upper bound (track firstSeen ≤ until). */
15255
+ until: number(),
15256
+ limit: number().int().min(1).max(200).default(50),
15257
+ /** Drop tracks scoring below this importance. */
15258
+ minImportance: number().min(0).max(1).optional(),
15259
+ /** Restrict to a single class (e.g. 'person'). */
15260
+ classFilter: string().optional()
15261
+ });
15262
+ var KeyEventSchema = object({
15263
+ /** The representative event id (the track's best ObjectEvent, else its trackId). */
15264
+ id: string(),
15265
+ trackId: string(),
15266
+ /** Track start time (firstSeen). */
15267
+ timestamp: number(),
15268
+ className: string(),
15269
+ label: string().optional(),
15270
+ importance: number(),
15271
+ /** Highest-confidence ObjectEvent id for the track (empty when none). */
15272
+ bestEventId: string(),
15273
+ /** Track lifetime in ms (lastSeen - firstSeen). */
15274
+ windowMs: number().optional()
15275
+ });
15018
15276
  var TrackedDetectionSchema = object({
15019
15277
  trackId: string(),
15020
15278
  className: string(),
@@ -15044,7 +15302,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
15044
15302
  }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
15045
15303
  kind: "mutation",
15046
15304
  auth: "admin"
15047
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({
15305
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
15048
15306
  deviceId: number(),
15049
15307
  since: number(),
15050
15308
  until: number(),
@@ -15089,11 +15347,11 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
15089
15347
  timestamp: number()
15090
15348
  });
15091
15349
  var CameraPipelineConfigSchema = object({
15092
- engine: PipelineEngineChoiceSchema,
15350
+ engine: PipelineEngineChoiceSchema.optional(),
15093
15351
  steps: array(PipelineStepInputSchema).readonly(),
15094
15352
  audio: object({
15095
- engine: PipelineEngineChoiceSchema,
15096
- modelId: string(),
15353
+ engine: PipelineEngineChoiceSchema.optional(),
15354
+ modelId: string().optional(),
15097
15355
  enabled: boolean(),
15098
15356
  settings: record(string(), unknown()).readonly().optional()
15099
15357
  }).nullable().optional()
@@ -15108,7 +15366,7 @@ var PipelineTemplateSchema = object({
15108
15366
  });
15109
15367
  var AgentAddonConfigSchema = object({
15110
15368
  enabled: boolean(),
15111
- modelId: string(),
15369
+ modelId: string().optional(),
15112
15370
  settings: record(string(), unknown()).readonly()
15113
15371
  });
15114
15372
  var AgentPipelineSettingsSchema = object({
@@ -15118,12 +15376,25 @@ var AgentPipelineSettingsSchema = object({
15118
15376
  detectWeight: number().positive().optional(),
15119
15377
  /** Node is eligible to run the detection pipeline (decode + inference). */
15120
15378
  detect: boolean().optional(),
15121
- /** Node is eligible to host decoder sessions. */
15379
+ /**
15380
+ * DEPRECATED AND IGNORED. Decode is always co-located with its frame
15381
+ * consumer, so decode eligibility IS detect eligibility. Kept optional in
15382
+ * the schema ONLY so persisted stores written before the removal still
15383
+ * parse — no code reads it and no write path emits it.
15384
+ */
15122
15385
  decode: boolean().optional(),
15123
15386
  /** Node is eligible to run audio-analyzer sessions. */
15124
15387
  audio: boolean().optional(),
15125
15388
  /** Node is eligible to be the ingest / source-owner (serve the restream). */
15126
- ingest: boolean().optional()
15389
+ ingest: boolean().optional(),
15390
+ /**
15391
+ * Operator override for the LAN host a cross-node decoder dials to reach
15392
+ * THIS node's restream (Cluster UI). Absent → auto-detect: a remote runner
15393
+ * falls back to its `CAMSTACK_HUB_URL`-derived host (the Moleculer address
15394
+ * it already uses to reach the hub). Set this only when the auto-detected
15395
+ * address is wrong (multi-homed host, NAT, custom interface).
15396
+ */
15397
+ reachableHost: string().optional()
15127
15398
  });
15128
15399
  var CameraPipelineForAgentSchema = object({
15129
15400
  steps: array(PipelineStepInputSchema).readonly(),
@@ -15171,25 +15442,6 @@ var PipelineAssignmentSchema = object({
15171
15442
  assignedAt: number()
15172
15443
  });
15173
15444
  /**
15174
- * Decoder placement record. Symmetric to `PipelineAssignmentSchema` but for
15175
- * the decoder-node placement domain (`balanceDecoder` decision: manual pin
15176
- * → co-located with pipeline → capacity).
15177
- */
15178
- var DecoderAssignmentSchema = object({
15179
- deviceId: number(),
15180
- /** Moleculer node id of the decoder provider currently responsible for this camera. */
15181
- decoderNodeId: string(),
15182
- /** True when the assignment was set manually via `assignDecoder`, false when chosen by the balancer. */
15183
- pinned: boolean(),
15184
- /** Why this assignment was made — useful for debugging the decoder balancer. */
15185
- reason: _enum([
15186
- "manual",
15187
- "co-located",
15188
- "capacity",
15189
- "hardware-affinity"
15190
- ])
15191
- });
15192
- /**
15193
15445
  * Per-agent load summary surfaced to the load balancer + dashboards.
15194
15446
  * Aggregated from each runner's `getLocalLoad` cap call.
15195
15447
  */
@@ -15229,6 +15481,15 @@ var GlobalMetricsSchema = object({
15229
15481
  * capability providers.
15230
15482
  */
15231
15483
  var CapabilityBindingsSchema = record(string(), string());
15484
+ /**
15485
+ * The cluster's single camera-source owner (`clusterRoles.ingestNode`) plus
15486
+ * its LAN-reachable host, if one is registered. See `getIngestOwner`.
15487
+ */
15488
+ var IngestOwnerSchema = object({
15489
+ ownerNodeId: string(),
15490
+ reachableHost: string().optional(),
15491
+ configIssue: string().optional()
15492
+ });
15232
15493
  /** Source block — always present; derives from the stream catalog. */
15233
15494
  var CameraSourceStatusSchema = object({ streams: array(object({
15234
15495
  camStreamId: string(),
@@ -15243,6 +15504,14 @@ var CameraAssignmentStatusSchema = object({
15243
15504
  detectionNodeId: string().nullable(),
15244
15505
  decoderNodeId: string().nullable(),
15245
15506
  audioNodeId: string().nullable(),
15507
+ /**
15508
+ * The node that OWNS this camera's physical source pull (dials the RTSP and
15509
+ * hosts the broker/restream) — the cluster ingest owner today
15510
+ * (`clusterRoles.ingestNode`), per-camera once source assignment lands. Lets
15511
+ * the UI show WHERE a camera is sourced without SSH/logs, and is the node the
15512
+ * broker block below was read from (pinned). Nullable only pre-wiring.
15513
+ */
15514
+ sourceNodeId: string().nullable(),
15246
15515
  pinned: object({
15247
15516
  detection: boolean(),
15248
15517
  decoder: boolean(),
@@ -15375,16 +15644,7 @@ method(object({
15375
15644
  }), object({ success: literal(true) }), {
15376
15645
  kind: "mutation",
15377
15646
  auth: "admin"
15378
- }), method(object({
15379
- deviceId: number(),
15380
- nodeId: string()
15381
- }), _void(), {
15382
- kind: "mutation",
15383
- auth: "admin"
15384
- }), method(object({ deviceId: number() }), _void(), {
15385
- kind: "mutation",
15386
- auth: "admin"
15387
- }), method(_void(), array(DecoderAssignmentSchema).readonly()), method(object({
15647
+ }), method(_void(), IngestOwnerSchema), method(object({
15388
15648
  deviceId: number(),
15389
15649
  nodeId: string()
15390
15650
  }), object({ success: literal(true) }), {
@@ -15405,10 +15665,7 @@ method(object({
15405
15665
  nodeId: string(),
15406
15666
  pinned: boolean(),
15407
15667
  assignedAt: number()
15408
- }))), method(object({
15409
- deviceId: number(),
15410
- pipelineNodeId: string().optional()
15411
- }), DecoderAssignmentSchema), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
15668
+ }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
15412
15669
  nodeId: string(),
15413
15670
  settings: AgentPipelineSettingsSchema
15414
15671
  })).readonly()), method(object({
@@ -15438,12 +15695,26 @@ method(object({
15438
15695
  }), method(object({
15439
15696
  agentNodeId: string(),
15440
15697
  detect: boolean().nullable().optional(),
15441
- decode: boolean().nullable().optional(),
15442
15698
  audio: boolean().nullable().optional(),
15443
15699
  ingest: boolean().nullable().optional()
15444
15700
  }), object({ success: literal(true) }), {
15445
15701
  kind: "mutation",
15446
15702
  auth: "admin"
15703
+ }), method(object({
15704
+ agentNodeId: string(),
15705
+ reachableHost: string().nullable()
15706
+ }), object({ success: literal(true) }), {
15707
+ kind: "mutation",
15708
+ auth: "admin"
15709
+ }), method(object({ agentNodeId: string() }), object({
15710
+ success: literal(true),
15711
+ /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
15712
+ effectiveModelId: string().nullable(),
15713
+ /** Number of cameras whose node-scoped overrides were cleared. */
15714
+ clearedCameraOverrides: number()
15715
+ }), {
15716
+ kind: "mutation",
15717
+ auth: "admin"
15447
15718
  }), method(object({ deviceId: number() }), CameraPipelineSettingsSchema.nullable()), method(object({
15448
15719
  deviceId: number(),
15449
15720
  addonId: string(),
@@ -15488,22 +15759,131 @@ method(object({
15488
15759
  kind: "mutation",
15489
15760
  auth: "admin"
15490
15761
  });
15491
- var RegisteredStreamSchema = object({
15492
- streamId: string(),
15493
- label: string().optional(),
15494
- codec: string(),
15495
- type: _enum(["video", "audio"]),
15496
- sourceUrl: string()
15762
+ /**
15763
+ * server-management — per-NODE singleton capability for a node's ROOT
15764
+ * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
15765
+ * agents).
15766
+ *
15767
+ * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
15768
+ * on agents) carries the whole software stack in its npm dep tree, so ONE
15769
+ * version describes the node. Updates install into
15770
+ * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
15771
+ * starter (probation boot + auto-rollback to N-1).
15772
+ *
15773
+ * Providers:
15774
+ * - HUB: `ServerUpdateService` behind the `server-provided` mount
15775
+ * (`buildServerProviders` in trpc.router.ts) — the default target for
15776
+ * unpinned calls.
15777
+ * - AGENT: `AgentUpdateService` registered by the agent bootstrap under
15778
+ * the synthetic `agent-runtime` addonId and declared in the agent's
15779
+ * `$hub.registerNode` manifest.
15780
+ *
15781
+ * Node routing: singleton caps get the codegen/runtime-builder `nodeId`
15782
+ * injection on every method — `input.nodeId` (or `nodePin(nodeId)` from the
15783
+ * SDK) routes the call to that node's provider via the standard remote
15784
+ * proxy (`createCapabilityProxy` → `$agent-cap-fwd` → the agent's
15785
+ * in-process provider lookup). No `nodeId` → the hub's own provider.
15786
+ *
15787
+ * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md
15788
+ */
15789
+ /**
15790
+ * Where the running hub's code was loaded from:
15791
+ * - `workspace` — dev checkout (tsx / workspace dist); the starter defers to
15792
+ * plain resolution and runtime updates are refused.
15793
+ * - `baked` — the immutable image seed closure (no data-dir root active).
15794
+ * - `data-root` — the runtime-updatable `<dataDir>/server-root` closure.
15795
+ */
15796
+ var ServerBootModeSchema = _enum([
15797
+ "workspace",
15798
+ "baked",
15799
+ "data-root"
15800
+ ]);
15801
+ /**
15802
+ * Update lifecycle state:
15803
+ * - `idle` / `checking` / `staging` — steady / in-flight registry work.
15804
+ * - `pending-restart` — a version is staged and the node has NOT yet
15805
+ * restarted onto it (still running the OLD version).
15806
+ * - `awaiting-confirmation` — the node HAS restarted onto the staged version
15807
+ * (it is the active probation boot) and is waiting to confirm boot-health.
15808
+ * Apply/rollback are refused in this state and the node must NOT be
15809
+ * manually restarted, or the probation boot auto-rolls-back.
15810
+ */
15811
+ var ServerUpdateStateSchema = _enum([
15812
+ "idle",
15813
+ "checking",
15814
+ "staging",
15815
+ "pending-restart",
15816
+ "awaiting-confirmation"
15817
+ ]);
15818
+ var ServerRollbackInfoSchema = object({
15819
+ /** The version that failed (or was manually rolled back). */
15820
+ fromVersion: string(),
15821
+ /** The version rolled back to; null = the baked seed. */
15822
+ toVersion: string().nullable(),
15823
+ atMs: number(),
15824
+ reason: string()
15497
15825
  });
15498
- var ExposedResourceSchema = object({
15499
- streamId: string(),
15500
- format: string(),
15501
- value: string()
15826
+ var ServerPackageStatusSchema = object({
15827
+ /** Root package name (`@camstack/server` on the hub). */
15828
+ packageName: string(),
15829
+ /** Version of the code the running process ACTUALLY loaded. */
15830
+ runningVersion: string().nullable(),
15831
+ /** Node.js runtime version the node's process runs on (`process.versions.node`). */
15832
+ nodeRuntimeVersion: string().nullable(),
15833
+ /** Active data-dir root version; null when booted from seed/workspace. */
15834
+ activeVersion: string().nullable(),
15835
+ /** N-1 version kept for rollback; null when no previous version exists. */
15836
+ previousVersion: string().nullable(),
15837
+ /** Version of the immutable baked seed closure (image fallback). */
15838
+ seedVersion: string().nullable(),
15839
+ /** Latest registry version from the most recent check (null = never checked). */
15840
+ latestVersion: string().nullable(),
15841
+ updateAvailable: boolean(),
15842
+ bootMode: ServerBootModeSchema,
15843
+ updateState: ServerUpdateStateSchema,
15844
+ /** Version staged + awaiting its probation boot, when one is pending. */
15845
+ pendingVersion: string().nullable(),
15846
+ /** Set when the last freshly-activated version failed its boot health-check. */
15847
+ rolledBack: ServerRollbackInfoSchema.nullable(),
15848
+ /**
15849
+ * True when `server-root/state.json` EXISTS but is unreadable/corrupt — the
15850
+ * hub is running from the baked seed (or workspace) while installed data-dir
15851
+ * versions are being IGNORED. Surfaced as a warning in the UI.
15852
+ */
15853
+ stateFileCorrupt: boolean(),
15854
+ lastCheckedAtMs: number().nullable()
15855
+ });
15856
+ var ServerUpdateCheckResultSchema = object({
15857
+ packageName: string(),
15858
+ runningVersion: string().nullable(),
15859
+ latestVersion: string().nullable(),
15860
+ updateAvailable: boolean(),
15861
+ checkedAtMs: number(),
15862
+ /** Non-null when the registry lookup failed (offline, bad registry, …). */
15863
+ error: string().nullable()
15864
+ });
15865
+ var ServerUpdateActionResultSchema = object({
15866
+ accepted: boolean(),
15867
+ targetVersion: string().nullable(),
15868
+ /** True when a graceful restart was scheduled to apply the change. */
15869
+ restarting: boolean(),
15870
+ message: string()
15871
+ });
15872
+ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
15873
+ kind: "mutation",
15874
+ auth: "admin"
15875
+ }), method(object({
15876
+ /** Explicit target version; omitted = latest from the registry. */
15877
+ version: string().optional() }), ServerUpdateActionResultSchema, {
15878
+ kind: "mutation",
15879
+ auth: "admin"
15880
+ }), method(_void(), ServerUpdateActionResultSchema, {
15881
+ kind: "mutation",
15882
+ auth: "admin"
15883
+ }), method(_void(), ServerUpdateActionResultSchema, {
15884
+ kind: "mutation",
15885
+ auth: "admin"
15502
15886
  });
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
15887
  /**
15508
15888
  * Query filter for settings-store collections.
15509
15889
  */
@@ -15656,9 +16036,9 @@ method(SendEmailInputSchema, SendEmailResultSchema, {
15656
16036
  /**
15657
16037
  * A single device snapshot returned as base64 JPEG/PNG.
15658
16038
  *
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.
16039
+ * The `SnapshotAddon` wrapper returns this shape whether the frame came from
16040
+ * the device-native provider (onboard capture) or from the stream-broker
16041
+ * prebuffer fallback.
15662
16042
  */
15663
16043
  var SnapshotImageSchema = object({
15664
16044
  base64: string(),
@@ -15689,11 +16069,12 @@ DeviceType.Camera, method(object({
15689
16069
  }), SnapshotImageSchema.nullable()), method(object({ deviceId: number() }), _void(), {
15690
16070
  kind: "mutation",
15691
16071
  auth: "admin"
15692
- });
15693
- method(object({ deviceId: number() }), boolean()), method(object({
16072
+ }), systemMethod(object({ deviceIds: array(number()).min(1).max(200) }), array(object({
15694
16073
  deviceId: number(),
15695
- streamId: string().optional()
15696
- }), SnapshotImageSchema.nullable());
16074
+ lastCapturedAt: number().nullable(),
16075
+ cacheAgeMs: number().nullable(),
16076
+ etag: string().nullable()
16077
+ })));
15697
16078
  /**
15698
16079
  * `sso-bridge` — internal hub-only cap that lets SSO-style auth
15699
16080
  * providers (OIDC, SAML, magic-link, …) mint an HMAC-signed token
@@ -15944,10 +16325,32 @@ method(_void(), array(TurnServerSchema).readonly());
15944
16325
  * b. `finishAuthentication({userId, response})` → server verifies
15945
16326
  * the assertion, bumps the credential counter, returns ok.
15946
16327
  *
16328
+ * 2b. Usernameless (discoverable-credential) authentication — the
16329
+ * passkey IS the primary factor, no password leg:
16330
+ * a. `beginDiscoverableAuthentication({})` → assertion options with
16331
+ * EMPTY `allowCredentials` (the browser offers every resident
16332
+ * passkey it holds for this RP) + `userVerification: 'required'`
16333
+ * (the passkey replaces both factors, so UV is mandatory).
16334
+ * The challenge is stored server-side, NOT bound to any user.
16335
+ * b. `finishDiscoverableAuthentication({response})` → the provider
16336
+ * resolves the credential by the response's credential id,
16337
+ * verifies the assertion against the stored challenge + that
16338
+ * credential's public key/counter, and returns the OWNING
16339
+ * `userId` — the caller (core auth router) mints the session.
16340
+ *
15947
16341
  * 3. Management:
15948
16342
  * - `listPasskeys({userId})` — enumerate user's enrolled credentials.
15949
16343
  * - `removePasskey({userId, credentialId})` — revoke one credential.
15950
16344
  *
16345
+ * 4. Second-factor preference (opt-in, default OFF):
16346
+ * Enrolling a passkey only enables passkey-FIRST sign-in. It is
16347
+ * demanded as a second factor after a password login ONLY when the
16348
+ * user explicitly opts in via `setSecondFactorPreference`.
16349
+ * - `getSecondFactorPreference({userId})` → `{ enabled }` (missing
16350
+ * row ⇒ `enabled: false`).
16351
+ * - `setSecondFactorPreference({userId, enabled})` — persisted by
16352
+ * the providing addon beside its credentials.
16353
+ *
15951
16354
  * Challenges are short-lived (5 min, in-memory). The cap is internal —
15952
16355
  * the admin-ui composes the begin/finish round-trip and never exposes
15953
16356
  * the cap to non-admins.
@@ -15990,6 +16393,17 @@ method(object({
15990
16393
  }), object({ verified: boolean() }), {
15991
16394
  kind: "mutation",
15992
16395
  access: "view"
16396
+ }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
16397
+ kind: "mutation",
16398
+ access: "view"
16399
+ }), method(object({
16400
+ /** AuthenticationResponseJSON from the browser. */
16401
+ response: record(string(), unknown()) }), object({
16402
+ verified: boolean(),
16403
+ userId: string().nullable()
16404
+ }), {
16405
+ kind: "mutation",
16406
+ access: "view"
15993
16407
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
15994
16408
  userId: string(),
15995
16409
  credentialId: string()
@@ -15997,6 +16411,13 @@ method(object({
15997
16411
  kind: "mutation",
15998
16412
  auth: "admin",
15999
16413
  access: "delete"
16414
+ }), method(object({ userId: string() }), object({ enabled: boolean() }), { auth: "admin" }), method(object({
16415
+ userId: string(),
16416
+ enabled: boolean()
16417
+ }), object({ success: literal(true) }), {
16418
+ kind: "mutation",
16419
+ auth: "admin",
16420
+ access: "create"
16000
16421
  });
16001
16422
  /**
16002
16423
  * `videoclips` — the unified, navigable-clip surface for a camera.
@@ -16054,9 +16475,10 @@ method(object({
16054
16475
  auth: "admin"
16055
16476
  });
16056
16477
  /**
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.
16478
+ * Optional client-side hints sent at session creation to help the provider
16479
+ * pick the best native source. All fields optional — a viewer that knows
16480
+ * nothing still gets a sane default. (Relocated from the retired `webrtc`
16481
+ * collection cap; this `webrtc-session` cap is the live signaling surface.)
16060
16482
  */
16061
16483
  var webrtcClientHintsSchema = object({
16062
16484
  viewportWidth: number().int().positive().optional(),
@@ -16067,22 +16489,6 @@ var webrtcClientHintsSchema = object({
16067
16489
  /** Hard tier override; takes precedence over scoring when registered. */
16068
16490
  prefersTier: string().optional()
16069
16491
  }).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
16492
  /**
16087
16493
  * Discriminated target for a WebRTC session. The client sends this
16088
16494
  * structured object instead of building / parsing brokerId strings;
@@ -16813,7 +17219,17 @@ var FaceInfoSchema = object({
16813
17219
  recognizedIdentityId: string().optional(),
16814
17220
  identityName: string().optional(),
16815
17221
  assigned: boolean(),
16816
- base64: string().optional()
17222
+ base64: string().optional(),
17223
+ /** Design B: the face bbox (pixel space) on the key frame — lets a detail
17224
+ * view draw the box over the native `keyFrameMediaKey` frame. Absent on
17225
+ * legacy rows written before design B. */
17226
+ faceBbox: BoundingBoxSchema.optional(),
17227
+ /** Design B: MediaStore key of the track's native-resolution key frame.
17228
+ * Fetch the native JPEG via the event-media data-plane
17229
+ * (`/addon/<addonId>/event-media/<keyFrameMediaKey>`). Absent when the
17230
+ * track produced no key frame (e.g. native/onboard source) — the UI falls
17231
+ * back to the inline `base64` face crop. */
17232
+ keyFrameMediaKey: string().optional()
16817
17233
  });
16818
17234
  var FaceFilterEnum = _enum([
16819
17235
  "unassigned",
@@ -17510,6 +17926,16 @@ var TopologyCategorySchema = object({
17510
17926
  healthy: number(),
17511
17927
  addons: array(TopologyCategoryAddonSchema).readonly()
17512
17928
  });
17929
+ /**
17930
+ * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
17931
+ * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
17932
+ * version visibility for the Server management surface. Nullable: offline
17933
+ * rows and pre-phase-2 nodes report none.
17934
+ */
17935
+ var TopologyRootPackageSchema = object({
17936
+ name: string(),
17937
+ version: string()
17938
+ });
17513
17939
  var TopologyNodeSchema = object({
17514
17940
  id: string(),
17515
17941
  name: string(),
@@ -17533,7 +17959,8 @@ var TopologyNodeSchema = object({
17533
17959
  status: string()
17534
17960
  })).readonly(),
17535
17961
  processes: array(TopologyProcessSchema).readonly(),
17536
- categories: array(TopologyCategorySchema).readonly()
17962
+ categories: array(TopologyCategorySchema).readonly(),
17963
+ rootPackage: TopologyRootPackageSchema.nullable()
17537
17964
  });
17538
17965
  var CapUsageEdgeSchema = object({
17539
17966
  callerAddonId: string(),
@@ -20333,6 +20760,12 @@ Object.freeze({
20333
20760
  addonId: null,
20334
20761
  access: "create"
20335
20762
  },
20763
+ "loginMethod.getLoginMethods": {
20764
+ capName: "login-method",
20765
+ capScope: "system",
20766
+ addonId: null,
20767
+ access: "view"
20768
+ },
20336
20769
  "mediaPlayer.next": {
20337
20770
  capName: "media-player",
20338
20771
  capScope: "device",
@@ -20915,6 +21348,12 @@ Object.freeze({
20915
21348
  addonId: null,
20916
21349
  access: "view"
20917
21350
  },
21351
+ "pipelineAnalytics.getKeyEvents": {
21352
+ capName: "pipeline-analytics",
21353
+ capScope: "device",
21354
+ addonId: null,
21355
+ access: "view"
21356
+ },
20918
21357
  "pipelineAnalytics.getMotionEvents": {
20919
21358
  capName: "pipeline-analytics",
20920
21359
  capScope: "device",
@@ -20963,23 +21402,23 @@ Object.freeze({
20963
21402
  addonId: null,
20964
21403
  access: "create"
20965
21404
  },
20966
- "pipelineExecutor.deleteModel": {
21405
+ "pipelineExecutor.clearDeviceOverrides": {
20967
21406
  capName: "pipeline-executor",
20968
21407
  capScope: "system",
20969
21408
  addonId: null,
20970
21409
  access: "delete"
20971
21410
  },
20972
- "pipelineExecutor.deleteTemplate": {
21411
+ "pipelineExecutor.deleteModel": {
20973
21412
  capName: "pipeline-executor",
20974
21413
  capScope: "system",
20975
21414
  addonId: null,
20976
21415
  access: "delete"
20977
21416
  },
20978
- "pipelineExecutor.detect": {
21417
+ "pipelineExecutor.deleteTemplate": {
20979
21418
  capName: "pipeline-executor",
20980
21419
  capScope: "system",
20981
21420
  addonId: null,
20982
- access: "view"
21421
+ access: "delete"
20983
21422
  },
20984
21423
  "pipelineExecutor.downloadModel": {
20985
21424
  capName: "pipeline-executor",
@@ -21173,13 +21612,13 @@ Object.freeze({
21173
21612
  addonId: null,
21174
21613
  access: "create"
21175
21614
  },
21176
- "pipelineOrchestrator.assignAudio": {
21177
- capName: "pipeline-orchestrator",
21615
+ "pipelineExecutor.validatePipeline": {
21616
+ capName: "pipeline-executor",
21178
21617
  capScope: "system",
21179
21618
  addonId: null,
21180
- access: "create"
21619
+ access: "view"
21181
21620
  },
21182
- "pipelineOrchestrator.assignDecoder": {
21621
+ "pipelineOrchestrator.assignAudio": {
21183
21622
  capName: "pipeline-orchestrator",
21184
21623
  capScope: "system",
21185
21624
  addonId: null,
@@ -21263,19 +21702,13 @@ Object.freeze({
21263
21702
  addonId: null,
21264
21703
  access: "view"
21265
21704
  },
21266
- "pipelineOrchestrator.getDecoderAssignment": {
21267
- capName: "pipeline-orchestrator",
21268
- capScope: "system",
21269
- addonId: null,
21270
- access: "view"
21271
- },
21272
- "pipelineOrchestrator.getDecoderAssignments": {
21705
+ "pipelineOrchestrator.getGlobalMetrics": {
21273
21706
  capName: "pipeline-orchestrator",
21274
21707
  capScope: "system",
21275
21708
  addonId: null,
21276
21709
  access: "view"
21277
21710
  },
21278
- "pipelineOrchestrator.getGlobalMetrics": {
21711
+ "pipelineOrchestrator.getIngestOwner": {
21279
21712
  capName: "pipeline-orchestrator",
21280
21713
  capScope: "system",
21281
21714
  addonId: null,
@@ -21317,6 +21750,12 @@ Object.freeze({
21317
21750
  addonId: null,
21318
21751
  access: "delete"
21319
21752
  },
21753
+ "pipelineOrchestrator.resetNodePipelineDefaults": {
21754
+ capName: "pipeline-orchestrator",
21755
+ capScope: "system",
21756
+ addonId: null,
21757
+ access: "delete"
21758
+ },
21320
21759
  "pipelineOrchestrator.resolvePipeline": {
21321
21760
  capName: "pipeline-orchestrator",
21322
21761
  capScope: "system",
@@ -21353,37 +21792,37 @@ Object.freeze({
21353
21792
  addonId: null,
21354
21793
  access: "create"
21355
21794
  },
21356
- "pipelineOrchestrator.setCameraPipelineForAgent": {
21795
+ "pipelineOrchestrator.setAgentReachableHost": {
21357
21796
  capName: "pipeline-orchestrator",
21358
21797
  capScope: "system",
21359
21798
  addonId: null,
21360
21799
  access: "create"
21361
21800
  },
21362
- "pipelineOrchestrator.setCameraStepOverride": {
21801
+ "pipelineOrchestrator.setCameraPipelineForAgent": {
21363
21802
  capName: "pipeline-orchestrator",
21364
21803
  capScope: "system",
21365
21804
  addonId: null,
21366
21805
  access: "create"
21367
21806
  },
21368
- "pipelineOrchestrator.setCameraStepToggle": {
21807
+ "pipelineOrchestrator.setCameraStepOverride": {
21369
21808
  capName: "pipeline-orchestrator",
21370
21809
  capScope: "system",
21371
21810
  addonId: null,
21372
21811
  access: "create"
21373
21812
  },
21374
- "pipelineOrchestrator.setCapabilityBinding": {
21813
+ "pipelineOrchestrator.setCameraStepToggle": {
21375
21814
  capName: "pipeline-orchestrator",
21376
21815
  capScope: "system",
21377
21816
  addonId: null,
21378
21817
  access: "create"
21379
21818
  },
21380
- "pipelineOrchestrator.unassignAudio": {
21819
+ "pipelineOrchestrator.setCapabilityBinding": {
21381
21820
  capName: "pipeline-orchestrator",
21382
21821
  capScope: "system",
21383
21822
  addonId: null,
21384
21823
  access: "create"
21385
21824
  },
21386
- "pipelineOrchestrator.unassignDecoder": {
21825
+ "pipelineOrchestrator.unassignAudio": {
21387
21826
  capName: "pipeline-orchestrator",
21388
21827
  capScope: "system",
21389
21828
  addonId: null,
@@ -21443,6 +21882,12 @@ Object.freeze({
21443
21882
  addonId: null,
21444
21883
  access: "view"
21445
21884
  },
21885
+ "pipelineRunner.getNativeCrop": {
21886
+ capName: "pipeline-runner",
21887
+ capScope: "system",
21888
+ addonId: null,
21889
+ access: "view"
21890
+ },
21446
21891
  "pipelineRunner.reportMotion": {
21447
21892
  capName: "pipeline-runner",
21448
21893
  capScope: "system",
@@ -21683,33 +22128,45 @@ Object.freeze({
21683
22128
  addonId: null,
21684
22129
  access: "create"
21685
22130
  },
21686
- "restreamer.getExposedResources": {
21687
- capName: "restreamer",
22131
+ "scriptRunner.run": {
22132
+ capName: "script-runner",
22133
+ capScope: "device",
22134
+ addonId: null,
22135
+ access: "create"
22136
+ },
22137
+ "scriptRunner.stop": {
22138
+ capName: "script-runner",
22139
+ capScope: "device",
22140
+ addonId: null,
22141
+ access: "create"
22142
+ },
22143
+ "serverManagement.applyServerUpdate": {
22144
+ capName: "server-management",
21688
22145
  capScope: "system",
21689
22146
  addonId: null,
21690
- access: "view"
22147
+ access: "create"
21691
22148
  },
21692
- "restreamer.registerDevice": {
21693
- capName: "restreamer",
22149
+ "serverManagement.checkServerUpdate": {
22150
+ capName: "server-management",
21694
22151
  capScope: "system",
21695
22152
  addonId: null,
21696
22153
  access: "create"
21697
22154
  },
21698
- "restreamer.unregisterDevice": {
21699
- capName: "restreamer",
22155
+ "serverManagement.getServerPackageStatus": {
22156
+ capName: "server-management",
21700
22157
  capScope: "system",
21701
22158
  addonId: null,
21702
- access: "delete"
22159
+ access: "view"
21703
22160
  },
21704
- "scriptRunner.run": {
21705
- capName: "script-runner",
21706
- capScope: "device",
22161
+ "serverManagement.restartServer": {
22162
+ capName: "server-management",
22163
+ capScope: "system",
21707
22164
  addonId: null,
21708
22165
  access: "create"
21709
22166
  },
21710
- "scriptRunner.stop": {
21711
- capName: "script-runner",
21712
- capScope: "device",
22167
+ "serverManagement.rollbackServerUpdate": {
22168
+ capName: "server-management",
22169
+ capScope: "system",
21713
22170
  addonId: null,
21714
22171
  access: "create"
21715
22172
  },
@@ -21797,23 +22254,17 @@ Object.freeze({
21797
22254
  addonId: null,
21798
22255
  access: "view"
21799
22256
  },
21800
- "snapshot.invalidateCache": {
22257
+ "snapshot.getSnapshotOverview": {
21801
22258
  capName: "snapshot",
21802
22259
  capScope: "device",
21803
22260
  addonId: null,
21804
- access: "create"
21805
- },
21806
- "snapshotProvider.getSnapshot": {
21807
- capName: "snapshot-provider",
21808
- capScope: "system",
21809
- addonId: null,
21810
22261
  access: "view"
21811
22262
  },
21812
- "snapshotProvider.supportsDevice": {
21813
- capName: "snapshot-provider",
21814
- capScope: "system",
22263
+ "snapshot.invalidateCache": {
22264
+ capName: "snapshot",
22265
+ capScope: "device",
21815
22266
  addonId: null,
21816
- access: "view"
22267
+ access: "create"
21817
22268
  },
21818
22269
  "ssoBridge.signBridgeToken": {
21819
22270
  capName: "sso-bridge",
@@ -22241,30 +22692,6 @@ Object.freeze({
22241
22692
  addonId: null,
22242
22693
  access: "view"
22243
22694
  },
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
22695
  "streamParams.getConfigSchema": {
22269
22696
  capName: "stream-params",
22270
22697
  capScope: "device",
@@ -22511,6 +22938,12 @@ Object.freeze({
22511
22938
  addonId: null,
22512
22939
  access: "view"
22513
22940
  },
22941
+ "userPasskeys.beginDiscoverableAuthentication": {
22942
+ capName: "user-passkeys",
22943
+ capScope: "system",
22944
+ addonId: null,
22945
+ access: "view"
22946
+ },
22514
22947
  "userPasskeys.beginRegistration": {
22515
22948
  capName: "user-passkeys",
22516
22949
  capScope: "system",
@@ -22523,12 +22956,24 @@ Object.freeze({
22523
22956
  addonId: null,
22524
22957
  access: "view"
22525
22958
  },
22959
+ "userPasskeys.finishDiscoverableAuthentication": {
22960
+ capName: "user-passkeys",
22961
+ capScope: "system",
22962
+ addonId: null,
22963
+ access: "view"
22964
+ },
22526
22965
  "userPasskeys.finishRegistration": {
22527
22966
  capName: "user-passkeys",
22528
22967
  capScope: "system",
22529
22968
  addonId: null,
22530
22969
  access: "create"
22531
22970
  },
22971
+ "userPasskeys.getSecondFactorPreference": {
22972
+ capName: "user-passkeys",
22973
+ capScope: "system",
22974
+ addonId: null,
22975
+ access: "view"
22976
+ },
22532
22977
  "userPasskeys.listPasskeys": {
22533
22978
  capName: "user-passkeys",
22534
22979
  capScope: "system",
@@ -22541,6 +22986,12 @@ Object.freeze({
22541
22986
  addonId: null,
22542
22987
  access: "delete"
22543
22988
  },
22989
+ "userPasskeys.setSecondFactorPreference": {
22990
+ capName: "user-passkeys",
22991
+ capScope: "system",
22992
+ addonId: null,
22993
+ access: "create"
22994
+ },
22544
22995
  "vacuumControl.locate": {
22545
22996
  capName: "vacuum-control",
22546
22997
  capScope: "device",
@@ -22613,6 +23064,18 @@ Object.freeze({
22613
23064
  addonId: null,
22614
23065
  access: "view"
22615
23066
  },
23067
+ "viewerUi.getStaticDir": {
23068
+ capName: "viewer-ui",
23069
+ capScope: "system",
23070
+ addonId: null,
23071
+ access: "view"
23072
+ },
23073
+ "viewerUi.getVersion": {
23074
+ capName: "viewer-ui",
23075
+ capScope: "system",
23076
+ addonId: null,
23077
+ access: "view"
23078
+ },
22616
23079
  "waterHeater.setAway": {
22617
23080
  capName: "water-heater",
22618
23081
  capScope: "device",
@@ -22631,54 +23094,6 @@ Object.freeze({
22631
23094
  addonId: null,
22632
23095
  access: "create"
22633
23096
  },
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
23097
  "webrtcSession.addIceCandidate": {
22683
23098
  capName: "webrtc-session",
22684
23099
  capScope: "device",
@@ -22849,7 +23264,7 @@ var AgentUIAddon = class extends BaseAddon {
22849
23264
  capability: adminUiCapability,
22850
23265
  provider: {
22851
23266
  getStaticDir: async () => ({ staticDir: path.resolve(__dirname) }),
22852
- getVersion: async () => ({ version: "1.1.20" })
23267
+ getVersion: async () => ({ version: "1.1.22" })
22853
23268
  }
22854
23269
  }];
22855
23270
  }