@camstack/addon-provider-dreame 0.2.123 → 0.2.125

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 (3) hide show
  1. package/dist/addon.js +305 -19
  2. package/dist/addon.mjs +305 -19
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -58282,7 +58282,7 @@ var ZodIssueCode = {
58282
58282
  var ZodFirstPartyTypeKind;
58283
58283
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
58284
58284
  //#endregion
58285
- //#region ../types/dist/sleep-DXKLNFvA.mjs
58285
+ //#region ../types/dist/sleep-C16NCZR2.mjs
58286
58286
  /**
58287
58287
  * The audio chunk plane's byte format, and the ONE expansion from a coded
58288
58288
  * window to float samples (D455).
@@ -63368,6 +63368,15 @@ var ClipSearchStrictnessSchema = _enum([
63368
63368
  "balanced",
63369
63369
  "strict"
63370
63370
  ]);
63371
+ /** Steps whose effect a root label can BE. */
63372
+ var LABEL_SUPPLY_STEP_IDS = [
63373
+ "animal-classifier",
63374
+ "vehicle-classifier",
63375
+ "package-detection"
63376
+ ];
63377
+ /** Steps whose box a root detection can BE. */
63378
+ var CROP_SUPPLY_STEP_IDS = ["plate-detection", "face-detection"];
63379
+ [...LABEL_SUPPLY_STEP_IDS, ...CROP_SUPPLY_STEP_IDS];
63371
63380
  var MODEL_FORMATS = [
63372
63381
  "onnx",
63373
63382
  "coreml",
@@ -63500,6 +63509,35 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
63500
63509
  /** True when the weights or their data forbid commercial use. */
63501
63510
  nonCommercial: boolean().optional()
63502
63511
  }));
63512
+ /**
63513
+ * One step a ROOT detector can supply from its own output (D730) — see
63514
+ * `ModelCatalogEntry.suppliesSteps`.
63515
+ *
63516
+ * - `label`: the root's raw class IS the step's answer. `labelToEffect` maps
63517
+ * the root's label to the step's vocabulary; `uncovered` is the vocabulary
63518
+ * the root cannot produce (shown as unavailable, never a blocker).
63519
+ * - `crop`: the root draws the box the step would have found (`license_plate`
63520
+ * for plate-detection, `face` for face-detection). The box becomes a detail
63521
+ * child of the `parentMacro` detection that contains it — never a track.
63522
+ */
63523
+ var RootStepSupplySchema = discriminatedUnion("kind", [object({
63524
+ kind: literal("label"),
63525
+ stepId: _enum(LABEL_SUPPLY_STEP_IDS),
63526
+ labelToEffect: record(string(), string()),
63527
+ uncovered: array(string()).readonly()
63528
+ }), object({
63529
+ kind: literal("crop"),
63530
+ stepId: _enum(CROP_SUPPLY_STEP_IDS),
63531
+ rootLabels: array(string()).readonly(),
63532
+ parentMacro: _enum(["vehicle", "person"]),
63533
+ childClass: _enum(["plate", "face"]),
63534
+ /**
63535
+ * The root's smaller input side, stamped on read by `rootSuppliesOf` from
63536
+ * the model entry — what a step's `minRootInputPx` gate judges. Never
63537
+ * stored by an import.
63538
+ */
63539
+ rootInputPx: number().int().positive().optional()
63540
+ })]);
63503
63541
  var ModelCatalogEntrySchema = object({
63504
63542
  id: string(),
63505
63543
  name: string(),
@@ -63626,6 +63664,16 @@ var ModelCatalogEntrySchema = object({
63626
63664
  */
63627
63665
  classMap: DetectionCatalogClassMapSchema.optional(),
63628
63666
  /**
63667
+ * The pipeline steps this ROOT detector can supply from its own output
63668
+ * (D730): its labels name a step's effect (`deer` for `animal-classifier`)
63669
+ * or draw a step's box (`license_plate` for `plate-detection`). Computed at
63670
+ * import from THIS model's labelmap by `deriveRootSupplies`, never written
63671
+ * by hand and never assumed per family; a row without it is derived on read
63672
+ * (`rootSuppliesOf`). Whether a camera uses it is the step's own
63673
+ * `useRootModel` flag (`resolveRootSupply`).
63674
+ */
63675
+ suppliesSteps: array(RootStepSupplySchema).readonly().optional(),
63676
+ /**
63629
63677
  * The model's CLIP feature-space contract (text encoder, dimension, vector
63630
63678
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
63631
63679
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -69091,6 +69139,18 @@ method(_void(), array(string()).readonly(), { auth: "admin" }), method(object({
69091
69139
  kind: "mutation",
69092
69140
  auth: "admin"
69093
69141
  });
69142
+ function hostnameOf(baseUrl) {
69143
+ try {
69144
+ const host = new URL(baseUrl).hostname;
69145
+ return host.length > 0 ? host : null;
69146
+ } catch {
69147
+ return null;
69148
+ }
69149
+ }
69150
+ /** The bare hostname of a base URL, or `null` when it does not parse. */
69151
+ function hubAddressHostname(baseUrl) {
69152
+ return baseUrl === null ? null : hostnameOf(baseUrl);
69153
+ }
69094
69154
  /**
69095
69155
  * Transport bounds for AI capability methods.
69096
69156
  *
@@ -71693,6 +71753,8 @@ var NcSystemEventKindSchema = _enum([
71693
71753
  "stream-offline",
71694
71754
  "node-online",
71695
71755
  "node-offline",
71756
+ "node-restarting",
71757
+ "node-updating",
71696
71758
  "node-inference-unavailable",
71697
71759
  "detection-blind",
71698
71760
  "addon-crash-loop",
@@ -76210,6 +76272,34 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
76210
76272
  timestamp: number()
76211
76273
  });
76212
76274
  /**
76275
+ * A root model's boxes standing in for one crop-kind step's own inference
76276
+ * (D730) — see `runPipeline.suppliedRoot`.
76277
+ */
76278
+ var SuppliedRootOutputSchema = object({
76279
+ stepId: string(),
76280
+ /** The root model that drew the boxes — stamped on the result. */
76281
+ modelId: string(),
76282
+ detections: array(object({
76283
+ /** `[x1, y1, x2, y2]` in the pixels of the call's image. */
76284
+ bbox: tuple([
76285
+ number(),
76286
+ number(),
76287
+ number(),
76288
+ number()
76289
+ ]),
76290
+ score: number(),
76291
+ /**
76292
+ * Five facial landmarks in the same pixels — a face the step's own
76293
+ * detector already re-found inside a root face box (D730), so its
76294
+ * embedder child aligns it exactly as it aligns any detected face.
76295
+ */
76296
+ landmarks: array(object({
76297
+ x: number(),
76298
+ y: number()
76299
+ })).optional()
76300
+ })).min(1)
76301
+ });
76302
+ /**
76213
76303
  * Reference to the frame's retained NATIVE surface + the parent crop's placement
76214
76304
  * within the frame, so the executor can re-cut a leaf child ROI at native
76215
76305
  * resolution on the detail plane. See the `runPipeline` `nativeCropRef` field.
@@ -76339,7 +76429,8 @@ var PipelineModelOptionSchema = object({
76339
76429
  group: ModelVariantGroupSchema.optional(),
76340
76430
  legacy: boolean().optional(),
76341
76431
  provider: ModelProviderIdSchema.optional(),
76342
- defaultConfidence: number().optional()
76432
+ defaultConfidence: number().optional(),
76433
+ suppliesSteps: array(RootStepSupplySchema).readonly().optional()
76343
76434
  });
76344
76435
  var ConfigFieldBridge = custom();
76345
76436
  var PipelineAddonSchemaSchema = object({
@@ -76607,7 +76698,16 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
76607
76698
  * `device-not-servable`), and nothing reaches the camera's live
76608
76699
  * trace stream. Absent ⇒ unchanged behaviour.
76609
76700
  */
76610
- replay: literal(true).optional()
76701
+ replay: literal(true).optional(),
76702
+ /**
76703
+ * Root-supplied detections for the tree's ROOT step (D730). Set by
76704
+ * `runDetailSubtree` when the camera's root model supplies a crop-kind
76705
+ * step (a Frigate+ `license_plate` for `plate-detection`): the step is
76706
+ * NOT inferred, these boxes are its output, and its children (the plate
76707
+ * reader) run on them through their own crop policy. Boxes are in the
76708
+ * PIXELS of the image this call carries. Absent ⇒ the root step runs.
76709
+ */
76710
+ suppliedRoot: SuppliedRootOutputSchema.optional()
76611
76711
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
76612
76712
  steps: array(PipelineStepInputSchema).min(1),
76613
76713
  frames: array(FrameInputSchema).min(1).max(255),
@@ -77749,7 +77849,22 @@ method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mu
77749
77849
  */
77750
77850
  cropJpeg: string().optional(),
77751
77851
  parent: DetailParentSchema,
77752
- steps: array(string()).optional()
77852
+ steps: array(string()).optional(),
77853
+ /**
77854
+ * The camera's root model already drew this step's boxes (D730): a
77855
+ * `license_plate` inside the parent vehicle. The named step is NOT
77856
+ * inferred — these FRAME-space boxes are its output — and its
77857
+ * requested children (the plate reader) run on them. Absent ⇒ every
77858
+ * requested step infers as before.
77859
+ */
77860
+ supplied: object({
77861
+ stepId: string(),
77862
+ modelId: string(),
77863
+ boxes: array(object({
77864
+ bbox: NativeCropBboxSchema,
77865
+ score: number()
77866
+ })).min(1)
77867
+ }).optional()
77753
77868
  }), object({ details: array(DetailResultSchema) }).nullable(), { kind: "mutation" }), method(object({
77754
77869
  /** Catalog step id, e.g. `clip-embedding`. */
77755
77870
  stepId: string(),
@@ -81079,6 +81194,14 @@ DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), ar
81079
81194
  */
81080
81195
  alive: boolean()
81081
81196
  })), method(object({
81197
+ deviceId: number().int().nonnegative(),
81198
+ sessionId: string(),
81199
+ downlinkMbps: number().nonnegative()
81200
+ }), object({
81201
+ outcome: _enum(["switching", "held"]),
81202
+ tier: CamProfileSchema.nullable(),
81203
+ reason: string()
81204
+ }), { kind: "mutation" }), method(object({
81082
81205
  deviceId: number().int().nonnegative(),
81083
81206
  sessionId: string()
81084
81207
  }), WebrtcSessionDebugSchema, { kind: "query" });
