@camstack/addon-pipeline 1.1.43 → 1.1.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/audio-analyzer/index.js +5 -4
  2. package/dist/audio-analyzer/index.mjs +1 -1
  3. package/dist/chunk-D6vf50IK.js +28 -0
  4. package/dist/detection-pipeline/index.js +2714 -2028
  5. package/dist/detection-pipeline/index.mjs +2708 -2023
  6. package/dist/{dist-NvwN60Fq.js → dist-CjxqjgEv.js} +255 -185
  7. package/dist/{dist-GFd8M6KO.mjs → dist-D04numuO.mjs} +250 -186
  8. package/dist/{model-download-service-C-IHWnXx-DxM2DSns.js → model-download-service-C-IHWnXx-BLXzxpRB.js} +3 -29
  9. package/dist/motion-wasm/index.js +1 -1
  10. package/dist/motion-wasm/index.mjs +1 -1
  11. package/dist/pipeline-runner/index.js +122 -287
  12. package/dist/pipeline-runner/index.mjs +118 -285
  13. package/dist/recorder/index.js +60 -20
  14. package/dist/recorder/index.mjs +57 -18
  15. package/dist/{frame-handle-plane-B3Fxww8H.js → remote-source-plane-CLuxyDV2.js} +236 -1
  16. package/dist/{frame-handle-plane-E_AsR77T.mjs → remote-source-plane-D31IILFN.mjs} +219 -2
  17. package/dist/session-decode/decode-worker-child.js +86 -2
  18. package/dist/session-decode/decode-worker-child.mjs +83 -2
  19. package/dist/stream-broker/_stub.js +550 -523
  20. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CeielP5P.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BGKueo9D.mjs} +2 -2
  21. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-D0sKyXiy.mjs +26 -0
  22. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-8BUVCFIR.mjs +26 -0
  23. package/dist/stream-broker/{hostInit-DmjqskOR.mjs → hostInit-DazV2RCq.mjs} +2 -2
  24. package/dist/stream-broker/index.js +746 -135
  25. package/dist/stream-broker/index.mjs +737 -127
  26. package/dist/stream-broker/remoteEntry.js +1 -1
  27. package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-CEsPjwzT.js → MaskShapeCanvas-DI4BY7W2-D_F4a_3H.js} +1 -1
  28. package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-D43fIRgB.js → MotionZonesSettings-NcxxQN8r-CfTBrn4G.js} +1 -1
  29. package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-C3wJxG8V.js → PrivacyMaskSettings-APgPLF7p-BWYkeoRj.js} +1 -1
  30. package/embed-dist/assets/{index-CSFtK41z.css → index-CA4kv43T.css} +1 -1
  31. package/embed-dist/assets/index-_ccEdNW7.js +81 -0
  32. package/embed-dist/index.html +2 -2
  33. package/package.json +2 -2
  34. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DqJvWBKS.mjs +0 -26
  35. package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-dGka8yZY.mjs +0 -26
  36. package/embed-dist/assets/index-CX-rILhw.js +0 -81
@@ -4627,7 +4627,7 @@ function _instanceof(cls, params = {}) {
4627
4627
  return inst;
4628
4628
  }
4629
4629
  //#endregion
4630
- //#region ../types/dist/sleep-CZDdRBua.mjs
4630
+ //#region ../types/dist/sleep-Cc14_yxc.mjs
4631
4631
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4632
4632
  EventCategory["SystemBoot"] = "system.boot";
4633
4633
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -4813,6 +4813,18 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
4813
4813
  */
4814
4814
  EventCategory["PipelineCameraUpdated"] = "pipeline.camera-updated";
