@camstack/addon-agent-ui 1.1.20 → 1.1.21

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-DJaTV2D7.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,21 @@ 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
+ var StaticDirOutputSchema$1 = object({ staticDir: string() });
6737
+ var VersionOutputSchema$1 = object({ version: string() });
6730
6738
  var adminUiCapability = {
6731
6739
  name: "admin-ui",
6732
6740
  scope: "system",
6733
6741
  mode: "singleton",
6734
6742
  internal: true,
6735
6743
  methods: {
6736
- getStaticDir: method(_void(), StaticDirOutputSchema),
6737
- getVersion: method(_void(), VersionOutputSchema)
6744
+ getStaticDir: method(_void(), StaticDirOutputSchema$1),
6745
+ getVersion: method(_void(), VersionOutputSchema$1)
6738
6746
  }
6739
6747
  };
6748
+ var StaticDirOutputSchema = object({ staticDir: string() });
6749
+ var VersionOutputSchema = object({ version: string() });
6750
+ method(_void(), StaticDirOutputSchema), method(_void(), VersionOutputSchema);
6740
6751
  /**
6741
6752
  * device-ops — device-scoped cap that unifies the per-IDevice operations
6742
6753
  * previously routed through the `.device-ops` Moleculer bridge service.
@@ -6903,6 +6914,36 @@ var ModelFormatsSchema = object({
6903
6914
  tflite: ModelFormatEntrySchema.optional(),
6904
6915
  pt: ModelFormatEntrySchema.optional()
6905
6916
  });
6917
+ /**
6918
+ * Variant-selector grouping axes. Shared by the full `ModelCatalogEntry` and by
6919
+ * the reduced `PipelineModelOption` returned in `pipeline.getSchema()` so the
6920
+ * grouped Family→Tier→Variant picker renders identically in the config UI and
6921
+ * in the pipeline/device steppers. The flat `id` stays the source of truth for
6922
+ * resolution/download/persistence; this is a presentation overlay resolved back
6923
+ * to an `id`.
6924
+ */
6925
+ var ModelVariantGroupSchema = object({
6926
+ /** Top-level family, e.g. `yolo26` (later `d-fine`, `rf-detr`). */
6927
+ family: string(),
6928
+ /** Size within the family, e.g. `n` | `s` | `m` | `l`. */
6929
+ tier: string(),
6930
+ /** Quantization axis. Omit ⇒ the fp32 base build. */
6931
+ precision: _enum(["fp32", "int8"]).optional(),
6932
+ /**
6933
+ * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
6934
+ * latency-optimized export (e.g. ReLU-activation variant) — the slot the
6935
+ * future performance variants plug into.
6936
+ */
6937
+ optimization: _enum(["standard", "fast"]).optional(),
6938
+ /**
6939
+ * Input-resolution axis (square input side, px). Omit ⇒ the family's native
6940
+ * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
6941
+ * cheap latency lever — especially on Apple ANE and the Intel N100 — at a
6942
+ * small-object accuracy cost. Mirrors the model's `inputSize` but lifted onto
6943
+ * the group so the selector can offer it as a variant axis.
6944
+ */
6945
+ resolution: number().int().positive().optional()
6946
+ });
6906
6947
  var ModelCatalogEntrySchema = object({
6907
6948
  id: string(),
6908
6949
  name: string(),
@@ -6932,7 +6973,43 @@ var ModelCatalogEntrySchema = object({
6932
6973
  * Auxiliary files required at runtime (labels JSON, charset dict, etc.).
6933
6974
  * Downloaded into the same modelsDir alongside the model file.
6934
6975
  */
6935
- extraFiles: array(ModelExtraFileSchema).readonly().optional()
6976
+ extraFiles: array(ModelExtraFileSchema).readonly().optional(),
6977
+ /**
6978
+ * LEGACY entry — retained in the catalog so a persisted operator selection
6979
+ * still RESOLVES (and can be re-activated), but hidden from the selectable
6980
+ * model list and excluded from the auto format-default pick. Set on the
6981
+ * superseded / consolidated models (older lineages, redundant fp16 IRs) so
6982
+ * the active lineup stays the coherent curated ladder without deleting a
6983
+ * model anyone may still be pinned to. `resolveModelForFormat` keeps honoring
6984
+ * an explicit legacy id that has a build for the node's format.
6985
+ */
6986
+ legacy: boolean().optional(),
6987
+ /**
6988
+ * Measured quality/latency metadata — populated from the benchmark addon on
6989
+ * the real node classes. Absent = not yet measured (most entries today; the
6990
+ * catalog historically carried only `sizeMB`, a poor cross-architecture
6991
+ * speed proxy). `p95LatencyMs` is keyed by node class (e.g. `n100`, `mac`).
6992
+ */
6993
+ metrics: object({
6994
+ map50: number().optional(),
6995
+ p95LatencyMs: record(string(), number()).optional()
6996
+ }).optional(),
6997
+ /**
6998
+ * SPDX-ish license id of the model weights (e.g. `AGPL-3.0` for Ultralytics
6999
+ * YOLO26, `GPL-3.0` for YOLOv9, `Apache-2.0` for D-FINE/RF-DETR). Matters for
7000
+ * the retraining addon and any future commercial distribution.
7001
+ */
7002
+ license: string().optional(),
7003
+ /**
7004
+ * Variant-selector grouping. The UI groups models by `family` + `tier` and
7005
+ * offers `precision` / `optimization` as variant axes WITHIN a tier — so all
7006
+ * of a family's sizes and quantizations collapse into one grouped picker
7007
+ * instead of a flat list of `yolo26s`, `yolo26s-int8`, … Absent ⇒ ungrouped
7008
+ * (legacy / custom models) — never shown in the grouped selector. The flat
7009
+ * `id` stays the source of truth for resolution/download/persistence; grouping
7010
+ * is a presentation overlay resolved back to an `id`.
7011
+ */
7012
+ group: ModelVariantGroupSchema.optional()
6936
7013
  });
6937
7014
  var ConvertTargetSchema = discriminatedUnion("format", [object({
6938
7015
  format: literal("openvino"),
@@ -6993,8 +7070,8 @@ var RecordingModeSchema = _enum([
6993
7070
  "onAudioThreshold"
6994
7071
  ]);
6995
7072
  /**
6996
- * First-class, authoritative per-camera storage mode — the netta choice the UI
6997
- * reads directly (never inferred from `rules`):
7073
+ * First-class, authoritative per-camera storage mode — the explicit choice the
7074
+ * UI reads directly (never inferred from `rules`):
6998
7075
  * - `off` — not recording.
6999
7076
  * - `events` — record only around triggers (motion / audio threshold),
7000
7077
  * with pre/post-buffer.
@@ -8642,26 +8719,13 @@ DeviceType.Light, method(object({
8642
8719
  percentage: number().min(0).max(100),
8643
8720
  lastChangedAt: number()
8644
8721
  });
8722
+ /** Stream delivery format. (Relocated from the retired `streaming-engine` cap.) */
8645
8723
  var StreamFormatSchema = _enum([
8646
8724
  "webrtc",
8647
8725
  "hls",
8648
8726
  "mjpeg",
8649
8727
  "rtsp"
8650
8728
  ]);
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
8729
  var RtspRestreamEntrySchema = object({
8666
8730
  brokerId: string(),
8667
8731
  url: string(),
@@ -9326,7 +9390,7 @@ var ConsumablesStatusSchema = object({
9326
9390
  })),
9327
9391
  lastChangedAt: number()
9328
9392
  });
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({
9393
+ Object.values(DeviceType), method(object({
9330
9394
  deviceId: number().int().nonnegative(),
9331
9395
  key: string().min(1)
9332
9396
  }), _void(), {
@@ -10241,7 +10305,7 @@ var BoundingBoxSchema = object({
10241
10305
  w: number(),
10242
10306
  h: number()
10243
10307
  });
10244
- var SpatialDetectionSchema = object({
10308
+ object({
10245
10309
  class: string(),
10246
10310
  originalClass: string(),
10247
10311
  score: number(),
@@ -10376,7 +10440,6 @@ var PipelineDefaultStepSchema = lazy(() => object({
10376
10440
  enabled: boolean(),
10377
10441
  modelId: string(),
10378
10442
  children: array(PipelineDefaultStepSchema).readonly(),
10379
- engine: PipelineEngineChoiceSchema.optional(),
10380
10443
  group: string().optional(),
10381
10444
  settings: record(string(), unknown()).optional()
10382
10445
  }));
@@ -10401,7 +10464,9 @@ var PipelineModelOptionSchema = object({
10401
10464
  formats: record(string(), object({
10402
10465
  downloaded: boolean(),
10403
10466
  sizeMB: number()
10404
- }))
10467
+ })),
10468
+ group: ModelVariantGroupSchema.optional(),
10469
+ legacy: boolean().optional()
10405
10470
  });
10406
10471
  var ConfigFieldBridge = custom();
10407
10472
  var PipelineAddonSchemaSchema = object({
@@ -10431,11 +10496,6 @@ var PipelineSchemaSchema = object({
10431
10496
  selectedEngine: PipelineEngineChoiceSchema,
10432
10497
  slots: array(PipelineSlotSchemaSchema).readonly()
10433
10498
  });
10434
- var DetectorOutputSchema = object({
10435
- detections: array(SpatialDetectionSchema).readonly(),
10436
- inferenceMs: number(),
10437
- modelId: string()
10438
- });
10439
10499
  var EngineProvisioningSchema = object({
10440
10500
  runtimeId: _enum([
10441
10501
  "onnx",
@@ -10452,15 +10512,42 @@ var EngineProvisioningSchema = object({
10452
10512
  ]),
10453
10513
  progress: number().optional(),
10454
10514
  error: string().optional(),
10455
- nextRetryAt: number().optional()
10515
+ nextRetryAt: number().optional(),
10516
+ /**
10517
+ * Gate A (config-correctness gate at engine change): human-readable
10518
+ * config issues surfaced EAGERLY when the node's engine changes — model
10519
+ * substitutions ("chose X, running Y") and zero-build steps ("no model
10520
+ * has a <format> build"). Additive/optional: informational only, never
10521
+ * enforced here — `assertEngineReady` (readiness) still gates inference.
10522
+ * Absent/empty when the node-default tree resolves cleanly.
10523
+ */
10524
+ configIssues: array(string()).optional()
10456
10525
  });
10457
10526
  var PipelineStepInputSchema = lazy(() => object({
10458
10527
  addonId: string(),
10459
- modelId: string(),
10528
+ modelId: string().optional(),
10460
10529
  enabled: boolean().default(true),
10461
10530
  children: array(PipelineStepInputSchema).optional(),
10462
10531
  settings: record(string(), unknown()).optional()
10463
10532
  }));
10533
+ var ModelSubstitutionSchema = object({
10534
+ addonId: string(),
10535
+ chosen: string(),
10536
+ running: string(),
10537
+ format: string()
10538
+ });
10539
+ var PipelineValidationIssueSchema = object({
10540
+ addonId: string(),
10541
+ kind: _enum(["unknown-addon", "no-format-build"]),
10542
+ detail: string()
10543
+ });
10544
+ var PipelineValidationResultSchema = object({
10545
+ ok: boolean(),
10546
+ issues: array(PipelineValidationIssueSchema).readonly(),
10547
+ substitutions: array(ModelSubstitutionSchema).readonly(),
10548
+ /** The node's `currentEngine.format` this validation ran against. */
10549
+ format: string()
10550
+ });
10464
10551
  var ReferenceImageEntrySchema = object({
10465
10552
  filename: string(),
10466
10553
  stepIds: array(string()).readonly().optional()
@@ -10531,7 +10618,13 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
10531
10618
  })) }), object({ success: literal(true) }), {
10532
10619
  kind: "mutation",
10533
10620
  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({
10621
+ }), method(object({ nodeId: string() }), object({
10622
+ success: literal(true),
10623
+ clearedDevices: number()
10624
+ }), {
10625
+ kind: "mutation",
10626
+ auth: "admin"
10627
+ }), 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
10628
  name: string(),
10536
10629
  steps: array(PipelineTemplateStepSchema).readonly(),
10537
10630
  engine: PipelineEngineChoiceSchema
@@ -10548,10 +10641,6 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
10548
10641
  modelId: string(),
10549
10642
  format: ModelFormatSchema$1
10550
10643
  }), 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
10644
  engine: PipelineEngineChoiceSchema.optional(),
10556
10645
  steps: array(PipelineStepInputSchema).min(1),
10557
10646
  frame: FrameInputSchema.optional(),
@@ -10791,6 +10880,13 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
10791
10880
  kind: literal("remote-restream"),
10792
10881
  /** The camera's source-owner node (slice 1: always the hub). */
10793
10882
  ownerNodeId: string(),
10883
+ /**
10884
+ * The owner's LAN-reachable host, resolved by the orchestrator from the
10885
+ * per-node `reachableHost` override (Cluster UI). When present the runner
10886
+ * dials THIS host for the owner's restream, in preference to the
10887
+ * `CAMSTACK_HUB_URL`-derived default. Absent → auto-detect fallback.
10888
+ */
10889
+ ownerReachableHost: string().optional(),
10794
10890
  /** Operator override for the owner host the runner dials. */
10795
10891
  hubHostnameOverride: string().optional()
10796
10892
  })]).describe("Per-camera frame-source mode for the runner (P2c)");
@@ -10799,13 +10895,11 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
10799
10895
  * specific runner instance via `attachCamera`. Carries everything the
10800
10896
  * runner needs to subscribe to the local broker and execute inference.
10801
10897
  *
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.
10898
+ * Stateless-pipeline model: the pipeline content (`steps`, optional
10899
+ * `audio`) travels with the attach payload. The runner keeps it in RAM
10900
+ * for the lifetime of the attach — on rebalance, edit, or restart the
10901
+ * orchestrator re-sends the latest snapshot. Engine is NOT carried: it is
10902
+ * node-local, resolved by the executing runner at dispatch time.
10809
10903
  */
10810
10904
  var RunnerCameraConfigSchema = object({
10811
10905
  deviceId: number(),
@@ -10856,14 +10950,11 @@ var RunnerCameraConfigSchema = object({
10856
10950
  */
10857
10951
  motionSources: MotionSourcesSchema.default(["analyzer"]),
10858
10952
  pipelineEnabled: boolean().default(true),
10859
- /** Engine choice for video steps (runtime+backend+format). */
10860
- engine: PipelineEngineChoiceSchema.optional(),
10861
10953
  /** Ordered tree of video steps. Absent → runner skips video detection. */
10862
10954
  steps: array(PipelineStepInputSchema).readonly().optional(),
10863
10955
  /** Audio classification branch. `enabled:false` disables, null skips. */
10864
10956
  audio: object({
10865
- engine: PipelineEngineChoiceSchema,
10866
- modelId: string(),
10957
+ modelId: string().optional(),
10867
10958
  enabled: boolean()
10868
10959
  }).nullable().optional(),
10869
10960
  /**
@@ -12244,7 +12335,9 @@ var AddonPageDeclarationSchema$1 = object({
12244
12335
  icon: string(),
12245
12336
  path: string(),
12246
12337
  remoteName: string(),
12247
- bundle: string()
12338
+ bundle: string(),
12339
+ section: string().optional(),
12340
+ sectionLabel: string().optional()
12248
12341
  });
12249
12342
  var AddonPageInfoSchema = object({
12250
12343
  addonId: string(),
@@ -12284,7 +12377,18 @@ var AddonPageDeclarationSchema = object({
12284
12377
  * the static-file route can compute an mtime-based cache-buster URL
12285
12378
  * without a separate filesystem stat.
12286
12379
  */
12287
- bundle: string()
12380
+ bundle: string(),
12381
+ /**
12382
+ * Sidebar section this page docks into. Well-known ids: `'detection'`,
12383
+ * `'cluster'`, `'administration'` — the page renders inside that group.
12384
+ * Any OTHER string creates (or joins) a custom section rendered after
12385
+ * the built-in groups; its label comes from `sectionLabel` (first
12386
+ * declaration wins), falling back to the id. Absent → the legacy
12387
+ * "Addon Pages" group.
12388
+ */
12389
+ section: string().optional(),
12390
+ /** Display label for a CUSTOM `section` id (ignored for well-known ids). */
12391
+ sectionLabel: string().optional()
12288
12392
  });
12289
12393
  method(_void(), array(AddonPageDeclarationSchema).readonly());
12290
12394
  var AddonHttpRouteSchema = object({
@@ -12500,6 +12604,17 @@ var WidgetMetadataSchema = object({
12500
12604
  deviceContext: boolean().default(false),
12501
12605
  integrationContext: boolean().default(false)
12502
12606
  }),
12607
+ /**
12608
+ * Loadable BEFORE authentication. The normal widget registry listing
12609
+ * (`addon-widgets.listWidgets`) is auth-gated, so a pre-auth surface
12610
+ * (the login page) cannot discover a widget through it. A widget that
12611
+ * declares `preAuth: true` marks itself as safe to mount on a pre-auth
12612
+ * screen — it is surfaced through the PUBLIC `auth.listLoginMethods`
12613
+ * login-method contribution channel (see `login-method.cap.ts`) rather
12614
+ * than the authenticated registry, and its bundle is served by the
12615
+ * public `/api/addon-widgets/:addonId/*` static route. Defaults false.
12616
+ */
12617
+ preAuth: boolean().optional().default(false),
12503
12618
  /** Dashboard placement HINTS (operator can override per instance). */
12504
12619
  defaultSize: WidgetSizeEnum.default("md"),
12505
12620
  allowedSizes: array(WidgetSizeEnum).readonly().default([
@@ -12801,6 +12916,66 @@ method(object({
12801
12916
  password: string()
12802
12917
  }), AuthResultSchema.nullable(), { kind: "mutation" }), method(object({ state: string() }), string()), method(record(string(), string()), AuthResultSchema, { kind: "mutation" }), method(object({ token: string() }), AuthResultSchema.nullable());
12803
12918
  /**
12919
+ * `login-method` — collection cap through which auth addons contribute
12920
+ * their pre-auth login surfaces to the login page. This is the SINGLE,
12921
+ * generic mechanism that supersedes the dead `auth.listProviders` reader:
12922
+ * every auth addon (OIDC, magic-link, WebAuthn/passkey) registers a
12923
+ * `login-method` provider and the PUBLIC `auth.listLoginMethods`
12924
+ * procedure aggregates them for the unauthenticated login page.
12925
+ *
12926
+ * A contribution is a discriminated union on `kind`:
12927
+ *
12928
+ * - `redirect` — a declarative button. The login page renders a generic
12929
+ * button that navigates to `startUrl` (an addon-owned HTTP route).
12930
+ * Covers OIDC (`/addon/auth-oidc/<id>/start`) and magic-link with
12931
+ * ZERO shell-side JS. A future SSO addon plugs in the same way — the
12932
+ * login page needs NO change.
12933
+ *
12934
+ * - `widget` — a Module-Federation widget the login page mounts (via
12935
+ * `loadRemoteBundle`) for an in-page ceremony. Covers the passkey
12936
+ * login ceremony, which must run `@simplewebauthn/browser` INSIDE the
12937
+ * addon bundle. The referenced widget also declares `preAuth: true` in
12938
+ * its `addon-widgets-source` catalog entry. `auth.listLoginMethods`
12939
+ * stamps a public `bundleUrl` from `addonId` + `bundle`.
12940
+ *
12941
+ * Every contribution carries a `stage`:
12942
+ * - `primary` — shown on the first credentials screen (OIDC /
12943
+ * magic-link buttons; a future usernameless passkey).
12944
+ * - `second-factor` — shown AFTER the password leg, gated on the
12945
+ * returned `factors` (passkey-as-2FA today).
12946
+ *
12947
+ * `mount: skip` — the cap is read server-side by the core auth router
12948
+ * (`registry.getCollection('login-method')`), never mounted as its own
12949
+ * tRPC router.
12950
+ */
12951
+ /** When a login method renders in the two-phase login flow. */
12952
+ var LoginStageEnum = _enum(["primary", "second-factor"]);
12953
+ /** One login-method contribution — redirect button OR pre-auth widget. */
12954
+ var LoginMethodContributionSchema = discriminatedUnion("kind", [object({
12955
+ kind: literal("redirect"),
12956
+ /** Stable id within the login-method set (e.g. `auth-oidc/google`). */
12957
+ id: string(),
12958
+ /** Operator-facing button label. */
12959
+ label: string(),
12960
+ /** lucide-react icon name. */
12961
+ icon: string().optional(),
12962
+ /** Addon-owned HTTP route the button navigates to (GET). */
12963
+ startUrl: string(),
12964
+ stage: LoginStageEnum
12965
+ }), object({
12966
+ kind: literal("widget"),
12967
+ /** Stable id within the login-method set (e.g. `auth-webauthn/passkey-login`). */
12968
+ id: string(),
12969
+ /** Owning addon id — drives the public bundle URL + the MF namespace. */
12970
+ addonId: string(),
12971
+ /** Bundle filename inside the addon's dist dir (`remoteEntry.js`). */
12972
+ bundle: string(),
12973
+ /** MF remote descriptor — `{ remoteName, exposedModule, componentKey }`. */
12974
+ remote: WidgetRemoteSchema,
12975
+ stage: LoginStageEnum
12976
+ })]);
12977
+ method(_void(), array(LoginMethodContributionSchema).readonly());
12978
+ /**
12804
12979
  * Orchestrator-side destination metadata. The orchestrator computes
12805
12980
  * `id = <addonId>:<subId>` from its provider lookup so consumers
12806
12981
  * (admin UI, restore flow) see one canonical key.
@@ -15089,11 +15264,11 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
15089
15264
  timestamp: number()
15090
15265
  });
15091
15266
  var CameraPipelineConfigSchema = object({
15092
- engine: PipelineEngineChoiceSchema,
15267
+ engine: PipelineEngineChoiceSchema.optional(),
15093
15268
  steps: array(PipelineStepInputSchema).readonly(),
15094
15269
  audio: object({
15095
- engine: PipelineEngineChoiceSchema,
15096
- modelId: string(),
15270
+ engine: PipelineEngineChoiceSchema.optional(),
15271
+ modelId: string().optional(),
15097
15272
  enabled: boolean(),
15098
15273
  settings: record(string(), unknown()).readonly().optional()
15099
15274
  }).nullable().optional()
@@ -15108,7 +15283,7 @@ var PipelineTemplateSchema = object({
15108
15283
  });
15109
15284
  var AgentAddonConfigSchema = object({
15110
15285
  enabled: boolean(),
15111
- modelId: string(),
15286
+ modelId: string().optional(),
15112
15287
  settings: record(string(), unknown()).readonly()
15113
15288
  });
15114
15289
  var AgentPipelineSettingsSchema = object({
@@ -15118,12 +15293,25 @@ var AgentPipelineSettingsSchema = object({
15118
15293
  detectWeight: number().positive().optional(),
15119
15294
  /** Node is eligible to run the detection pipeline (decode + inference). */
15120
15295
  detect: boolean().optional(),
15121
- /** Node is eligible to host decoder sessions. */
15296
+ /**
15297
+ * DEPRECATED AND IGNORED. Decode is always co-located with its frame
15298
+ * consumer, so decode eligibility IS detect eligibility. Kept optional in
15299
+ * the schema ONLY so persisted stores written before the removal still
15300
+ * parse — no code reads it and no write path emits it.
15301
+ */
15122
15302
  decode: boolean().optional(),
15123
15303
  /** Node is eligible to run audio-analyzer sessions. */
15124
15304
  audio: boolean().optional(),
15125
15305
  /** Node is eligible to be the ingest / source-owner (serve the restream). */
15126
- ingest: boolean().optional()
15306
+ ingest: boolean().optional(),
15307
+ /**
15308
+ * Operator override for the LAN host a cross-node decoder dials to reach
15309
+ * THIS node's restream (Cluster UI). Absent → auto-detect: a remote runner
15310
+ * falls back to its `CAMSTACK_HUB_URL`-derived host (the Moleculer address
15311
+ * it already uses to reach the hub). Set this only when the auto-detected
15312
+ * address is wrong (multi-homed host, NAT, custom interface).
15313
+ */
15314
+ reachableHost: string().optional()
15127
15315
  });
15128
15316
  var CameraPipelineForAgentSchema = object({
15129
15317
  steps: array(PipelineStepInputSchema).readonly(),
@@ -15171,25 +15359,6 @@ var PipelineAssignmentSchema = object({
15171
15359
  assignedAt: number()
15172
15360
  });
15173
15361
  /**
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
15362
  * Per-agent load summary surfaced to the load balancer + dashboards.
15194
15363
  * Aggregated from each runner's `getLocalLoad` cap call.
15195
15364
  */
@@ -15229,6 +15398,15 @@ var GlobalMetricsSchema = object({
15229
15398
  * capability providers.
15230
15399
  */
15231
15400
  var CapabilityBindingsSchema = record(string(), string());
15401
+ /**
15402
+ * The cluster's single camera-source owner (`clusterRoles.ingestNode`) plus
15403
+ * its LAN-reachable host, if one is registered. See `getIngestOwner`.
15404
+ */
15405
+ var IngestOwnerSchema = object({
15406
+ ownerNodeId: string(),
15407
+ reachableHost: string().optional(),
15408
+ configIssue: string().optional()
15409
+ });
15232
15410
  /** Source block — always present; derives from the stream catalog. */
15233
15411
  var CameraSourceStatusSchema = object({ streams: array(object({
15234
15412
  camStreamId: string(),
@@ -15243,6 +15421,14 @@ var CameraAssignmentStatusSchema = object({
15243
15421
  detectionNodeId: string().nullable(),
15244
15422
  decoderNodeId: string().nullable(),
15245
15423
  audioNodeId: string().nullable(),
15424
+ /**
15425
+ * The node that OWNS this camera's physical source pull (dials the RTSP and
15426
+ * hosts the broker/restream) — the cluster ingest owner today
15427
+ * (`clusterRoles.ingestNode`), per-camera once source assignment lands. Lets
15428
+ * the UI show WHERE a camera is sourced without SSH/logs, and is the node the
15429
+ * broker block below was read from (pinned). Nullable only pre-wiring.
15430
+ */
15431
+ sourceNodeId: string().nullable(),
15246
15432
  pinned: object({
15247
15433
  detection: boolean(),
15248
15434
  decoder: boolean(),
@@ -15375,16 +15561,7 @@ method(object({
15375
15561
  }), object({ success: literal(true) }), {
15376
15562
  kind: "mutation",
15377
15563
  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({
15564
+ }), method(_void(), IngestOwnerSchema), method(object({
15388
15565
  deviceId: number(),
15389
15566
  nodeId: string()
15390
15567
  }), object({ success: literal(true) }), {
@@ -15405,10 +15582,7 @@ method(object({
15405
15582
  nodeId: string(),
15406
15583
  pinned: boolean(),
15407
15584
  assignedAt: number()
15408
- }))), method(object({
15409
- deviceId: number(),
15410
- pipelineNodeId: string().optional()
15411
- }), DecoderAssignmentSchema), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
15585
+ }))), method(object({ agentNodeId: string() }), AgentPipelineSettingsSchema.nullable()), method(_void(), array(object({
15412
15586
  nodeId: string(),
15413
15587
  settings: AgentPipelineSettingsSchema
15414
15588
  })).readonly()), method(object({
@@ -15438,12 +15612,26 @@ method(object({
15438
15612
  }), method(object({
15439
15613
  agentNodeId: string(),
15440
15614
  detect: boolean().nullable().optional(),
15441
- decode: boolean().nullable().optional(),
15442
15615
  audio: boolean().nullable().optional(),
15443
15616
  ingest: boolean().nullable().optional()
15444
15617
  }), object({ success: literal(true) }), {
15445
15618
  kind: "mutation",
15446
15619
  auth: "admin"
15620
+ }), method(object({
15621
+ agentNodeId: string(),
15622
+ reachableHost: string().nullable()
15623
+ }), object({ success: literal(true) }), {
15624
+ kind: "mutation",
15625
+ auth: "admin"
15626
+ }), method(object({ agentNodeId: string() }), object({
15627
+ success: literal(true),
15628
+ /** Hardware-aware default detection model now in effect on the node (null when unresolvable). */
15629
+ effectiveModelId: string().nullable(),
15630
+ /** Number of cameras whose node-scoped overrides were cleared. */
15631
+ clearedCameraOverrides: number()
15632
+ }), {
15633
+ kind: "mutation",
15634
+ auth: "admin"
15447
15635
  }), method(object({ deviceId: number() }), CameraPipelineSettingsSchema.nullable()), method(object({
15448
15636
  deviceId: number(),
15449
15637
  addonId: string(),
@@ -15488,22 +15676,131 @@ method(object({
15488
15676
  kind: "mutation",
15489
15677
  auth: "admin"
15490
15678
  });
15491
- var RegisteredStreamSchema = object({
15492
- streamId: string(),
15493
- label: string().optional(),
15494
- codec: string(),
15495
- type: _enum(["video", "audio"]),
15496
- sourceUrl: string()
15679
+ /**
15680
+ * server-management — per-NODE singleton capability for a node's ROOT
15681
+ * package lifecycle (runtime-updatable node packages, phase 2: hub + docker
15682
+ * agents).
15683
+ *
15684
+ * Each node's root package (`@camstack/server` on the hub, `@camstack/agent`
15685
+ * on agents) carries the whole software stack in its npm dep tree, so ONE
15686
+ * version describes the node. Updates install into
15687
+ * `<dataDir>/server-root/versions/<v>/` and apply on restart via the baked
15688
+ * starter (probation boot + auto-rollback to N-1).
15689
+ *
15690
+ * Providers:
15691
+ * - HUB: `ServerUpdateService` behind the `server-provided` mount
15692
+ * (`buildServerProviders` in trpc.router.ts) — the default target for
15693
+ * unpinned calls.
15694
+ * - AGENT: `AgentUpdateService` registered by the agent bootstrap under
15695
+ * the synthetic `agent-runtime` addonId and declared in the agent's
15696
+ * `$hub.registerNode` manifest.
15697
+ *
15698
+ * Node routing: singleton caps get the codegen/runtime-builder `nodeId`
15699
+ * injection on every method — `input.nodeId` (or `nodePin(nodeId)` from the
15700
+ * SDK) routes the call to that node's provider via the standard remote
15701
+ * proxy (`createCapabilityProxy` → `$agent-cap-fwd` → the agent's
15702
+ * in-process provider lookup). No `nodeId` → the hub's own provider.
15703
+ *
15704
+ * Spec: docs/superpowers/specs/2026-07-12-runtime-updatable-node-packages-design.md
15705
+ */
15706
+ /**
15707
+ * Where the running hub's code was loaded from:
15708
+ * - `workspace` — dev checkout (tsx / workspace dist); the starter defers to
15709
+ * plain resolution and runtime updates are refused.
15710
+ * - `baked` — the immutable image seed closure (no data-dir root active).
15711
+ * - `data-root` — the runtime-updatable `<dataDir>/server-root` closure.
15712
+ */
15713
+ var ServerBootModeSchema = _enum([
15714
+ "workspace",
15715
+ "baked",
15716
+ "data-root"
15717
+ ]);
15718
+ /**
15719
+ * Update lifecycle state:
15720
+ * - `idle` / `checking` / `staging` — steady / in-flight registry work.
15721
+ * - `pending-restart` — a version is staged and the node has NOT yet
15722
+ * restarted onto it (still running the OLD version).
15723
+ * - `awaiting-confirmation` — the node HAS restarted onto the staged version
15724
+ * (it is the active probation boot) and is waiting to confirm boot-health.
15725
+ * Apply/rollback are refused in this state and the node must NOT be
15726
+ * manually restarted, or the probation boot auto-rolls-back.
15727
+ */
15728
+ var ServerUpdateStateSchema = _enum([
15729
+ "idle",
15730
+ "checking",
15731
+ "staging",
15732
+ "pending-restart",
15733
+ "awaiting-confirmation"
15734
+ ]);
15735
+ var ServerRollbackInfoSchema = object({
15736
+ /** The version that failed (or was manually rolled back). */
15737
+ fromVersion: string(),
15738
+ /** The version rolled back to; null = the baked seed. */
15739
+ toVersion: string().nullable(),
15740
+ atMs: number(),
15741
+ reason: string()
15497
15742
  });
15498
- var ExposedResourceSchema = object({
15499
- streamId: string(),
15500
- format: string(),
15501
- value: string()
15743
+ var ServerPackageStatusSchema = object({
15744
+ /** Root package name (`@camstack/server` on the hub). */
15745
+ packageName: string(),
15746
+ /** Version of the code the running process ACTUALLY loaded. */
15747
+ runningVersion: string().nullable(),
15748
+ /** Node.js runtime version the node's process runs on (`process.versions.node`). */
15749
+ nodeRuntimeVersion: string().nullable(),
15750
+ /** Active data-dir root version; null when booted from seed/workspace. */
15751
+ activeVersion: string().nullable(),
15752
+ /** N-1 version kept for rollback; null when no previous version exists. */
15753
+ previousVersion: string().nullable(),
15754
+ /** Version of the immutable baked seed closure (image fallback). */
15755
+ seedVersion: string().nullable(),
15756
+ /** Latest registry version from the most recent check (null = never checked). */
15757
+ latestVersion: string().nullable(),
15758
+ updateAvailable: boolean(),
15759
+ bootMode: ServerBootModeSchema,
15760
+ updateState: ServerUpdateStateSchema,
15761
+ /** Version staged + awaiting its probation boot, when one is pending. */
15762
+ pendingVersion: string().nullable(),
15763
+ /** Set when the last freshly-activated version failed its boot health-check. */
15764
+ rolledBack: ServerRollbackInfoSchema.nullable(),
15765
+ /**
15766
+ * True when `server-root/state.json` EXISTS but is unreadable/corrupt — the
15767
+ * hub is running from the baked seed (or workspace) while installed data-dir
15768
+ * versions are being IGNORED. Surfaced as a warning in the UI.
15769
+ */
15770
+ stateFileCorrupt: boolean(),
15771
+ lastCheckedAtMs: number().nullable()
15772
+ });
15773
+ var ServerUpdateCheckResultSchema = object({
15774
+ packageName: string(),
15775
+ runningVersion: string().nullable(),
15776
+ latestVersion: string().nullable(),
15777
+ updateAvailable: boolean(),
15778
+ checkedAtMs: number(),
15779
+ /** Non-null when the registry lookup failed (offline, bad registry, …). */
15780
+ error: string().nullable()
15781
+ });
15782
+ var ServerUpdateActionResultSchema = object({
15783
+ accepted: boolean(),
15784
+ targetVersion: string().nullable(),
15785
+ /** True when a graceful restart was scheduled to apply the change. */
15786
+ restarting: boolean(),
15787
+ message: string()
15788
+ });
15789
+ method(_void(), ServerPackageStatusSchema, { auth: "admin" }), method(_void(), ServerUpdateCheckResultSchema, {
15790
+ kind: "mutation",
15791
+ auth: "admin"
15792
+ }), method(object({
15793
+ /** Explicit target version; omitted = latest from the registry. */
15794
+ version: string().optional() }), ServerUpdateActionResultSchema, {
15795
+ kind: "mutation",
15796
+ auth: "admin"
15797
+ }), method(_void(), ServerUpdateActionResultSchema, {
15798
+ kind: "mutation",
15799
+ auth: "admin"
15800
+ }), method(_void(), ServerUpdateActionResultSchema, {
15801
+ kind: "mutation",
15802
+ auth: "admin"
15502
15803
  });
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
15804
  /**
15508
15805
  * Query filter for settings-store collections.
15509
15806
  */
@@ -15656,9 +15953,9 @@ method(SendEmailInputSchema, SendEmailResultSchema, {
15656
15953
  /**
15657
15954
  * A single device snapshot returned as base64 JPEG/PNG.
15658
15955
  *
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.
15956
+ * The `SnapshotAddon` wrapper returns this shape whether the frame came from
15957
+ * the device-native provider (onboard capture) or from the stream-broker
15958
+ * prebuffer fallback.
15662
15959
  */
15663
15960
  var SnapshotImageSchema = object({
15664
15961
  base64: string(),
@@ -15690,10 +15987,6 @@ DeviceType.Camera, method(object({
15690
15987
  kind: "mutation",
15691
15988
  auth: "admin"
15692
15989
  });
15693
- method(object({ deviceId: number() }), boolean()), method(object({
15694
- deviceId: number(),
15695
- streamId: string().optional()
15696
- }), SnapshotImageSchema.nullable());
15697
15990
  /**
15698
15991
  * `sso-bridge` — internal hub-only cap that lets SSO-style auth
15699
15992
  * providers (OIDC, SAML, magic-link, …) mint an HMAC-signed token
@@ -15944,10 +16237,32 @@ method(_void(), array(TurnServerSchema).readonly());
15944
16237
  * b. `finishAuthentication({userId, response})` → server verifies
15945
16238
  * the assertion, bumps the credential counter, returns ok.
15946
16239
  *
16240
+ * 2b. Usernameless (discoverable-credential) authentication — the
16241
+ * passkey IS the primary factor, no password leg:
16242
+ * a. `beginDiscoverableAuthentication({})` → assertion options with
16243
+ * EMPTY `allowCredentials` (the browser offers every resident
16244
+ * passkey it holds for this RP) + `userVerification: 'required'`
16245
+ * (the passkey replaces both factors, so UV is mandatory).
16246
+ * The challenge is stored server-side, NOT bound to any user.
16247
+ * b. `finishDiscoverableAuthentication({response})` → the provider
16248
+ * resolves the credential by the response's credential id,
16249
+ * verifies the assertion against the stored challenge + that
16250
+ * credential's public key/counter, and returns the OWNING
16251
+ * `userId` — the caller (core auth router) mints the session.
16252
+ *
15947
16253
  * 3. Management:
15948
16254
  * - `listPasskeys({userId})` — enumerate user's enrolled credentials.
15949
16255
  * - `removePasskey({userId, credentialId})` — revoke one credential.
15950
16256
  *
16257
+ * 4. Second-factor preference (opt-in, default OFF):
16258
+ * Enrolling a passkey only enables passkey-FIRST sign-in. It is
16259
+ * demanded as a second factor after a password login ONLY when the
16260
+ * user explicitly opts in via `setSecondFactorPreference`.
16261
+ * - `getSecondFactorPreference({userId})` → `{ enabled }` (missing
16262
+ * row ⇒ `enabled: false`).
16263
+ * - `setSecondFactorPreference({userId, enabled})` — persisted by
16264
+ * the providing addon beside its credentials.
16265
+ *
15951
16266
  * Challenges are short-lived (5 min, in-memory). The cap is internal —
15952
16267
  * the admin-ui composes the begin/finish round-trip and never exposes
15953
16268
  * the cap to non-admins.
@@ -15990,6 +16305,17 @@ method(object({
15990
16305
  }), object({ verified: boolean() }), {
15991
16306
  kind: "mutation",
15992
16307
  access: "view"
16308
+ }), method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
16309
+ kind: "mutation",
16310
+ access: "view"
16311
+ }), method(object({
16312
+ /** AuthenticationResponseJSON from the browser. */
16313
+ response: record(string(), unknown()) }), object({
16314
+ verified: boolean(),
16315
+ userId: string().nullable()
16316
+ }), {
16317
+ kind: "mutation",
16318
+ access: "view"
15993
16319
  }), method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }), method(object({
15994
16320
  userId: string(),
15995
16321
  credentialId: string()
@@ -15997,6 +16323,13 @@ method(object({
15997
16323
  kind: "mutation",
15998
16324
  auth: "admin",
15999
16325
  access: "delete"
16326
+ }), method(object({ userId: string() }), object({ enabled: boolean() }), { auth: "admin" }), method(object({
16327
+ userId: string(),
16328
+ enabled: boolean()
16329
+ }), object({ success: literal(true) }), {
16330
+ kind: "mutation",
16331
+ auth: "admin",
16332
+ access: "create"
16000
16333
  });
16001
16334
  /**
16002
16335
  * `videoclips` — the unified, navigable-clip surface for a camera.
@@ -16054,9 +16387,10 @@ method(object({
16054
16387
  auth: "admin"
16055
16388
  });
16056
16389
  /**
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.
16390
+ * Optional client-side hints sent at session creation to help the provider
16391
+ * pick the best native source. All fields optional — a viewer that knows
16392
+ * nothing still gets a sane default. (Relocated from the retired `webrtc`
16393
+ * collection cap; this `webrtc-session` cap is the live signaling surface.)
16060
16394
  */
16061
16395
  var webrtcClientHintsSchema = object({
16062
16396
  viewportWidth: number().int().positive().optional(),
@@ -16067,22 +16401,6 @@ var webrtcClientHintsSchema = object({
16067
16401
  /** Hard tier override; takes precedence over scoring when registered. */
16068
16402
  prefersTier: string().optional()
16069
16403
  }).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
16404
  /**
16087
16405
  * Discriminated target for a WebRTC session. The client sends this
16088
16406
  * structured object instead of building / parsing brokerId strings;
@@ -17510,6 +17828,16 @@ var TopologyCategorySchema = object({
17510
17828
  healthy: number(),
17511
17829
  addons: array(TopologyCategoryAddonSchema).readonly()
17512
17830
  });
17831
+ /**
17832
+ * The node's runtime-updatable ROOT package (`@camstack/server` on the hub,
17833
+ * `@camstack/agent` on agents) as reported by its `registerNode` manifest —
17834
+ * version visibility for the Server management surface. Nullable: offline
17835
+ * rows and pre-phase-2 nodes report none.
17836
+ */
17837
+ var TopologyRootPackageSchema = object({
17838
+ name: string(),
17839
+ version: string()
17840
+ });
17513
17841
  var TopologyNodeSchema = object({
17514
17842
  id: string(),
17515
17843
  name: string(),
@@ -17533,7 +17861,8 @@ var TopologyNodeSchema = object({
17533
17861
  status: string()
17534
17862
  })).readonly(),
17535
17863
  processes: array(TopologyProcessSchema).readonly(),
17536
- categories: array(TopologyCategorySchema).readonly()
17864
+ categories: array(TopologyCategorySchema).readonly(),
17865
+ rootPackage: TopologyRootPackageSchema.nullable()
17537
17866
  });
17538
17867
  var CapUsageEdgeSchema = object({
17539
17868
  callerAddonId: string(),
@@ -20333,6 +20662,12 @@ Object.freeze({
20333
20662
  addonId: null,
20334
20663
  access: "create"
20335
20664
  },
20665
+ "loginMethod.getLoginMethods": {
20666
+ capName: "login-method",
20667
+ capScope: "system",
20668
+ addonId: null,
20669
+ access: "view"
20670
+ },
20336
20671
  "mediaPlayer.next": {
20337
20672
  capName: "media-player",
20338
20673
  capScope: "device",
@@ -20963,23 +21298,23 @@ Object.freeze({
20963
21298
  addonId: null,
20964
21299
  access: "create"
20965
21300
  },
20966
- "pipelineExecutor.deleteModel": {
21301
+ "pipelineExecutor.clearDeviceOverrides": {
20967
21302
  capName: "pipeline-executor",
20968
21303
  capScope: "system",
20969
21304
  addonId: null,
20970
21305
  access: "delete"
20971
21306
  },
20972
- "pipelineExecutor.deleteTemplate": {
21307
+ "pipelineExecutor.deleteModel": {
20973
21308
  capName: "pipeline-executor",
20974
21309
  capScope: "system",
20975
21310
  addonId: null,
20976
21311
  access: "delete"
20977
21312
  },
20978
- "pipelineExecutor.detect": {
21313
+ "pipelineExecutor.deleteTemplate": {
20979
21314
  capName: "pipeline-executor",
20980
21315
  capScope: "system",
20981
21316
  addonId: null,
20982
- access: "view"
21317
+ access: "delete"
20983
21318
  },
20984
21319
  "pipelineExecutor.downloadModel": {
20985
21320
  capName: "pipeline-executor",
@@ -21173,13 +21508,13 @@ Object.freeze({
21173
21508
  addonId: null,
21174
21509
  access: "create"
21175
21510
  },
21176
- "pipelineOrchestrator.assignAudio": {
21177
- capName: "pipeline-orchestrator",
21511
+ "pipelineExecutor.validatePipeline": {
21512
+ capName: "pipeline-executor",
21178
21513
  capScope: "system",
21179
21514
  addonId: null,
21180
- access: "create"
21515
+ access: "view"
21181
21516
  },
21182
- "pipelineOrchestrator.assignDecoder": {
21517
+ "pipelineOrchestrator.assignAudio": {
21183
21518
  capName: "pipeline-orchestrator",
21184
21519
  capScope: "system",
21185
21520
  addonId: null,
@@ -21263,19 +21598,13 @@ Object.freeze({
21263
21598
  addonId: null,
21264
21599
  access: "view"
21265
21600
  },
21266
- "pipelineOrchestrator.getDecoderAssignment": {
21267
- capName: "pipeline-orchestrator",
21268
- capScope: "system",
21269
- addonId: null,
21270
- access: "view"
21271
- },
21272
- "pipelineOrchestrator.getDecoderAssignments": {
21601
+ "pipelineOrchestrator.getGlobalMetrics": {
21273
21602
  capName: "pipeline-orchestrator",
21274
21603
  capScope: "system",
21275
21604
  addonId: null,
21276
21605
  access: "view"
21277
21606
  },
21278
- "pipelineOrchestrator.getGlobalMetrics": {
21607
+ "pipelineOrchestrator.getIngestOwner": {
21279
21608
  capName: "pipeline-orchestrator",
21280
21609
  capScope: "system",
21281
21610
  addonId: null,
@@ -21317,6 +21646,12 @@ Object.freeze({
21317
21646
  addonId: null,
21318
21647
  access: "delete"
21319
21648
  },
21649
+ "pipelineOrchestrator.resetNodePipelineDefaults": {
21650
+ capName: "pipeline-orchestrator",
21651
+ capScope: "system",
21652
+ addonId: null,
21653
+ access: "delete"
21654
+ },
21320
21655
  "pipelineOrchestrator.resolvePipeline": {
21321
21656
  capName: "pipeline-orchestrator",
21322
21657
  capScope: "system",
@@ -21353,37 +21688,37 @@ Object.freeze({
21353
21688
  addonId: null,
21354
21689
  access: "create"
21355
21690
  },
21356
- "pipelineOrchestrator.setCameraPipelineForAgent": {
21691
+ "pipelineOrchestrator.setAgentReachableHost": {
21357
21692
  capName: "pipeline-orchestrator",
21358
21693
  capScope: "system",
21359
21694
  addonId: null,
21360
21695
  access: "create"
21361
21696
  },
21362
- "pipelineOrchestrator.setCameraStepOverride": {
21697
+ "pipelineOrchestrator.setCameraPipelineForAgent": {
21363
21698
  capName: "pipeline-orchestrator",
21364
21699
  capScope: "system",
21365
21700
  addonId: null,
21366
21701
  access: "create"
21367
21702
  },
21368
- "pipelineOrchestrator.setCameraStepToggle": {
21703
+ "pipelineOrchestrator.setCameraStepOverride": {
21369
21704
  capName: "pipeline-orchestrator",
21370
21705
  capScope: "system",
21371
21706
  addonId: null,
21372
21707
  access: "create"
21373
21708
  },
21374
- "pipelineOrchestrator.setCapabilityBinding": {
21709
+ "pipelineOrchestrator.setCameraStepToggle": {
21375
21710
  capName: "pipeline-orchestrator",
21376
21711
  capScope: "system",
21377
21712
  addonId: null,
21378
21713
  access: "create"
21379
21714
  },
21380
- "pipelineOrchestrator.unassignAudio": {
21715
+ "pipelineOrchestrator.setCapabilityBinding": {
21381
21716
  capName: "pipeline-orchestrator",
21382
21717
  capScope: "system",
21383
21718
  addonId: null,
21384
21719
  access: "create"
21385
21720
  },
21386
- "pipelineOrchestrator.unassignDecoder": {
21721
+ "pipelineOrchestrator.unassignAudio": {
21387
21722
  capName: "pipeline-orchestrator",
21388
21723
  capScope: "system",
21389
21724
  addonId: null,
@@ -21683,33 +22018,45 @@ Object.freeze({
21683
22018
  addonId: null,
21684
22019
  access: "create"
21685
22020
  },
21686
- "restreamer.getExposedResources": {
21687
- capName: "restreamer",
22021
+ "scriptRunner.run": {
22022
+ capName: "script-runner",
22023
+ capScope: "device",
22024
+ addonId: null,
22025
+ access: "create"
22026
+ },
22027
+ "scriptRunner.stop": {
22028
+ capName: "script-runner",
22029
+ capScope: "device",
22030
+ addonId: null,
22031
+ access: "create"
22032
+ },
22033
+ "serverManagement.applyServerUpdate": {
22034
+ capName: "server-management",
21688
22035
  capScope: "system",
21689
22036
  addonId: null,
21690
- access: "view"
22037
+ access: "create"
21691
22038
  },
21692
- "restreamer.registerDevice": {
21693
- capName: "restreamer",
22039
+ "serverManagement.checkServerUpdate": {
22040
+ capName: "server-management",
21694
22041
  capScope: "system",
21695
22042
  addonId: null,
21696
22043
  access: "create"
21697
22044
  },
21698
- "restreamer.unregisterDevice": {
21699
- capName: "restreamer",
22045
+ "serverManagement.getServerPackageStatus": {
22046
+ capName: "server-management",
21700
22047
  capScope: "system",
21701
22048
  addonId: null,
21702
- access: "delete"
22049
+ access: "view"
21703
22050
  },
21704
- "scriptRunner.run": {
21705
- capName: "script-runner",
21706
- capScope: "device",
22051
+ "serverManagement.restartServer": {
22052
+ capName: "server-management",
22053
+ capScope: "system",
21707
22054
  addonId: null,
21708
22055
  access: "create"
21709
22056
  },
21710
- "scriptRunner.stop": {
21711
- capName: "script-runner",
21712
- capScope: "device",
22057
+ "serverManagement.rollbackServerUpdate": {
22058
+ capName: "server-management",
22059
+ capScope: "system",
21713
22060
  addonId: null,
21714
22061
  access: "create"
21715
22062
  },
@@ -21803,18 +22150,6 @@ Object.freeze({
21803
22150
  addonId: null,
21804
22151
  access: "create"
21805
22152
  },
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
22153
  "ssoBridge.signBridgeToken": {
21819
22154
  capName: "sso-bridge",
21820
22155
  capScope: "system",
@@ -22241,30 +22576,6 @@ Object.freeze({
22241
22576
  addonId: null,
22242
22577
  access: "view"
22243
22578
  },
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
22579
  "streamParams.getConfigSchema": {
22269
22580
  capName: "stream-params",
22270
22581
  capScope: "device",
@@ -22511,6 +22822,12 @@ Object.freeze({
22511
22822
  addonId: null,
22512
22823
  access: "view"
22513
22824
  },
22825
+ "userPasskeys.beginDiscoverableAuthentication": {
22826
+ capName: "user-passkeys",
22827
+ capScope: "system",
22828
+ addonId: null,
22829
+ access: "view"
22830
+ },
22514
22831
  "userPasskeys.beginRegistration": {
22515
22832
  capName: "user-passkeys",
22516
22833
  capScope: "system",
@@ -22523,12 +22840,24 @@ Object.freeze({
22523
22840
  addonId: null,
22524
22841
  access: "view"
22525
22842
  },
22843
+ "userPasskeys.finishDiscoverableAuthentication": {
22844
+ capName: "user-passkeys",
22845
+ capScope: "system",
22846
+ addonId: null,
22847
+ access: "view"
22848
+ },
22526
22849
  "userPasskeys.finishRegistration": {
22527
22850
  capName: "user-passkeys",
22528
22851
  capScope: "system",
22529
22852
  addonId: null,
22530
22853
  access: "create"
22531
22854
  },
22855
+ "userPasskeys.getSecondFactorPreference": {
22856
+ capName: "user-passkeys",
22857
+ capScope: "system",
22858
+ addonId: null,
22859
+ access: "view"
22860
+ },
22532
22861
  "userPasskeys.listPasskeys": {
22533
22862
  capName: "user-passkeys",
22534
22863
  capScope: "system",
@@ -22541,6 +22870,12 @@ Object.freeze({
22541
22870
  addonId: null,
22542
22871
  access: "delete"
22543
22872
  },
22873
+ "userPasskeys.setSecondFactorPreference": {
22874
+ capName: "user-passkeys",
22875
+ capScope: "system",
22876
+ addonId: null,
22877
+ access: "create"
22878
+ },
22544
22879
  "vacuumControl.locate": {
22545
22880
  capName: "vacuum-control",
22546
22881
  capScope: "device",
@@ -22613,6 +22948,18 @@ Object.freeze({
22613
22948
  addonId: null,
22614
22949
  access: "view"
22615
22950
  },
22951
+ "viewerUi.getStaticDir": {
22952
+ capName: "viewer-ui",
22953
+ capScope: "system",
22954
+ addonId: null,
22955
+ access: "view"
22956
+ },
22957
+ "viewerUi.getVersion": {
22958
+ capName: "viewer-ui",
22959
+ capScope: "system",
22960
+ addonId: null,
22961
+ access: "view"
22962
+ },
22616
22963
  "waterHeater.setAway": {
22617
22964
  capName: "water-heater",
22618
22965
  capScope: "device",
@@ -22631,54 +22978,6 @@ Object.freeze({
22631
22978
  addonId: null,
22632
22979
  access: "create"
22633
22980
  },
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
22981
  "webrtcSession.addIceCandidate": {
22683
22982
  capName: "webrtc-session",
22684
22983
  capScope: "device",
@@ -22849,7 +23148,7 @@ var AgentUIAddon = class extends BaseAddon {
22849
23148
  capability: adminUiCapability,
22850
23149
  provider: {
22851
23150
  getStaticDir: async () => ({ staticDir: path.resolve(__dirname) }),
22852
- getVersion: async () => ({ version: "1.1.20" })
23151
+ getVersion: async () => ({ version: "1.1.21" })
22853
23152
  }
22854
23153
  }];
22855
23154
  }