@@ -84915,7 +85038,8 @@ var ConnectionEndpointSchema = object({
84915
85038
  "lan-ipv6",
84916
85039
  "public",
84917
85040
  "loopback",
84918
- "app-link"
85041
+ "app-link",
85042
+ "custom"
84919
85043
  ]),
84920
85044
  /**
84921
85045
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -85017,6 +85141,76 @@ var ViewerEndpointsSchema = object({
85017
85141
  /** What the ranking currently resolves to (may be empty if nothing is up). */
85018
85142
  resolved: array(string()).readonly()
85019
85143
  });
85144
+ /**
85145
+ * DEPRECATED compatibility shape of `getHubAddresses` (D729 amendment, kept
85146
+ * one release for addons built against it): `cluster` is the `agents` role,
85147
+ * `browser` the `signIn` role; `override` is the flagged address.
85148
+ */
85149
+ var HubAddressSnapshotSchema = object({
85150
+ override: string().nullable(),
85151
+ resolved: string().nullable(),
85152
+ source: _enum([
85153
+ "override",
85154
+ "auto",
85155
+ "none"
85156
+ ])
85157
+ });
85158
+ var HubAddressesSchema = object({
85159
+ cluster: HubAddressSnapshotSchema,
85160
+ browser: HubAddressSnapshotSchema
85161
+ });
85162
+ /**
85163
+ * What an address is used for (`hub-address.ts`). `viewer` is many-valued;
85164
+ * `notifications`, `agents` and `signIn` are carried by at most one address.
85165
+ */
85166
+ var HubAddressRoleSchema = _enum([
85167
+ "viewer",
85168
+ "notifications",
85169
+ "agents",
85170
+ "signIn"
85171
+ ]);
85172
+ var RoleSourceSchema = _enum([
85173
+ "flagged",
85174
+ "auto",
85175
+ "none"
85176
+ ]);
85177
+ /** One single-valued role: the flagged address, the one in use, and why. */
85178
+ var HubAddressRoleResolutionSchema = object({
85179
+ /** The address carrying the flag, or null = automatic. */
85180
+ flagged: string().nullable(),
85181
+ /** The address in use, or null when nothing qualifies (never loopback). */
85182
+ resolved: string().nullable(),
85183
+ source: RoleSourceSchema
85184
+ });
85185
+ var HubViewerResolutionSchema = object({
85186
+ /** The addresses flagged `viewer`, or empty = automatic. */
85187
+ flagged: array(string()).readonly(),
85188
+ /** What the apps race right now. */
85189
+ resolved: array(string()).readonly(),
85190
+ source: RoleSourceSchema
85191
+ });
85192
+ var HubAddressBookSchema = object({
85193
+ rows: array(ConnectionEndpointSchema.extend({
85194
+ /** In the hub's detected palette right now. */
85195
+ detected: boolean(),
85196
+ /** Entered by the operator (removable). */
85197
+ custom: boolean(),
85198
+ /** The roles explicitly flagged on this address. */
85199
+ flags: array(HubAddressRoleSchema).readonly(),
85200
+ /** The roles this address serves right now — flagged or automatic. */
85201
+ inUse: array(HubAddressRoleSchema).readonly(),
85202
+ /** The roles this address may be flagged with. */
85203
+ eligible: array(HubAddressRoleSchema).readonly()
85204
+ })).readonly(),
85205
+ roles: object({
85206
+ viewer: HubViewerResolutionSchema,
85207
+ notifications: HubAddressRoleResolutionSchema,
85208
+ agents: HubAddressRoleResolutionSchema,
85209
+ signIn: HubAddressRoleResolutionSchema
85210
+ }),
85211
+ /** The `hub=` an app link carries (D709), or null. */
85212
+ appLinkHub: string().nullable()
85213
+ });
85020
85214
  var AllowedAddressesSchema = object({
85021
85215
  /**
85022
85216
  * Allowlist of interface addresses operators have explicitly opted
@@ -85063,7 +85257,24 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
85063
85257
  * an address notification links can be flagged with, not a hub
85064
85258
  * route. Default `false`: racers and rankers never see it. */
85065
85259
  includeAppLink: boolean().optional()
85066
- }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
85260
+ }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(object({ scheme: _enum(["http", "https"]).optional() }).optional(), HubAddressBookSchema), method(object({
85261
+ baseUrl: string(),
85262
+ label: string().max(80)
85263
+ }), HubAddressBookSchema, {
85264
+ kind: "mutation",
85265
+ auth: "admin"
85266
+ }), method(object({ baseUrl: string() }), HubAddressBookSchema, {
85267
+ kind: "mutation",
85268
+ auth: "admin"
85269
+ }), method(object({
85270
+ role: HubAddressRoleSchema,
85271
+ baseUrl: string().nullable(),
85272
+ enabled: boolean(),
85273
+ acceptInsecureHttp: boolean().optional()
85274
+ }), HubAddressBookSchema, {
85275
+ kind: "mutation",
85276
+ auth: "admin"
85277
+ }), method(_void(), HubAddressesSchema), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
85067
85278
  kind: "mutation",