4815
4815
  /**
4816
+ * The cluster camera-source OWNER changed (`clusterRoles.ingestNode`).
4817
+ * Emitted by addon-pipeline-orchestrator whenever it (re)derives node
4818
+ * capabilities — at boot, on agent online/offline, and on an ingest-node
4819
+ * flip. Carries the resolved `ownerNodeId`. The stream-broker consumes it to
4820
+ * keep its ingest-owner-gate decision current WITHOUT a per-`ensureBroker`
4821
+ * cross-process `getIngestOwner` query (push the authority's decision instead
4822
+ * of polling it on the hot path). Idempotent state — re-emitted on every
4823
+ * topology change, so a dropped event self-heals on the next one (plus the
4824
+ * broker's long backstop reconcile query).
4825
+ */
4826
+ EventCategory["PipelineIngestOwnerChanged"] = "pipeline.ingest-owner-changed";
4827
+ /**
4816
4828
  * Periodic snapshot of per-node pipeline-runner load
4817
4829
  * (`RunnerLocalLoad`). Emitted ~1Hz by every runner so UI dashboards
4818
4830
  * subscribe instead of polling `pipelineRunner.getLocalLoad`.
@@ -5367,6 +5379,22 @@ function typeOf(field) {
5367
5379
  }
5368
5380
  }
5369
5381
  /**
5382
+ * Narrow a SystemEvent to a typed event by checking its category.
5383
+ * Returns `true` (and narrows the type) if the category matches.
5384
+ *
5385
+ * @example
5386
+ * ```typescript
5387
+ * eventBus.subscribe({ category: 'addon.started' }, (event) => {
5388
+ * if (isEvent(event, 'addon.started')) {
5389
+ * event.data.addonId // ✓ typed as string
5390
+ * }
5391
+ * })
5392
+ * ```
5393
+ */
5394
+ function isEvent(event, category) {
5395
+ return event.category === category;
5396
+ }
5397
+ /**
5370
5398
  * Create a typed event with less boilerplate.
5371
5399
  *
5372
5400
  * @example
@@ -7016,6 +7044,36 @@ var ModelFormatsSchema = object({
7016
7044
  tflite: ModelFormatEntrySchema.optional(),
7017
7045
  pt: ModelFormatEntrySchema.optional()
7018
7046
  });
7047
+ /**
7048
+ * Variant-selector grouping axes. Shared by the full `ModelCatalogEntry` and by
7049
+ * the reduced `PipelineModelOption` returned in `pipeline.getSchema()` so the
7050
+ * grouped Family→Tier→Variant picker renders identically in the config UI and
7051
+ * in the pipeline/device steppers. The flat `id` stays the source of truth for
7052
+ * resolution/download/persistence; this is a presentation overlay resolved back
7053
+ * to an `id`.
7054
+ */
7055
+ var ModelVariantGroupSchema = object({
7056
+ /** Top-level family, e.g. `yolo26` (later `d-fine`, `rf-detr`). */
7057
+ family: string(),
7058
+ /** Size within the family, e.g. `n` | `s` | `m` | `l`. */
7059
+ tier: string(),
7060
+ /** Quantization axis. Omit ⇒ the fp32 base build. */
7061
+ precision: _enum(["fp32", "int8"]).optional(),
7062
+ /**
7063
+ * Speed-optimization axis. Omit ⇒ the standard build. `fast` marks a
7064
+ * latency-optimized export (e.g. ReLU-activation variant) — the slot the
7065
+ * future performance variants plug into.
7066
+ */
7067
+ optimization: _enum(["standard", "fast"]).optional(),
7068
+ /**
7069
+ * Input-resolution axis (square input side, px). Omit ⇒ the family's native
7070
+ * resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
7071
+ * cheap latency lever — especially on Apple ANE and the Intel N100 — at a
7072
+ * small-object accuracy cost. Mirrors the model's `inputSize` but lifted onto
7073
+ * the group so the selector can offer it as a variant axis.
7074
+ */
7075
+ resolution: number().int().positive().optional()
7076
+ });
7019
7077
  var ModelCatalogEntrySchema = object({
7020
7078
  id: string(),
7021
7079
  name: string(),
@@ -7045,7 +7103,43 @@ var ModelCatalogEntrySchema = object({
7045
7103
  * Auxiliary files required at runtime (labels JSON, charset dict, etc.).
7046
7104
  * Downloaded into the same modelsDir alongside the model file.
7047
7105
  */
7048
- extraFiles: array(ModelExtraFileSchema).readonly().optional()
7106
+ extraFiles: array(ModelExtraFileSchema).readonly().optional(),
7107
+ /**
7108
+ * LEGACY entry — retained in the catalog so a persisted operator selection
7109
+ * still RESOLVES (and can be re-activated), but hidden from the selectable
7110
+ * model list and excluded from the auto format-default pick. Set on the
7111
+ * superseded / consolidated models (older lineages, redundant fp16 IRs) so
7112
+ * the active lineup stays the coherent curated ladder without deleting a
7113
+ * model anyone may still be pinned to. `resolveModelForFormat` keeps honoring
7114
+ * an explicit legacy id that has a build for the node's format.
7115
+ */
7116
+ legacy: boolean().optional(),
7117
+ /**
7118
+ * Measured quality/latency metadata — populated from the benchmark addon on
7119
+ * the real node classes. Absent = not yet measured (most entries today; the
7120
+ * catalog historically carried only `sizeMB`, a poor cross-architecture
7121
+ * speed proxy). `p95LatencyMs` is keyed by node class (e.g. `n100`, `mac`).
7122
+ */
7123
+ metrics: object({
7124
+ map50: number().optional(),
7125
+ p95LatencyMs: record(string(), number()).optional()
7126
+ }).optional(),
7127
+ /**
7128
+ * SPDX-ish license id of the model weights (e.g. `AGPL-3.0` for Ultralytics
7129
+ * YOLO26, `GPL-3.0` for YOLOv9, `Apache-2.0` for D-FINE/RF-DETR). Matters for
7130
+ * the retraining addon and any future commercial distribution.
7131
+ */
7132
+ license: string().optional(),
7133
+ /**
7134
+ * Variant-selector grouping. The UI groups models by `family` + `tier` and
7135
+ * offers `precision` / `optimization` as variant axes WITHIN a tier — so all
7136
+ * of a family's sizes and quantizations collapse into one grouped picker
7137
+ * instead of a flat list of `yolo26s`, `yolo26s-int8`, … Absent ⇒ ungrouped
7138
+ * (legacy / custom models) — never shown in the grouped selector. The flat
7139
+ * `id` stays the source of truth for resolution/download/persistence; grouping
7140
+ * is a presentation overlay resolved back to an `id`.
7141
+ */
7142
+ group: ModelVariantGroupSchema.optional()
7049
7143
  });
7050
7144
  var ConvertTargetSchema = discriminatedUnion("format", [object({
7051
7145
  format: literal("openvino"),
@@ -7125,8 +7219,8 @@ var RecordingModeSchema = _enum([
7125
7219
  "onAudioThreshold"
7126
7220
  ]);
7127
7221
  /**
7128
- * First-class, authoritative per-camera storage mode — the netta choice the UI
7129
- * reads directly (never inferred from `rules`):
7222
+ * First-class, authoritative per-camera storage mode — the explicit choice the
7223
+ * UI reads directly (never inferred from `rules`):
7130
7224
  * - `off` — not recording.
7131
7225
  * - `events` — record only around triggers (motion / audio threshold),
7132
7226
  * with pre/post-buffer.
@@ -9338,26 +9432,13 @@ DeviceType.Light, method(object({
9338
9432
  percentage: number().min(0).max(100),
9339
9433
  lastChangedAt: number()
9340
9434
  });
9435
+ /** Stream delivery format. (Relocated from the retired `streaming-engine` cap.) */
9341
9436
  var StreamFormatSchema = _enum([
9342
9437
  "webrtc",
9343
9438
  "hls",
9344
9439
  "mjpeg",
9345
9440
  "rtsp"
9346
9441
  ]);
9347
- var StreamInfoSchema = object({
9348
- streamId: string(),
9349
- format: StreamFormatSchema,
9350
- url: string().nullable(),
9351
- active: boolean()
9352
- });
9353
- method(object({
9354
- streamId: string(),
9355
- sourceUrl: string(),
9356
- codec: string().optional()
9357
- }), _void(), { kind: "mutation" }), method(object({ streamId: string() }), _void(), { kind: "mutation" }), method(object({
9358
- streamId: string(),
9359
- format: StreamFormatSchema
9360
- }), string().nullable()), method(_void(), array(StreamInfoSchema));
9361
9442
  var RtspRestreamEntrySchema = object({
9362
9443
  brokerId: string(),
9363
9444
  url: string(),
@@ -10225,7 +10306,7 @@ var ConsumablesStatusSchema = object({
10225
10306
  })),
10226
10307
  lastChangedAt: number()
10227
10308
  });
10228
- 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({
10309
+ Object.values(DeviceType), method(object({
10229
10310
  deviceId: number().int().nonnegative(),
10230
10311
  key: string().min(1)
10231
10312
  }), _void(), {
@@ -11288,7 +11369,6 @@ var PipelineDefaultStepSchema = lazy(() => object({
11288
11369
  enabled: boolean(),
11289
11370
  modelId: string(),
11290
11371
  children: array(PipelineDefaultStepSchema).readonly(),
11291
- engine: PipelineEngineChoiceSchema.optional(),
11292
11372
  group: string().optional(),
11293
11373
  settings: record(string(), unknown()).optional()
11294
11374
  }));
@@ -11313,7 +11393,9 @@ var PipelineModelOptionSchema = object({
11313
11393
  formats: record(string(), object({
11314
11394
  downloaded: boolean(),
11315
11395
  sizeMB: number()
11316
- }))
11396
+ })),
11397
+ group: ModelVariantGroupSchema.optional(),
11398
+ legacy: boolean().optional()
11317
11399
  });
11318
11400
  var ConfigFieldBridge = custom();
11319
11401
  var PipelineAddonSchemaSchema = object({
@@ -11364,15 +11446,42 @@ var EngineProvisioningSchema = object({
11364
11446
  ]),
11365
11447
  progress: number().optional(),
11366
11448
  error: string().optional(),
11367
- nextRetryAt: number().optional()
11449
+ nextRetryAt: number().optional(),
11450
+ /**
11451
+ * Gate A (config-correctness gate at engine change): human-readable
11452
+ * config issues surfaced EAGERLY when the node's engine changes — model
11453
+ * substitutions ("chose X, running Y") and zero-build steps ("no model
11454
+ * has a <format> build"). Additive/optional: informational only, never
11455
+ * enforced here — `assertEngineReady` (readiness) still gates inference.
11456
+ * Absent/empty when the node-default tree resolves cleanly.
11457
+ */
11458
+ configIssues: array(string()).optional()
11368
11459
  });
11369
11460
  var PipelineStepInputSchema = lazy(() => object({
11370
11461
  addonId: string(),
11371
- modelId: string(),
11462
+ modelId: string().optional(),
11372
11463
  enabled: boolean().default(true),
11373
11464
  children: array(PipelineStepInputSchema).optional(),
11374
11465
  settings: record(string(), unknown()).optional()
11375
11466
  }));
11467
+ var ModelSubstitutionSchema = object({
11468
+ addonId: string(),
11469
+ chosen: string(),
11470
+ running: string(),
11471
+ format: string()
11472
+ });
11473
+ var PipelineValidationIssueSchema = object({
11474
+ addonId: string(),
11475
+ kind: _enum(["unknown-addon", "no-format-build"]),
11476
+ detail: string()
11477
+ });
11478
+ var PipelineValidationResultSchema = object({
11479
+ ok: boolean(),
11480
+ issues: array(PipelineValidationIssueSchema).readonly(),
11481
+ substitutions: array(ModelSubstitutionSchema).readonly(),
11482
+ /** The node's `currentEngine.format` this validation ran against. */
11483
+ format: string()
11484
+ });
11376
11485
  var ReferenceImageEntrySchema = object({
11377
11486
  filename: string(),
11378
11487
  stepIds: array(string()).readonly().optional()
@@ -11485,10 +11594,45 @@ var pipelineExecutorCapability = {
11485
11594
  kind: "mutation",
11486
11595
  auth: "admin"
11487
11596
  }),
11597
+ /**
11598
+ * Reset ONE node's detection-pipeline to its factory defaults, forcing
11599
+ * regeneration of the (now hardware-aware) default object-detection
11600
+ * model. `nodeId` is the ROUTING key — the generated cap-router strips
11601
+ * it (default `nodeIdMode: 'routing'`, same as `getSelectedEngine` /
11602
+ * `getDefaultSteps`) and dispatches to that node, so the provider method
11603
+ * runs ON the target node and receives no `nodeId`.
11604
+ *
11605
+ * Clears the node's persisted global pipeline seed (`pipelineSteps`) +
11606
+ * legacy engine blob (`pipelineEngine`) and every device's per-camera
11607
+ * step overrides, then re-seeds the hardware-aware default tree. Returns
11608
+ * the regenerated object-detection model id (null when the default tree
11609
+ * has no detector for this node's engine format) so the caller can
11610
+ * verify the reset without a second round-trip.
11611
+ */
11612
+ resetToDefault: method(object({ nodeId: string() }), object({
11613
+ success: literal(true),
11614
+ regeneratedModelId: string().nullable()
11615
+ }), {
11616
+ kind: "mutation",
11617
+ auth: "admin"
11618
+ }),
11488
11619
  getSchema: method(_void(), PipelineSchemaSchema),
11489
11620
  getGlobalSteps: method(_void(), array(PipelineDefaultStepSchema).readonly().nullable()),
11490
11621
  getGlobalPipelineConfig: method(_void(), PipelineConfigBridge),
11491
11622
  getOrchestratorConfigSchema: method(_void(), ConfigUISchemaBridge),
11623
+ /**
11624
+ * Gate B (pre-init config-correctness gate). PURE COMPUTE against this
11625
+ * node's `currentEngine.format` — resolves `steps` the same way the
11626
+ * runtime dispatch path would, and reports what WOULD happen without
11627
+ * touching any node-global state. Called by the orchestrator at attach
11628
+ * time (`attachOn`), node-pinned to the TARGET node, so config problems
11629
+ * surface BEFORE `pipelineRunner.attachCamera` rather than at the first
11630
+ * per-frame resolve. `ok` is false iff `issues` is non-empty (both
11631
+ * `unknown-addon` and `no-format-build` are HARD issues); `substitutions`
11632
+ * is informational (a degraded-but-loadable model swap) and never
11633
+ * affects `ok`. Never throws.
11634
+ */
11635
+ validatePipeline: method(object({ steps: array(PipelineStepInputSchema) }), PipelineValidationResultSchema),
11492
11636
  listTemplates: method(_void(), array(PipelineTemplateSchema$1).readonly()),
11493
11637
  saveTemplate: method(object({
11494
11638
  name: string(),
@@ -11838,6 +11982,13 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
11838
11982
  kind: literal("remote-restream"),
11839
11983
  /** The camera's source-owner node (slice 1: always the hub). */
11840
11984
  ownerNodeId: string(),
11985
+ /**
11986
+ * The owner's LAN-reachable host, resolved by the orchestrator from the
11987
+ * per-node `reachableHost` override (Cluster UI). When present the runner
11988
+ * dials THIS host for the owner's restream, in preference to the
11989
+ * `CAMSTACK_HUB_URL`-derived default. Absent → auto-detect fallback.
11990
+ */
11991
+ ownerReachableHost: string().optional(),
11841
11992
  /** Operator override for the owner host the runner dials. */
11842
11993
  hubHostnameOverride: string().optional()
11843
11994
  })]).describe("Per-camera frame-source mode for the runner (P2c)");
@@ -11846,13 +11997,11 @@ var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal
11846
11997
  * specific runner instance via `attachCamera`. Carries everything the
11847
11998
  * runner needs to subscribe to the local broker and execute inference.
11848
11999
  *
11849
- * Stateless-pipeline model: the full pipeline content (`engine`, `steps`,
11850
- * optional `audio`) travels with the attach payload. The runner keeps it
11851
- * in RAM for the lifetime of the attach — on rebalance, edit, or
11852
- * restart the orchestrator re-sends the latest snapshot.
11853
- *
11854
- * `engine`/`steps`/`audio` are optional during the additive migration
11855
- * window; once orchestrator + UI are migrated they become required.
12000
+ * Stateless-pipeline model: the pipeline content (`steps`, optional
12001
+ * `audio`) travels with the attach payload. The runner keeps it in RAM
12002
+ * for the lifetime of the attach — on rebalance, edit, or restart the
12003
+ * orchestrator re-sends the latest snapshot. Engine is NOT carried: it is
12004
+ * node-local, resolved by the executing runner at dispatch time.
11856
12005
  */
11857
12006
  var RunnerCameraConfigSchema = object({
11858
12007
  deviceId: number(),
@@ -11903,14 +12052,11 @@ var RunnerCameraConfigSchema = object({
11903
12052
  */
11904
12053
  motionSources: MotionSourcesSchema.default(["analyzer"]),
11905
12054
  pipelineEnabled: boolean().default(true),
11906
- /** Engine choice for video steps (runtime+backend+format). */
11907
- engine: PipelineEngineChoiceSchema.optional(),
11908
12055
  /** Ordered tree of video steps. Absent → runner skips video detection. */
11909
12056
  steps: array(PipelineStepInputSchema).readonly().optional(),
11910
12057
  /** Audio classification branch. `enabled:false` disables, null skips. */
11911
12058
  audio: object({
11912
- engine: PipelineEngineChoiceSchema,
11913
- modelId: string(),
12059
+ modelId: string().optional(),
11914
12060
  enabled: boolean()
11915
12061
  }).nullable().optional(),
11916
12062
  /**
@@ -16396,11 +16542,11 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16396
16542
  timestamp: number()
16397
16543
  });
16398
16544
  var CameraPipelineConfigSchema = object({
16399
- engine: PipelineEngineChoiceSchema,
16545
+ engine: PipelineEngineChoiceSchema.optional(),
16400
16546
  steps: array(PipelineStepInputSchema).readonly(),
16401
16547
  audio: object({
16402
- engine: PipelineEngineChoiceSchema,
16403
- modelId: string(),
16548
+ engine: PipelineEngineChoiceSchema.optional(),
16549
+ modelId: string().optional(),
16404
16550
  enabled: boolean(),
16405
16551
  settings: record(string(), unknown()).readonly().optional()
16406
16552
  }).nullable().optional()
@@ -16415,7 +16561,7 @@ var PipelineTemplateSchema = object({
16415
16561
  });
16416
16562
  var AgentAddonConfigSchema = object({
16417
16563
  enabled: boolean(),
16418
- modelId: string(),
16564
+ modelId: string().optional(),
16419
16565
  settings: record(string(), unknown()).readonly()
16420
16566
  });
16421
16567
  var AgentPipelineSettingsSchema = object({
@@ -16430,7 +16576,15 @@ var AgentPipelineSettingsSchema = object({
16430
16576
  /** Node is eligible to run audio-analyzer sessions. */
16431
16577
  audio: boolean().optional(),
16432
16578
  /** Node is eligible to be the ingest / source-owner (serve the restream). */
16433
- ingest: boolean().optional()
16579
+ ingest: boolean().optional(),
16580
+ /**
16581
+ * Operator override for the LAN host a cross-node decoder dials to reach
16582
+ * THIS node's restream (Cluster UI). Absent → auto-detect: a remote runner
16583
+ * falls back to its `CAMSTACK_HUB_URL`-derived host (the Moleculer address
16584
+ * it already uses to reach the hub). Set this only when the auto-detected
16585
+ * address is wrong (multi-homed host, NAT, custom interface).
16586
+ */
16587
+ reachableHost: string().optional()
16434
16588
  });
16435
16589
  var CameraPipelineForAgentSchema = object({
16436
16590
  steps: array(PipelineStepInputSchema).readonly(),
@@ -16536,6 +16690,15 @@ var GlobalMetricsSchema = object({
16536
16690
  * capability providers.
16537
16691
  */
16538
16692
  var CapabilityBindingsSchema = record(string(), string());
16693
+ /**
16694
+ * The cluster's single camera-source owner (`clusterRoles.ingestNode`) plus
16695
+ * its LAN-reachable host, if one is registered. See `getIngestOwner`.
16696
+ */
16697
+ var IngestOwnerSchema = object({
16698
+ ownerNodeId: string(),
16699
+ reachableHost: string().optional(),
16700
+ configIssue: string().optional()
16701
+ });
16539
16702
  /** Source block — always present; derives from the stream catalog. */
16540
16703
  var CameraSourceStatusSchema = object({ streams: array(object({
16541
16704
  camStreamId: string(),
@@ -16550,6 +16713,14 @@ var CameraAssignmentStatusSchema = object({
16550
16713
  detectionNodeId: string().nullable(),
16551
16714
  decoderNodeId: string().nullable(),
16552
16715
  audioNodeId: string().nullable(),
16716
+ /**
16717
+ * The node that OWNS this camera's physical source pull (dials the RTSP and
16718
+ * hosts the broker/restream) — the cluster ingest owner today
16719
+ * (`clusterRoles.ingestNode`), per-camera once source assignment lands. Lets
16720
+ * the UI show WHERE a camera is sourced without SSH/logs, and is the node the
16721
+ * broker block below was read from (pinned). Nullable only pre-wiring.
16722
+ */
16723
+ sourceNodeId: string().nullable(),
16553
16724
  pinned: object({
16554
16725
  detection: boolean(),
16555
16726
  decoder: boolean(),
@@ -16682,7 +16853,7 @@ method(object({
16682
16853
  }), object({ success: literal(true) }), {
16683
16854
  kind: "mutation",
16684
16855
  auth: "admin"
16685
- }), method(object({
16856
+ }), method(_void(), IngestOwnerSchema), method(object({
16686
16857
  deviceId: number(),
16687
16858
  nodeId: string()
16688
16859
  }), _void(), {
@@ -16751,6 +16922,12 @@ method(object({
16751
16922
  }), object({ success: literal(true) }), {
16752
16923
  kind: "mutation",
16753
16924
  auth: "admin"
16925
+ }), method(object({
16926
+ agentNodeId: string(),
16927
+ reachableHost: string().nullable()
16928
+ }), object({ success: literal(true) }), {
16929
+ kind: "mutation",
16930
+ auth: "admin"
16754
16931
  }), method(object({ deviceId: number() }), CameraPipelineSettingsSchema.nullable()), method(object({
16755
16932
  deviceId: number(),
16756
16933
  addonId: string(),
@@ -16795,22 +16972,6 @@ method(object({
16795
16972
  kind: "mutation",
16796
16973
  auth: "admin"
16797
16974
  });
16798
- var RegisteredStreamSchema = object({
16799
- streamId: string(),
16800
- label: string().optional(),
16801
- codec: string(),
16802
- type: _enum(["video", "audio"]),
16803
- sourceUrl: string()
16804
- });
16805
- var ExposedResourceSchema = object({
16806
- streamId: string(),
16807
- format: string(),
16808
- value: string()
16809
- });
16810
- method(object({
16811
- deviceId: number(),
16812
- streams: array(RegisteredStreamSchema).readonly()
16813
- }), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), _void(), { kind: "mutation" }), method(object({ deviceId: number() }), array(ExposedResourceSchema).readonly());
16814
16975
  /**
16815
16976
  * Query filter for settings-store collections.
16816
16977
  */
@@ -16963,9 +17124,9 @@ method(SendEmailInputSchema, SendEmailResultSchema, {
16963
17124
  /**
16964
17125
  * A single device snapshot returned as base64 JPEG/PNG.
16965
17126
  *
16966
- * Shared with the `snapshot-provider` collection cap the orchestrator
16967
- * receives the same shape from each native provider and from the
16968
- * broker-based fallback.
17127
+ * The `SnapshotAddon` wrapper returns this shape whether the frame came from
17128
+ * the device-native provider (onboard capture) or from the stream-broker
17129
+ * prebuffer fallback.
16969
17130
  */
16970
17131
  var SnapshotImageSchema = object({
16971
17132
  base64: string(),
@@ -16997,10 +17158,6 @@ DeviceType.Camera, method(object({
16997
17158
  kind: "mutation",
16998
17159
  auth: "admin"
16999
17160
  });
17000
- method(object({ deviceId: number() }), boolean()), method(object({
17001
- deviceId: number(),
17002
- streamId: string().optional()
17003
- }), SnapshotImageSchema.nullable());
17004
17161
  /**
17005
17162
  * `sso-bridge` — internal hub-only cap that lets SSO-style auth
17006
17163
  * providers (OIDC, SAML, magic-link, …) mint an HMAC-signed token
@@ -17376,9 +17533,10 @@ method(object({
17376
17533
  auth: "admin"
17377
17534
  });
17378
17535
  /**
17379
- * Optional client-side hints sent at session creation to help the
17380
- * provider pick the best native source. All fields are optional —
17381
- * a viewer that knows nothing still gets a sane default.
17536
+ * Optional client-side hints sent at session creation to help the provider
17537
+ * pick the best native source. All fields optional — a viewer that knows
17538
+ * nothing still gets a sane default. (Relocated from the retired `webrtc`
17539
+ * collection cap; this `webrtc-session` cap is the live signaling surface.)
17382
17540
  */
17383
17541
  var webrtcClientHintsSchema = object({
17384
17542
  viewportWidth: number().int().positive().optional(),
@@ -17389,22 +17547,6 @@ var webrtcClientHintsSchema = object({
17389
17547
  /** Hard tier override; takes precedence over scoring when registered. */
17390
17548
  prefersTier: string().optional()
17391
17549
  }).partial();
17392
- method(object({
17393
- streamId: string(),
17394
- sdpOffer: string()
17395
- }), string(), { kind: "mutation" }), method(object({ streamId: string() }), boolean()), method(object({
17396
- streamId: string(),
17397
- codec: string()
17398
- }), _void(), { kind: "mutation" }), method(object({ streamId: string() }), _void(), { kind: "mutation" }), method(object({
17399
- streamId: string(),
17400
- hints: webrtcClientHintsSchema.optional()
17401
- }), object({
17402
- sessionId: string(),
17403
- sdpOffer: string()
17404
- }), { kind: "mutation" }), method(object({
17405
- sessionId: string(),
17406
- sdpAnswer: string()
17407
- }), _void(), { kind: "mutation" }), method(object({ sessionId: string() }), _void(), { kind: "mutation" }), method(object({ streamId: string() }), boolean());
17408
17550
  /**
17409
17551
  * Discriminated target for a WebRTC session. The client sends this
17410
17552
  * structured object instead of building / parsing brokerId strings;
@@ -17677,7 +17819,7 @@ var webrtcSessionCapability = {
17677
17819
  }).nullable() }))
17678
17820
  },
17679
17821
  /** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
17680
- mount: { kind: "custom" }
17822
+ mount: { kind: "server-provided" }
17681
17823
  };
17682
17824
  object({
17683
17825
  /** All accessory children of the parent. */
@@ -22560,6 +22702,12 @@ Object.freeze({
22560
22702
  addonId: null,
22561
22703
  access: "create"
22562
22704
  },
22705
+ "pipelineExecutor.resetToDefault": {
22706
+ capName: "pipeline-executor",
22707
+ capScope: "system",
22708
+ addonId: null,
22709
+ access: "delete"
22710
+ },
22563
22711
  "pipelineExecutor.runAudioTest": {
22564
22712
  capName: "pipeline-executor",
22565
22713
  capScope: "system",
@@ -22608,6 +22756,12 @@ Object.freeze({
22608
22756
  addonId: null,
22609
22757
  access: "create"
22610
22758
  },
22759
+ "pipelineExecutor.validatePipeline": {
22760
+ capName: "pipeline-executor",
22761
+ capScope: "system",
22762
+ addonId: null,
22763
+ access: "view"
22764
+ },
22611
22765
  "pipelineOrchestrator.assignAudio": {
22612
22766
  capName: "pipeline-orchestrator",
22613
22767
  capScope: "system",
@@ -22716,6 +22870,12 @@ Object.freeze({
22716
22870
  addonId: null,
22717
22871
  access: "view"
22718
22872
  },
22873
+ "pipelineOrchestrator.getIngestOwner": {
22874
+ capName: "pipeline-orchestrator",
22875
+ capScope: "system",
22876
+ addonId: null,
22877
+ access: "view"
22878
+ },
22719
22879
  "pipelineOrchestrator.getPipelineAssignment": {
22720
22880
  capName: "pipeline-orchestrator",
22721
22881
  capScope: "system",
@@ -22788,6 +22948,12 @@ Object.freeze({
22788
22948
  addonId: null,
22789
22949
  access: "create"
22790
22950
  },
22951
+ "pipelineOrchestrator.setAgentReachableHost": {
22952
+ capName: "pipeline-orchestrator",
22953
+ capScope: "system",
22954
+ addonId: null,
22955
+ access: "create"
22956
+ },
22791
22957
  "pipelineOrchestrator.setCameraPipelineForAgent": {
22792
22958
  capName: "pipeline-orchestrator",
22793
22959
  capScope: "system",
@@ -23118,24 +23284,6 @@ Object.freeze({
23118
23284
  addonId: null,
23119
23285
  access: "create"
23120
23286
  },
23121
- "restreamer.getExposedResources": {
23122
- capName: "restreamer",
23123
- capScope: "system",
23124
- addonId: null,
23125
- access: "view"
23126
- },
23127
- "restreamer.registerDevice": {
23128
- capName: "restreamer",
23129
- capScope: "system",
23130
- addonId: null,
23131
- access: "create"
23132
- },
23133
- "restreamer.unregisterDevice": {
23134
- capName: "restreamer",
23135
- capScope: "system",
23136
- addonId: null,
23137
- access: "delete"
23138
- },
23139
23287
  "scriptRunner.run": {
23140
23288
  capName: "script-runner",
23141
23289
  capScope: "device",
@@ -23238,18 +23386,6 @@ Object.freeze({
23238
23386
  addonId: null,
23239
23387
  access: "create"
23240
23388
  },
23241
- "snapshotProvider.getSnapshot": {
23242
- capName: "snapshot-provider",
23243
- capScope: "system",
23244
- addonId: null,
23245
- access: "view"
23246
- },
23247
- "snapshotProvider.supportsDevice": {
23248
- capName: "snapshot-provider",
23249
- capScope: "system",
23250
- addonId: null,
23251
- access: "view"
23252
- },
23253
23389
  "ssoBridge.signBridgeToken": {
23254
23390
  capName: "sso-bridge",
23255
23391
  capScope: "system",
@@ -23676,30 +23812,6 @@ Object.freeze({
23676
23812
  addonId: null,
23677
23813
  access: "view"
23678
23814
  },
23679
- "streamingEngine.getStreamUrl": {
23680
- capName: "streaming-engine",
23681
- capScope: "system",
23682
- addonId: null,
23683
- access: "view"
23684
- },
23685
- "streamingEngine.listStreams": {
23686
- capName: "streaming-engine",
23687
- capScope: "system",
23688
- addonId: null,
23689
- access: "view"
23690
- },
23691
- "streamingEngine.registerStream": {
23692
- capName: "streaming-engine",
23693
- capScope: "system",
23694
- addonId: null,
23695
- access: "create"
23696
- },
23697
- "streamingEngine.unregisterStream": {
23698
- capName: "streaming-engine",
23699
- capScope: "system",
23700
- addonId: null,
23701
- access: "delete"
23702
- },
23703
23815
  "streamParams.getConfigSchema": {
23704
23816
  capName: "stream-params",
23705
23817
  capScope: "device",
@@ -24066,54 +24178,6 @@ Object.freeze({
24066
24178
  addonId: null,
24067
24179
  access: "create"
24068
24180
  },
24069
- "webrtc.closeSession": {
24070
- capName: "webrtc",
24071
- capScope: "system",
24072
- addonId: null,
24073
- access: "create"
24074
- },
24075
- "webrtc.createSession": {
24076
- capName: "webrtc",
24077
- capScope: "system",
24078
- addonId: null,
24079
- access: "create"
24080
- },
24081
- "webrtc.handleAnswer": {
24082
- capName: "webrtc",
24083
- capScope: "system",
24084
- addonId: null,
24085
- access: "create"
24086
- },
24087
- "webrtc.handleOffer": {
24088
- capName: "webrtc",
24089
- capScope: "system",
24090
- addonId: null,
24091
- access: "create"
24092
- },
24093
- "webrtc.hasAdaptiveBitrate": {
24094
- capName: "webrtc",
24095
- capScope: "system",
24096
- addonId: null,
24097
- access: "view"
24098
- },
24099
- "webrtc.registerStream": {
24100
- capName: "webrtc",
24101
- capScope: "system",
24102
- addonId: null,
24103
- access: "create"
24104
- },
24105
- "webrtc.supportsStream": {
24106
- capName: "webrtc",
24107
- capScope: "system",
24108
- addonId: null,
24109
- access: "view"
24110
- },
24111
- "webrtc.unregisterStream": {
24112
- capName: "webrtc",
24113
- capScope: "system",
24114
- addonId: null,
24115
- access: "delete"
24116
- },
24117
24181
  "webrtcSession.addIceCandidate": {
24118
24182
  capName: "webrtc-session",
24119
24183
  capScope: "device",
@@ -24660,6 +24724,12 @@ Object.defineProperty(exports, "hydrateSchema", {
24660
24724
  return hydrateSchema;
24661
24725
  }
24662
24726
  });
24727
+ Object.defineProperty(exports, "isEvent", {
24728
+ enumerable: true,
24729
+ get: function() {
24730
+ return isEvent;
24731
+ }
24732
+ });
24663
24733
  Object.defineProperty(exports, "lazy", {
24664
24734
  enumerable: true,
24665
24735
  get: function() {