85068
85279
  auth: "admin"
85069
85280
  }), method(object({
@@ -85521,7 +85732,8 @@ var MotionStatusSchema = object({
85521
85732
  * writes this slice (not even a boot seed), and neither does the runner's
85522
85733
  * phase machine: its phase is "a session is attached" for every on-motion
85523
85734
  * session, not motion, and it now has its own `DetectionPhaseTransition`.
85524
- * A provider's `isDetected` answers from the hub's slice.
85735
+ * A provider's `isDetected` and `getStatus` answer from the hub's slice
85736
+ * (`hubMotionNativeProvider`).
85525
85737
  * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
85526
85738
  * imports) — the provider pushes both edges itself, from the upstream
85527
85739
  * system's own state change. That is the sensor's own fact.
@@ -96668,12 +96880,24 @@ Object.freeze({
96668
96880
  addonId: null,
96669
96881
  access: "view"
96670
96882
  },
96883
+ "localNetwork.addCustomAddress": {
96884
+ capName: "local-network",
96885
+ capScope: "system",
96886
+ addonId: null,
96887
+ access: "create"
96888
+ },
96671
96889
  "localNetwork.downloadCa": {
96672
96890
  capName: "local-network",
96673
96891
  capScope: "system",
96674
96892
  addonId: null,
96675
96893
  access: "view"
96676
96894
  },
96895
+ "localNetwork.getAddresses": {
96896
+ capName: "local-network",
96897
+ capScope: "system",
96898
+ addonId: null,
96899
+ access: "view"
96900
+ },
96677
96901
  "localNetwork.getAllowedAddresses": {
96678
96902
  capName: "local-network",
96679
96903
  capScope: "system",
@@ -96686,6 +96910,12 @@ Object.freeze({
96686
96910
  addonId: null,
96687
96911
  access: "view"
96688
96912
  },
96913
+ "localNetwork.getHubAddresses": {
96914
+ capName: "local-network",
96915
+ capScope: "system",
96916
+ addonId: null,
96917
+ access: "view"
96918
+ },
96689
96919
  "localNetwork.getNotificationEndpoint": {
96690
96920
  capName: "local-network",
96691
96921
  capScope: "system",
@@ -96722,6 +96952,12 @@ Object.freeze({
96722
96952
  addonId: null,
96723
96953
  access: "create"
96724
96954
  },
96955
+ "localNetwork.removeCustomAddress": {
96956
+ capName: "local-network",
96957
+ capScope: "system",
96958
+ addonId: null,
96959
+ access: "delete"
96960
+ },
96725
96961
  "localNetwork.resetAllowlistToBestMatch": {
96726
96962
  capName: "local-network",
96727
96963
  capScope: "system",
@@ -96734,6 +96970,12 @@ Object.freeze({
96734
96970
  addonId: null,
96735
96971
  access: "create"
96736
96972
  },
96973
+ "localNetwork.setAddressRole": {
96974
+ capName: "local-network",
96975
+ capScope: "system",
96976
+ addonId: null,
96977
+ access: "create"
96978
+ },
96737
96979
  "localNetwork.setAllowedAddresses": {
96738
96980
  capName: "local-network",
96739
96981
  capScope: "system",
@@ -100988,6 +101230,12 @@ Object.freeze({
100988
101230
  addonId: null,
100989
101231
  access: "create"
100990
101232
  },
101233
+ "webrtcSession.applyDownlinkProbe": {
101234
+ capName: "webrtc-session",
101235
+ capScope: "device",
101236
+ addonId: null,
101237
+ access: "create"
101238
+ },
100991
101239
  "webrtcSession.closeSession": {
100992
101240
  capName: "webrtc-session",
100993
101241
  capScope: "device",
@@ -104910,6 +105158,11 @@ Object.freeze({
104910
105158
  form: "single",
104911
105159
  optional: false
104912
105160
  }],
105161
+ "webrtcSession.applyDownlinkProbe": [{
105162
+ name: "deviceId",
105163
+ form: "single",
105164
+ optional: false
105165
+ }],
104913
105166
  "webrtcSession.closeSession": [{
104914
105167
  name: "deviceId",
104915
105168
  form: "single",
@@ -105139,6 +105392,8 @@ new Map(Object.entries({
105139
105392
  "detection-blind": "device-events",
105140
105393
  "node-online": "system",
105141
105394
  "node-offline": "system",
105395
+ "node-restarting": "system",
105396
+ "node-updating": "system",
105142
105397
  "node-inference-unavailable": "system",
105143
105398
  "addon-crash-loop": "system",
105144
105399
  "addon-update-available": "system",
@@ -105216,6 +105471,7 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
105216
105471
  kinds: [
105217
105472
  "node-offline",
105218
105473
  "node-online",
105474
+ "node-restarting",
105219
105475
  "node-inference-unavailable"
105220
105476
  ]
105221
105477
  },
@@ -105237,6 +105493,7 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
105237
105493
  label: "Server & container updates",
105238
105494
  kinds: [
105239
105495
  "server-update-available",
105496
+ "node-updating",
105240
105497
  "server-updated",
105241
105498
  "wrapper-update-available"
105242
105499
  ]
@@ -105384,6 +105641,7 @@ var STATE_SUMMARY_SECTION_VARS = [
105384
105641
  kinds: [
105385
105642
  "node-offline",
105386
105643
  "node-online",
105644
+ "node-restarting",
105387
105645
  "node-inference-unavailable"
105388
105646
  ]
105389
105647
  },
@@ -105405,6 +105663,7 @@ var STATE_SUMMARY_SECTION_VARS = [
105405
105663
  example: "server 1.2.377 → 1.2.378",
105406
105664
  kinds: [
105407
105665
  "server-update-available",
105666
+ "node-updating",
105408
105667
  "server-updated",
105409
105668
  "wrapper-update-available"
105410
105669
  ]
@@ -105437,7 +105696,7 @@ var STATE_SUMMARY_VARS = [
105437
105696
  {
105438
105697
  name: "summarySection",
105439
105698
  label: "Summary: this section",
105440
- description: "The section a per-section summary row is about (D698); on a summary sent as one message, every section it reports, comma-separated.",
105699
+ description: "The section a per-section summary row is about; on a summary sent as one message, every section it reports, comma-separated.",
105441
105700
  example: "Batterie scariche",
105442
105701
  group: "system",
105443
105702
  families: ["rule"],
@@ -108438,6 +108697,18 @@ function nextVacuumControlSlice(prev, next) {
108438
108697
  }
108439
108698
  //#endregion
108440
108699
  //#region src/devices/dreame-camera-stream.ts
108700
+ /**
108701
+ * The robot camera as a stream the broker can pull — the pure facts.
108702
+ *
108703
+ * A Dreame relay carries video only between `open()` and `close()`, and the
108704
+ * robot runs on a battery, so the camera cannot sit in the catalog with a
108705
+ * URL the way a mains RTSP camera does. The seam is the broker's own battery
108706
+ * path: `battery.wakeForStream` opens the monitor, and the catalog then
108707
+ * names the local RFC 4571 server (`dreame-rfc4571-server.ts`) the broker
108708
+ * pulls. While the monitor is CLOSED the
108709
+ * catalog carries the broker's lazy sentinel (Reolink's shape): the stream is
108710
+ * listed, and the first dial asks the publisher to materialize it.
108711
+ */
108441
108712
  /** The one stream the robot camera offers. Half of the broker id (`<deviceId>/live`). */
108442
108713
  var CAMERA_STREAM_ID = "live";
108443
108714
  /** The plugin's cap: a monitor never outlives this, whoever is watching. */
@@ -108517,17 +108788,14 @@ function cameraStreamCatalog(session) {
108517
108788
  /**
108518
108789
  * The host the broker is told to dial. The provider and the ingest owner
108519
108790
  * share the hub today, but a broker on another node reaches the hub only
108520
- * through its public address — which is what `CAMSTACK_HUB_PUBLIC_URL` is
108521
- * for. Loopback when nothing better is known.
108791
+ * through the hub's address for agents — `local-network.getAddresses()
108792
+ * .roles.agents` (the address flagged "Agents" on the Network page, else the
108793
+ * detected LAN address).
108794
+ * Loopback when that names nothing: then the only broker that can dial at
108795
+ * all is this node's own.
108522
108796
  */
108523
- function advertisedRfcHost(hubPublicUrl) {
108524
- if (hubPublicUrl === void 0 || hubPublicUrl.length === 0) return "127.0.0.1";
108525
- try {
108526
- const host = new URL(hubPublicUrl).hostname;
108527
- return host.length > 0 ? host : "127.0.0.1";
108528
- } catch {
108529
- return "127.0.0.1";
108530
- }
108797
+ function advertisedRfcHost(clusterBaseUrl) {
108798
+ return hubAddressHostname(clusterBaseUrl) ?? "127.0.0.1";
108531
108799
  }
108532
108800
  function rfcUrl(host, port) {
108533
108801
  return `tcp://${host}:${String(port)}`;
@@ -154917,6 +155185,24 @@ var DreameCameraDevice = class extends DreameChildDevice {
154917
155185
  }
154918
155186
  unsubscribeRefresh = null;
154919
155187
  /** Register the stream on the broker — the server, or the lazy sentinel (push semantics; the catalog is the durable copy). */
155188
+ /**
155189
+ * The hub's address for agents and LAN devices
155190
+ * (`local-network.getAddresses().roles.agents`: the address flagged
155191
+ * "Agents" on the Network page, else the detected LAN address). A failed
155192
+ * read is `null` — `advertisedRfcHost` then answers loopback, which this
155193
+ * node's own broker can still dial.
155194
+ */
155195
+ async hubClusterAddress() {
155196
+ try {
155197
+ return (await this.ctx.api.localNetwork.getAddresses.query()).roles.agents.resolved;
155198
+ } catch (err) {
155199
+ this.ctx.logger.warn("robot camera: hub address unavailable — advertising loopback", {
155200
+ tags: { deviceId: this.id },
155201
+ meta: { error: err instanceof Error ? err.message : String(err) }
155202
+ });
155203
+ return null;
155204
+ }
155205
+ }
154920
155206
  async publishRelay(session) {
154921
155207
  const [descriptor] = cameraStreamCatalog(session);
154922
155208
  if (descriptor === void 0) return;
@@ -155002,7 +155288,7 @@ var DreameCameraDevice = class extends DreameChildDevice {
155002
155288
  rfc
155003
155289
  };
155004
155290
  this.session = {
155005
- url: rfcUrl(advertisedRfcHost(process.env.CAMSTACK_HUB_PUBLIC_URL), rfc.port),
155291
+ url: rfcUrl(advertisedRfcHost(await this.hubClusterAddress()), rfc.port),
155006
155292
  sdp: rfc.sdp
155007
155293
  };
155008
155294
  this.sessionOpenedAt = Date.now();
package/dist/addon.mjs CHANGED
@@ -58279,7 +58279,7 @@ var ZodIssueCode = {
58279
58279
  var ZodFirstPartyTypeKind;
58280
58280
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
58281
58281
  //#endregion
58282
- //#region ../types/dist/sleep-DXKLNFvA.mjs
58282
+ //#region ../types/dist/sleep-C16NCZR2.mjs
58283
58283
  /**
58284
58284
  * The audio chunk plane's byte format, and the ONE expansion from a coded
58285
58285
  * window to float samples (D455).
@@ -63365,6 +63365,15 @@ var ClipSearchStrictnessSchema = _enum([
63365
63365
  "balanced",
63366
63366
  "strict"
63367
63367
  ]);
63368
+ /** Steps whose effect a root label can BE. */
63369
+ var LABEL_SUPPLY_STEP_IDS = [
63370
+ "animal-classifier",
63371
+ "vehicle-classifier",
63372
+ "package-detection"
63373
+ ];
63374
+ /** Steps whose box a root detection can BE. */
63375
+ var CROP_SUPPLY_STEP_IDS = ["plate-detection", "face-detection"];
63376
+ [...LABEL_SUPPLY_STEP_IDS, ...CROP_SUPPLY_STEP_IDS];
63368
63377
  var MODEL_FORMATS = [
63369
63378
  "onnx",
63370
63379
  "coreml",
@@ -63497,6 +63506,35 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
63497
63506
  /** True when the weights or their data forbid commercial use. */
63498
63507
  nonCommercial: boolean().optional()
63499
63508
  }));
63509
+ /**
63510
+ * One step a ROOT detector can supply from its own output (D730) — see
63511
+ * `ModelCatalogEntry.suppliesSteps`.
63512
+ *
63513
+ * - `label`: the root's raw class IS the step's answer. `labelToEffect` maps
63514
+ * the root's label to the step's vocabulary; `uncovered` is the vocabulary
63515
+ * the root cannot produce (shown as unavailable, never a blocker).
63516
+ * - `crop`: the root draws the box the step would have found (`license_plate`
63517
+ * for plate-detection, `face` for face-detection). The box becomes a detail
63518
+ * child of the `parentMacro` detection that contains it — never a track.
63519
+ */
63520
+ var RootStepSupplySchema = discriminatedUnion("kind", [object({
63521
+ kind: literal("label"),
63522
+ stepId: _enum(LABEL_SUPPLY_STEP_IDS),
63523
+ labelToEffect: record(string(), string()),
63524
+ uncovered: array(string()).readonly()
63525
+ }), object({
63526
+ kind: literal("crop"),
63527
+ stepId: _enum(CROP_SUPPLY_STEP_IDS),
63528
+ rootLabels: array(string()).readonly(),
63529
+ parentMacro: _enum(["vehicle", "person"]),
63530
+ childClass: _enum(["plate", "face"]),
63531
+ /**
63532
+ * The root's smaller input side, stamped on read by `rootSuppliesOf` from
63533
+ * the model entry — what a step's `minRootInputPx` gate judges. Never
63534
+ * stored by an import.
63535
+ */
63536
+ rootInputPx: number().int().positive().optional()
63537
+ })]);
63500
63538
  var ModelCatalogEntrySchema = object({
63501
63539
  id: string(),
63502
63540
  name: string(),
@@ -63623,6 +63661,16 @@ var ModelCatalogEntrySchema = object({
63623
63661
  */
63624
63662
  classMap: DetectionCatalogClassMapSchema.optional(),
63625
63663
  /**
63664
+ * The pipeline steps this ROOT detector can supply from its own output
63665
+ * (D730): its labels name a step's effect (`deer` for `animal-classifier`)
63666
+ * or draw a step's box (`license_plate` for `plate-detection`). Computed at
63667
+ * import from THIS model's labelmap by `deriveRootSupplies`, never written
63668
+ * by hand and never assumed per family; a row without it is derived on read
63669
+ * (`rootSuppliesOf`). Whether a camera uses it is the step's own
63670
+ * `useRootModel` flag (`resolveRootSupply`).
63671
+ */
63672
+ suppliesSteps: array(RootStepSupplySchema).readonly().optional(),
63673
+ /**
63626
63674
  * The model's CLIP feature-space contract (text encoder, dimension, vector
63627
63675
  * index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
63628
63676
  * CLIP image encoder; its absence is what "not a CLIP model" means to the
@@ -69088,6 +69136,18 @@ method(_void(), array(string()).readonly(), { auth: "admin" }), method(object({
69088
69136
  kind: "mutation",
69089
69137
  auth: "admin"
69090
69138
  });
69139
+ function hostnameOf(baseUrl) {
69140
+ try {
69141
+ const host = new URL(baseUrl).hostname;
69142
+ return host.length > 0 ? host : null;
69143
+ } catch {
69144
+ return null;
69145
+ }
69146
+ }
69147
+ /** The bare hostname of a base URL, or `null` when it does not parse. */
69148
+ function hubAddressHostname(baseUrl) {
69149
+ return baseUrl === null ? null : hostnameOf(baseUrl);
69150
+ }
69091
69151
  /**
69092
69152
  * Transport bounds for AI capability methods.
69093
69153
  *
@@ -71690,6 +71750,8 @@ var NcSystemEventKindSchema = _enum([
71690
71750
  "stream-offline",
71691
71751
  "node-online",
71692
71752
  "node-offline",
71753
+ "node-restarting",
71754
+ "node-updating",
71693
71755
  "node-inference-unavailable",
71694
71756
  "detection-blind",
71695
71757
  "addon-crash-loop",
@@ -76207,6 +76269,34 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
76207
76269
  timestamp: number()
76208
76270
  });
76209
76271
  /**
76272
+ * A root model's boxes standing in for one crop-kind step's own inference
76273
+ * (D730) — see `runPipeline.suppliedRoot`.
76274
+ */
76275
+ var SuppliedRootOutputSchema = object({
76276
+ stepId: string(),
76277
+ /** The root model that drew the boxes — stamped on the result. */
76278
+ modelId: string(),
76279
+ detections: array(object({
76280
+ /** `[x1, y1, x2, y2]` in the pixels of the call's image. */
76281
+ bbox: tuple([
76282
+ number(),
76283
+ number(),
76284
+ number(),
76285
+ number()
76286
+ ]),
76287
+ score: number(),
76288
+ /**
76289
+ * Five facial landmarks in the same pixels — a face the step's own
76290
+ * detector already re-found inside a root face box (D730), so its
76291
+ * embedder child aligns it exactly as it aligns any detected face.
76292
+ */
76293
+ landmarks: array(object({
76294
+ x: number(),
76295
+ y: number()
76296
+ })).optional()
76297
+ })).min(1)
76298
+ });
76299
+ /**
76210
76300
  * Reference to the frame's retained NATIVE surface + the parent crop's placement
76211
76301
  * within the frame, so the executor can re-cut a leaf child ROI at native
76212
76302
  * resolution on the detail plane. See the `runPipeline` `nativeCropRef` field.
@@ -76336,7 +76426,8 @@ var PipelineModelOptionSchema = object({
76336
76426
  group: ModelVariantGroupSchema.optional(),
76337
76427
  legacy: boolean().optional(),
76338
76428
  provider: ModelProviderIdSchema.optional(),
76339
- defaultConfidence: number().optional()
76429
+ defaultConfidence: number().optional(),
76430
+ suppliesSteps: array(RootStepSupplySchema).readonly().optional()
76340
76431
  });
76341
76432
  var ConfigFieldBridge = custom();
76342
76433
  var PipelineAddonSchemaSchema = object({
@@ -76604,7 +76695,16 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
76604
76695
  * `device-not-servable`), and nothing reaches the camera's live
76605
76696
  * trace stream. Absent ⇒ unchanged behaviour.
76606
76697
  */
76607
- replay: literal(true).optional()
76698
+ replay: literal(true).optional(),
76699
+ /**
76700
+ * Root-supplied detections for the tree's ROOT step (D730). Set by
76701
+ * `runDetailSubtree` when the camera's root model supplies a crop-kind
76702
+ * step (a Frigate+ `license_plate` for `plate-detection`): the step is
76703
+ * NOT inferred, these boxes are its output, and its children (the plate
76704
+ * reader) run on them through their own crop policy. Boxes are in the
76705
+ * PIXELS of the image this call carries. Absent ⇒ the root step runs.
76706
+ */
76707
+ suppliedRoot: SuppliedRootOutputSchema.optional()
76608
76708
  }), PipelineRunResultBridge, { kind: "mutation" }), method(object({
76609
76709
  steps: array(PipelineStepInputSchema).min(1),
76610
76710
  frames: array(FrameInputSchema).min(1).max(255),
@@ -77746,7 +77846,22 @@ method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mu
77746
77846
  */
77747
77847
  cropJpeg: string().optional(),
77748
77848
  parent: DetailParentSchema,
77749
- steps: array(string()).optional()
77849
+ steps: array(string()).optional(),
77850
+ /**
77851
+ * The camera's root model already drew this step's boxes (D730): a
77852
+ * `license_plate` inside the parent vehicle. The named step is NOT
77853
+ * inferred — these FRAME-space boxes are its output — and its
77854
+ * requested children (the plate reader) run on them. Absent ⇒ every
77855
+ * requested step infers as before.
77856
+ */
77857
+ supplied: object({
77858
+ stepId: string(),
77859
+ modelId: string(),
77860
+ boxes: array(object({
77861
+ bbox: NativeCropBboxSchema,
77862
+ score: number()
77863
+ })).min(1)
77864
+ }).optional()
77750
77865
  }), object({ details: array(DetailResultSchema) }).nullable(), { kind: "mutation" }), method(object({
77751
77866
  /** Catalog step id, e.g. `clip-embedding`. */
77752
77867
  stepId: string(),
@@ -81076,6 +81191,14 @@ DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), ar
81076
81191
  */
81077
81192
  alive: boolean()
81078
81193
  })), method(object({
81194
+ deviceId: number().int().nonnegative(),
81195
+ sessionId: string(),
81196
+ downlinkMbps: number().nonnegative()
81197
+ }), object({
81198
+ outcome: _enum(["switching", "held"]),
81199
+ tier: CamProfileSchema.nullable(),
81200
+ reason: string()
81201
+ }), { kind: "mutation" }), method(object({
81079
81202
  deviceId: number().int().nonnegative(),
81080
81203
  sessionId: string()
81081
81204
  }), WebrtcSessionDebugSchema, { kind: "query" });
@@ -84912,7 +85035,8 @@ var ConnectionEndpointSchema = object({
84912
85035
  "lan-ipv6",
84913
85036
  "public",
84914
85037
  "loopback",
84915
- "app-link"
85038
+ "app-link",
85039
+ "custom"
84916
85040
  ]),
84917
85041
  /**
84918
85042
  * Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
@@ -85014,6 +85138,76 @@ var ViewerEndpointsSchema = object({
85014
85138
  /** What the ranking currently resolves to (may be empty if nothing is up). */
85015
85139
  resolved: array(string()).readonly()
85016
85140
  });
85141
+ /**
85142
+ * DEPRECATED compatibility shape of `getHubAddresses` (D729 amendment, kept
85143
+ * one release for addons built against it): `cluster` is the `agents` role,
85144
+ * `browser` the `signIn` role; `override` is the flagged address.
85145
+ */
85146
+ var HubAddressSnapshotSchema = object({
85147
+ override: string().nullable(),
85148
+ resolved: string().nullable(),
85149
+ source: _enum([
85150
+ "override",
85151
+ "auto",
85152
+ "none"
85153
+ ])
85154
+ });
85155
+ var HubAddressesSchema = object({
85156
+ cluster: HubAddressSnapshotSchema,
85157
+ browser: HubAddressSnapshotSchema
85158
+ });
85159
+ /**
85160
+ * What an address is used for (`hub-address.ts`). `viewer` is many-valued;
85161
+ * `notifications`, `agents` and `signIn` are carried by at most one address.
85162
+ */
85163
+ var HubAddressRoleSchema = _enum([
85164
+ "viewer",
85165
+ "notifications",
85166
+ "agents",
85167
+ "signIn"
85168
+ ]);
85169
+ var RoleSourceSchema = _enum([
85170
+ "flagged",
85171
+ "auto",
85172
+ "none"
85173
+ ]);
85174
+ /** One single-valued role: the flagged address, the one in use, and why. */
85175
+ var HubAddressRoleResolutionSchema = object({
85176
+ /** The address carrying the flag, or null = automatic. */
85177
+ flagged: string().nullable(),
85178
+ /** The address in use, or null when nothing qualifies (never loopback). */
85179
+ resolved: string().nullable(),
85180
+ source: RoleSourceSchema
85181
+ });
85182
+ var HubViewerResolutionSchema = object({
85183
+ /** The addresses flagged `viewer`, or empty = automatic. */
85184
+ flagged: array(string()).readonly(),
85185
+ /** What the apps race right now. */
85186
+ resolved: array(string()).readonly(),
85187
+ source: RoleSourceSchema
85188
+ });
85189
+ var HubAddressBookSchema = object({
85190
+ rows: array(ConnectionEndpointSchema.extend({
85191
+ /** In the hub's detected palette right now. */
85192
+ detected: boolean(),
85193
+ /** Entered by the operator (removable). */
85194
+ custom: boolean(),
85195
+ /** The roles explicitly flagged on this address. */
85196
+ flags: array(HubAddressRoleSchema).readonly(),
85197
+ /** The roles this address serves right now — flagged or automatic. */
85198
+ inUse: array(HubAddressRoleSchema).readonly(),
85199
+ /** The roles this address may be flagged with. */
85200
+ eligible: array(HubAddressRoleSchema).readonly()
85201
+ })).readonly(),
85202
+ roles: object({
85203
+ viewer: HubViewerResolutionSchema,
85204
+ notifications: HubAddressRoleResolutionSchema,
85205
+ agents: HubAddressRoleResolutionSchema,
85206
+ signIn: HubAddressRoleResolutionSchema
85207
+ }),
85208
+ /** The `hub=` an app link carries (D709), or null. */
85209
+ appLinkHub: string().nullable()
85210
+ });
85017
85211
  var AllowedAddressesSchema = object({
85018
85212
  /**
85019
85213
  * Allowlist of interface addresses operators have explicitly opted
@@ -85060,7 +85254,24 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
85060
85254
  * an address notification links can be flagged with, not a hub
85061
85255
  * route. Default `false`: racers and rankers never see it. */
85062
85256
  includeAppLink: boolean().optional()
85063
- }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
85257
+ }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(object({ scheme: _enum(["http", "https"]).optional() }).optional(), HubAddressBookSchema), method(object({
85258
+ baseUrl: string(),
85259
+ label: string().max(80)
85260
+ }), HubAddressBookSchema, {
85261
+ kind: "mutation",
85262
+ auth: "admin"
85263
+ }), method(object({ baseUrl: string() }), HubAddressBookSchema, {
85264
+ kind: "mutation",
85265
+ auth: "admin"
85266
+ }), method(object({
85267
+ role: HubAddressRoleSchema,
85268
+ baseUrl: string().nullable(),
85269
+ enabled: boolean(),
85270
+ acceptInsecureHttp: boolean().optional()
85271
+ }), HubAddressBookSchema, {
85272
+ kind: "mutation",
85273
+ auth: "admin"
85274
+ }), method(_void(), HubAddressesSchema), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
85064
85275
  kind: "mutation",
85065
85276
  auth: "admin"
85066
85277
  }), method(object({
@@ -85518,7 +85729,8 @@ var MotionStatusSchema = object({
85518
85729
  * writes this slice (not even a boot seed), and neither does the runner's
85519
85730
  * phase machine: its phase is "a session is attached" for every on-motion
85520
85731
  * session, not motion, and it now has its own `DetectionPhaseTransition`.
85521
- * A provider's `isDetected` answers from the hub's slice.
85732
+ * A provider's `isDetected` and `getStatus` answer from the hub's slice
85733
+ * (`hubMotionNativeProvider`).
85522
85734
  * - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
85523
85735
  * imports) — the provider pushes both edges itself, from the upstream
85524
85736
  * system's own state change. That is the sensor's own fact.
@@ -96665,12 +96877,24 @@ Object.freeze({
96665
96877
  addonId: null,
96666
96878
  access: "view"
96667
96879
  },
96880
+ "localNetwork.addCustomAddress": {
96881
+ capName: "local-network",
96882
+ capScope: "system",
96883
+ addonId: null,
96884
+ access: "create"
96885
+ },
96668
96886
  "localNetwork.downloadCa": {
96669
96887
  capName: "local-network",
96670
96888
  capScope: "system",
96671
96889
  addonId: null,
96672
96890
  access: "view"
96673
96891
  },
96892
+ "localNetwork.getAddresses": {
96893
+ capName: "local-network",
96894
+ capScope: "system",
96895
+ addonId: null,
96896
+ access: "view"
96897
+ },
96674
96898
  "localNetwork.getAllowedAddresses": {
96675
96899
  capName: "local-network",
96676
96900
  capScope: "system",
@@ -96683,6 +96907,12 @@ Object.freeze({
96683
96907
  addonId: null,
96684
96908
  access: "view"
96685
96909
  },
96910
+ "localNetwork.getHubAddresses": {
96911
+ capName: "local-network",
96912
+ capScope: "system",
96913
+ addonId: null,
96914
+ access: "view"
96915
+ },
96686
96916
  "localNetwork.getNotificationEndpoint": {
96687
96917
  capName: "local-network",
96688
96918
  capScope: "system",
@@ -96719,6 +96949,12 @@ Object.freeze({
96719
96949
  addonId: null,
96720
96950
  access: "create"
96721
96951
  },
96952
+ "localNetwork.removeCustomAddress": {
96953
+ capName: "local-network",
96954
+ capScope: "system",
96955
+ addonId: null,
96956
+ access: "delete"
96957
+ },
96722
96958
  "localNetwork.resetAllowlistToBestMatch": {
96723
96959
  capName: "local-network",
96724
96960
  capScope: "system",
@@ -96731,6 +96967,12 @@ Object.freeze({
96731
96967
  addonId: null,
96732
96968
  access: "create"
96733
96969
  },
96970
+ "localNetwork.setAddressRole": {
96971
+ capName: "local-network",
96972
+ capScope: "system",
96973
+ addonId: null,
96974
+ access: "create"
96975
+ },
96734
96976
  "localNetwork.setAllowedAddresses": {
96735
96977
  capName: "local-network",
96736
96978
  capScope: "system",
@@ -100985,6 +101227,12 @@ Object.freeze({
100985
101227
  addonId: null,
100986
101228
  access: "create"
100987
101229
  },
101230
+ "webrtcSession.applyDownlinkProbe": {
101231
+ capName: "webrtc-session",
101232
+ capScope: "device",
101233
+ addonId: null,
101234
+ access: "create"
101235
+ },
100988
101236
  "webrtcSession.closeSession": {
100989
101237
  capName: "webrtc-session",
100990
101238
  capScope: "device",
@@ -104907,6 +105155,11 @@ Object.freeze({
104907
105155
  form: "single",
104908
105156
  optional: false
104909
105157
  }],
105158
+ "webrtcSession.applyDownlinkProbe": [{
105159
+ name: "deviceId",
105160
+ form: "single",
105161
+ optional: false
105162
+ }],
104910
105163
  "webrtcSession.closeSession": [{
104911
105164
  name: "deviceId",
104912
105165
  form: "single",
@@ -105136,6 +105389,8 @@ new Map(Object.entries({
105136
105389
  "detection-blind": "device-events",
105137
105390
  "node-online": "system",
105138
105391
  "node-offline": "system",
105392
+ "node-restarting": "system",
105393
+ "node-updating": "system",
105139
105394
  "node-inference-unavailable": "system",
105140
105395
  "addon-crash-loop": "system",
105141
105396
  "addon-update-available": "system",
@@ -105213,6 +105468,7 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
105213
105468
  kinds: [
105214
105469
  "node-offline",
105215
105470
  "node-online",
105471
+ "node-restarting",
105216
105472
  "node-inference-unavailable"
105217
105473
  ]
105218
105474
  },
@@ -105234,6 +105490,7 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
105234
105490
  label: "Server & container updates",
105235
105491
  kinds: [
105236
105492
  "server-update-available",
105493
+ "node-updating",
105237
105494
  "server-updated",
105238
105495
  "wrapper-update-available"
105239
105496
  ]
@@ -105381,6 +105638,7 @@ var STATE_SUMMARY_SECTION_VARS = [
105381
105638
  kinds: [
105382
105639
  "node-offline",
105383
105640
  "node-online",
105641
+ "node-restarting",
105384
105642
  "node-inference-unavailable"
105385
105643
  ]
105386
105644
  },
@@ -105402,6 +105660,7 @@ var STATE_SUMMARY_SECTION_VARS = [
105402
105660
  example: "server 1.2.377 → 1.2.378",
105403
105661
  kinds: [
105404
105662
  "server-update-available",
105663
+ "node-updating",
105405
105664
  "server-updated",
105406
105665
  "wrapper-update-available"
105407
105666
  ]
@@ -105434,7 +105693,7 @@ var STATE_SUMMARY_VARS = [
105434
105693
  {
105435
105694
  name: "summarySection",
105436
105695
  label: "Summary: this section",
105437
- description: "The section a per-section summary row is about (D698); on a summary sent as one message, every section it reports, comma-separated.",
105696
+ description: "The section a per-section summary row is about; on a summary sent as one message, every section it reports, comma-separated.",
105438
105697
  example: "Batterie scariche",
105439
105698
  group: "system",
105440
105699
  families: ["rule"],
@@ -108435,6 +108694,18 @@ function nextVacuumControlSlice(prev, next) {
108435
108694
  }
108436
108695
  //#endregion
108437
108696
  //#region src/devices/dreame-camera-stream.ts
108697
+ /**
108698
+ * The robot camera as a stream the broker can pull — the pure facts.
108699
+ *
108700
+ * A Dreame relay carries video only between `open()` and `close()`, and the
108701
+ * robot runs on a battery, so the camera cannot sit in the catalog with a
108702
+ * URL the way a mains RTSP camera does. The seam is the broker's own battery
108703
+ * path: `battery.wakeForStream` opens the monitor, and the catalog then
108704
+ * names the local RFC 4571 server (`dreame-rfc4571-server.ts`) the broker
108705
+ * pulls. While the monitor is CLOSED the
108706
+ * catalog carries the broker's lazy sentinel (Reolink's shape): the stream is
108707
+ * listed, and the first dial asks the publisher to materialize it.
108708
+ */
108438
108709
  /** The one stream the robot camera offers. Half of the broker id (`<deviceId>/live`). */
108439
108710
  var CAMERA_STREAM_ID = "live";
108440
108711
  /** The plugin's cap: a monitor never outlives this, whoever is watching. */
@@ -108514,17 +108785,14 @@ function cameraStreamCatalog(session) {
108514
108785
  /**
108515
108786
  * The host the broker is told to dial. The provider and the ingest owner
108516
108787
  * share the hub today, but a broker on another node reaches the hub only
108517
- * through its public address — which is what `CAMSTACK_HUB_PUBLIC_URL` is
108518
- * for. Loopback when nothing better is known.
108788
+ * through the hub's address for agents — `local-network.getAddresses()
108789
+ * .roles.agents` (the address flagged "Agents" on the Network page, else the
108790
+ * detected LAN address).
108791
+ * Loopback when that names nothing: then the only broker that can dial at
108792
+ * all is this node's own.
108519
108793
  */
108520
- function advertisedRfcHost(hubPublicUrl) {
108521
- if (hubPublicUrl === void 0 || hubPublicUrl.length === 0) return "127.0.0.1";
108522
- try {
108523
- const host = new URL(hubPublicUrl).hostname;
108524
- return host.length > 0 ? host : "127.0.0.1";
108525
- } catch {
108526
- return "127.0.0.1";
108527
- }
108794
+ function advertisedRfcHost(clusterBaseUrl) {
108795
+ return hubAddressHostname(clusterBaseUrl) ?? "127.0.0.1";
108528
108796
  }
108529
108797
  function rfcUrl(host, port) {
108530
108798
  return `tcp://${host}:${String(port)}`;
@@ -154914,6 +155182,24 @@ var DreameCameraDevice = class extends DreameChildDevice {
154914
155182
  }
154915
155183
  unsubscribeRefresh = null;
154916
155184
  /** Register the stream on the broker — the server, or the lazy sentinel (push semantics; the catalog is the durable copy). */
155185
+ /**
155186
+ * The hub's address for agents and LAN devices
155187
+ * (`local-network.getAddresses().roles.agents`: the address flagged
155188
+ * "Agents" on the Network page, else the detected LAN address). A failed
155189
+ * read is `null` — `advertisedRfcHost` then answers loopback, which this
155190
+ * node's own broker can still dial.
155191
+ */
155192
+ async hubClusterAddress() {
155193
+ try {
155194
+ return (await this.ctx.api.localNetwork.getAddresses.query()).roles.agents.resolved;
155195
+ } catch (err) {
155196
+ this.ctx.logger.warn("robot camera: hub address unavailable — advertising loopback", {
155197
+ tags: { deviceId: this.id },
155198
+ meta: { error: err instanceof Error ? err.message : String(err) }
155199
+ });
155200
+ return null;
155201
+ }
155202
+ }
154917
155203
  async publishRelay(session) {
154918
155204
  const [descriptor] = cameraStreamCatalog(session);
154919
155205
  if (descriptor === void 0) return;
@@ -154999,7 +155285,7 @@ var DreameCameraDevice = class extends DreameChildDevice {
154999
155285
  rfc
155000
155286
  };
155001
155287
  this.session = {
155002
- url: rfcUrl(advertisedRfcHost(process.env.CAMSTACK_HUB_PUBLIC_URL), rfc.port),
155288
+ url: rfcUrl(advertisedRfcHost(await this.hubClusterAddress()), rfc.port),
155003
155289
  sdp: rfc.sdp
155004
155290
  };
155005
155291
  this.sessionOpenedAt = Date.now();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-dreame",
3
- "version": "0.2.123",
3
+ "version": "0.2.125",
4
4
  "description": "Dreame robot-vacuum / lawn-mower device-provider addon for CamStack — wraps the @apocaliss92/nodedreame Dreamehome cloud client",
5
5
  "keywords": [
6
6
  "camstack",