@camstack/addon-provider-onvif 1.2.105 → 1.2.107

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
@@ -12262,7 +12262,23 @@ var PickStreamRequirementsSchema = object({
12262
12262
  * This is what lets one picker serve both the bypass and the full source
12263
12263
  * choice, instead of a consumer scoring privately when the bypass misses.
12264
12264
  */
12265
- allowTranscode: boolean().optional()
12265
+ allowTranscode: boolean().optional(),
12266
+ /**
12267
+ * Consider ONLY streams the broker has bound to a profile slot.
12268
+ *
12269
+ * A consumer that dials the broker — which is every exporter, since none
12270
+ * of them may open the camera's own URL — can do nothing with a source
12271
+ * that has no slot: there is no restream to dial. Without this the picker
12272
+ * can name such a stream, and each consumer discovers the dead end for
12273
+ * itself: Alexa's `profileForCamStream` returns `null` and it quietly
12274
+ * falls back, and HomeKit would have had to grow the same function again.
12275
+ *
12276
+ * Default `false`, and deliberately so: the BROKER itself picks through
12277
+ * here when it decides which source to BIND to a slot
12278
+ * (`computeInitialAssignment`), and it must see the unbound ones or it
12279
+ * could never bind them.
12280
+ */
12281
+ requireProfileBound: boolean().optional()
12266
12282
  }).readonly();
12267
12283
  var PickStreamPreferencesSchema = object({
12268
12284
  /**
@@ -12303,7 +12319,43 @@ var PickedCamStreamSchema = object({
12303
12319
  */
12304
12320
  transcodes: boolean(),
12305
12321
  /** One-line explanation of why this stream won — for logs / debug UI. */
12306
- reason: string()
12322
+ reason: string(),
12323
+ /**
12324
+ * The broker profile slot this source is bound to, when it is bound.
12325
+ *
12326
+ * Answered HERE because every consumer needs it and none of them can get it
12327
+ * from the `camStreamId` alone. Alexa wrote `profileForCamStream` for it —
12328
+ * a second cap read plus a `null` branch — and HomeKit was about to write
12329
+ * the same function a second time.
12330
+ *
12331
+ * Absent when the source has no slot, which a caller passing
12332
+ * `requireProfileBound` can never see.
12333
+ */
12334
+ profile: CamProfileSchema.optional(),
12335
+ /** The broker id of that slot, for logs that must name what was dialled. */
12336
+ brokerId: string().optional(),
12337
+ /**
12338
+ * The broker restream URL to dial for this stream.
12339
+ *
12340
+ * An exporter must never open the camera's own URL — the broker is the one
12341
+ * that dials the camera, and every consumer goes through its restream. So
12342
+ * the picker answers with the thing a consumer may actually use, instead of
12343
+ * naming a source and leaving each caller to look the URL up.
12344
+ */
12345
+ url: string().optional(),
12346
+ /**
12347
+ * Frames per second this stream really delivers, and where the number came
12348
+ * from.
12349
+ *
12350
+ * It is here because getting it wrong is expensive and silent: a HomeKit
12351
+ * accessory advertised 720p at 24 fps while the slot serving it ran at 9,
12352
+ * and the controller rendered nothing at all. The source is carried with the
12353
+ * value for the same reason the bitrate evidence is: `published` is what the
12354
+ * publisher declares and `measured` is what the broker observed, and they
12355
+ * are not interchangeable.
12356
+ */
12357
+ fps: number().positive().optional(),
12358
+ fpsSource: _enum(["published", "measured"]).optional()
12307
12359
  });
12308
12360
  DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), array(CameraStreamSchema).readonly()), method(object({ deviceId: number().int().nonnegative() }), array(ProfileSlotSchema).readonly()), method(object({
12309
12361
  deviceId: number().int().nonnegative(),
@@ -13277,6 +13329,70 @@ var LocationIconAssignmentSchema = object({
13277
13329
  locationKey: string(),
13278
13330
  icon: LocationIconIdSchema
13279
13331
  });
13332
+ /**
13333
+ * One (location, description) assignment as it travels.
13334
+ *
13335
+ * Same key discipline as {@link LocationIconAssignmentSchema}, and for the same
13336
+ * reason: this lived for a while in the post-analysis addon's own settings,
13337
+ * keyed by a HAND-TYPED label matched exactly and case-sensitively. A rename in
13338
+ * the Locations page carried the icon and silently orphaned the description —
13339
+ * two authorities for one thing, joined by two different rules. Now both hang
13340
+ * off the location itself, on `locationIconKey`.
13341
+ */
13342
+ var LocationDescriptionAssignmentSchema = object({
13343
+ locationKey: string(),
13344
+ description: string()
13345
+ });
13346
+ /**
13347
+ * A SITE ZONE — a named part of the property that several locations belong to.
13348
+ *
13349
+ * "Zona notte" holds every bedroom; "Zona giorno" the living room and the
13350
+ * kitchen. A camera belongs to exactly one location, and a location to at most
13351
+ * one zone, so a camera's zone is derived and never stored on the device: the
13352
+ * whole point of this entity is that grouping rooms touches no device row.
13353
+ *
13354
+ * ## Why not `zone`
13355
+ *
13356
+ * Because `zone` is already the most loaded word in this product: 612 source
13357
+ * files and 24 Italian strings where it means a DETECTION zone drawn on a
13358
+ * camera. The two are unrelated — one is a polygon in a frame, the other is a
13359
+ * set of rooms — and a reader who confuses them will look for a camera's
13360
+ * bedrooms. So the code says `siteZone` everywhere, and the UI frees the plain
13361
+ * word by calling the drawn one what it actually is: a detection zone.
13362
+ *
13363
+ * ## The key
13364
+ *
13365
+ * `siteZoneKey(label)` — trimmed, lower-cased, the SAME derivation locations
13366
+ * use (`locationIconKey`). Membership and the icon both hang off it, so a
13367
+ * case-only rename keeps them, which is exactly the orphaning that cost us a
13368
+ * silently-dropped location description.
13369
+ *
13370
+ * The icon vocabulary is the location one, unchanged: a zone is drawn on the
13371
+ * same two surfaces by the same glyph map, so a second vocabulary would be a
13372
+ * second thing to keep drawable (`scripts/check-location-icons-drawable.ts`).
13373
+ */
13374
+ /**
13375
+ * One zone as it travels: its key, the label the operator typed, its icon and
13376
+ * the locations inside it.
13377
+ *
13378
+ * The LABEL is carried alongside the key because the key is lossy on purpose —
13379
+ * a surface must show "Zona notte", not "zona notte". Locations are carried
13380
+ * here, rather than left to a second call, because every consumer wants both
13381
+ * at once and a viewer that asked twice could render a zone whose membership
13382
+ * it has not fetched yet.
13383
+ *
13384
+ * `icon: null` means nobody chose one, which is NOT the fallback pin: only one
13385
+ * of those two is a choice, and a picker has to draw them differently.
13386
+ */
13387
+ var SiteZoneSchema = object({
13388
+ zoneKey: string(),
13389
+ label: string(),
13390
+ icon: LocationIconIdSchema.nullable(),
13391
+ /** Folded location keys, sorted. A location listed here need not be
13392
+ * REGISTERED — devices carry labels nobody registered, and those rooms are
13393
+ * the ones that most want grouping. */
13394
+ locationKeys: array(string())
13395
+ });
13280
13396
  var ProviderStatusSchema = object({
13281
13397
  connected: boolean(),
13282
13398
  deviceCount: number(),
@@ -13875,6 +13991,33 @@ method(object({
13875
13991
  }), _void(), {
13876
13992
  kind: "mutation",
13877
13993
  auth: "admin"
13994
+ }), method(_void(), array(LocationDescriptionAssignmentSchema)), method(object({
13995
+ location: string(),
13996
+ description: string().max(400).nullable()
13997
+ }), _void(), {
13998
+ kind: "mutation",
13999
+ auth: "admin"
14000
+ }), method(_void(), array(SiteZoneSchema)), method(object({
14001
+ name: string(),
14002
+ icon: LocationIconIdSchema.nullable().optional()
14003
+ }), _void(), {
14004
+ kind: "mutation",
14005
+ auth: "admin"
14006
+ }), method(object({ name: string() }), _void(), {
14007
+ kind: "mutation",
14008
+ auth: "admin"
14009
+ }), method(object({
14010
+ from: string(),
14011
+ to: string()
14012
+ }), _void(), {
14013
+ kind: "mutation",
14014
+ auth: "admin"
14015
+ }), method(object({
14016
+ location: string(),
14017
+ zone: string().nullable()
14018
+ }), _void(), {
14019
+ kind: "mutation",
14020
+ auth: "admin"
13878
14021
  }), method(object({
13879
14022
  deviceId: number(),
13880
14023
  disabled: boolean()
@@ -33670,6 +33813,12 @@ Object.freeze({
33670
33813
  addonId: null,
33671
33814
  access: "view"
33672
33815
  },
33816
+ "deviceManager.listLocationDescriptions": {
33817
+ capName: "device-manager",
33818
+ capScope: "system",
33819
+ addonId: null,
33820
+ access: "view"
33821
+ },
33673
33822
  "deviceManager.listLocationIcons": {
33674
33823
  capName: "device-manager",
33675
33824
  capScope: "system",
@@ -33688,6 +33837,12 @@ Object.freeze({
33688
33837
  addonId: null,
33689
33838
  access: "view"
33690
33839
  },
33840
+ "deviceManager.listSiteZones": {
33841
+ capName: "device-manager",
33842
+ capScope: "system",
33843
+ addonId: null,
33844
+ access: "view"
33845
+ },
33691
33846
  "deviceManager.listWrappersForCap": {
33692
33847
  capName: "device-manager",
33693
33848
  capScope: "system",
@@ -33772,12 +33927,24 @@ Object.freeze({
33772
33927
  addonId: null,
33773
33928
  access: "delete"
33774
33929
  },
33930
+ "deviceManager.removeSiteZone": {
33931
+ capName: "device-manager",
33932
+ capScope: "system",
33933
+ addonId: null,
33934
+ access: "delete"
33935
+ },
33775
33936
  "deviceManager.renameLocation": {
33776
33937
  capName: "device-manager",
33777
33938
  capScope: "system",
33778
33939
  addonId: null,
33779
33940
  access: "create"
33780
33941
  },
33942
+ "deviceManager.renameSiteZone": {
33943
+ capName: "device-manager",
33944
+ capScope: "system",
33945
+ addonId: null,
33946
+ access: "create"
33947
+ },
33781
33948
  "deviceManager.runDeviceAction": {
33782
33949
  capName: "device-manager",
33783
33950
  capScope: "system",
@@ -33820,12 +33987,24 @@ Object.freeze({
33820
33987
  addonId: null,
33821
33988
  access: "create"
33822
33989
  },
33990
+ "deviceManager.setLocationDescription": {
33991
+ capName: "device-manager",
33992
+ capScope: "system",
33993
+ addonId: null,
33994
+ access: "create"
33995
+ },
33823
33996
  "deviceManager.setLocationIcon": {
33824
33997
  capName: "device-manager",
33825
33998
  capScope: "system",
33826
33999
  addonId: null,
33827
34000
  access: "create"
33828
34001
  },
34002
+ "deviceManager.setLocationZone": {
34003
+ capName: "device-manager",
34004
+ capScope: "system",
34005
+ addonId: null,
34006
+ access: "create"
34007
+ },
33829
34008
  "deviceManager.setMetadata": {
33830
34009
  capName: "device-manager",
33831
34010
  capScope: "system",
@@ -33856,6 +34035,12 @@ Object.freeze({
33856
34035
  addonId: null,
33857
34036
  access: "create"
33858
34037
  },
34038
+ "deviceManager.setSiteZone": {
34039
+ capName: "device-manager",
34040
+ capScope: "system",
34041
+ addonId: null,
34042
+ access: "create"
34043
+ },
33859
34044
  "deviceManager.setStreamProfileMap": {
33860
34045
  capName: "device-manager",
33861
34046
  capScope: "system",
package/dist/addon.mjs CHANGED
@@ -12263,7 +12263,23 @@ var PickStreamRequirementsSchema = object({
12263
12263
  * This is what lets one picker serve both the bypass and the full source
12264
12264
  * choice, instead of a consumer scoring privately when the bypass misses.
12265
12265
  */
12266
- allowTranscode: boolean().optional()
12266
+ allowTranscode: boolean().optional(),
12267
+ /**
12268
+ * Consider ONLY streams the broker has bound to a profile slot.
12269
+ *
12270
+ * A consumer that dials the broker — which is every exporter, since none
12271
+ * of them may open the camera's own URL — can do nothing with a source
12272
+ * that has no slot: there is no restream to dial. Without this the picker
12273
+ * can name such a stream, and each consumer discovers the dead end for
12274
+ * itself: Alexa's `profileForCamStream` returns `null` and it quietly
12275
+ * falls back, and HomeKit would have had to grow the same function again.
12276
+ *
12277
+ * Default `false`, and deliberately so: the BROKER itself picks through
12278
+ * here when it decides which source to BIND to a slot
12279
+ * (`computeInitialAssignment`), and it must see the unbound ones or it
12280
+ * could never bind them.
12281
+ */
12282
+ requireProfileBound: boolean().optional()
12267
12283
  }).readonly();
12268
12284
  var PickStreamPreferencesSchema = object({
12269
12285
  /**
@@ -12304,7 +12320,43 @@ var PickedCamStreamSchema = object({
12304
12320
  */
12305
12321
  transcodes: boolean(),
12306
12322
  /** One-line explanation of why this stream won — for logs / debug UI. */
12307
- reason: string()
12323
+ reason: string(),
12324
+ /**
12325
+ * The broker profile slot this source is bound to, when it is bound.
12326
+ *
12327
+ * Answered HERE because every consumer needs it and none of them can get it
12328
+ * from the `camStreamId` alone. Alexa wrote `profileForCamStream` for it —
12329
+ * a second cap read plus a `null` branch — and HomeKit was about to write
12330
+ * the same function a second time.
12331
+ *
12332
+ * Absent when the source has no slot, which a caller passing
12333
+ * `requireProfileBound` can never see.
12334
+ */
12335
+ profile: CamProfileSchema.optional(),
12336
+ /** The broker id of that slot, for logs that must name what was dialled. */
12337
+ brokerId: string().optional(),
12338
+ /**
12339
+ * The broker restream URL to dial for this stream.
12340
+ *
12341
+ * An exporter must never open the camera's own URL — the broker is the one
12342
+ * that dials the camera, and every consumer goes through its restream. So
12343
+ * the picker answers with the thing a consumer may actually use, instead of
12344
+ * naming a source and leaving each caller to look the URL up.
12345
+ */
12346
+ url: string().optional(),
12347
+ /**
12348
+ * Frames per second this stream really delivers, and where the number came
12349
+ * from.
12350
+ *
12351
+ * It is here because getting it wrong is expensive and silent: a HomeKit
12352
+ * accessory advertised 720p at 24 fps while the slot serving it ran at 9,
12353
+ * and the controller rendered nothing at all. The source is carried with the
12354
+ * value for the same reason the bitrate evidence is: `published` is what the
12355
+ * publisher declares and `measured` is what the broker observed, and they
12356
+ * are not interchangeable.
12357
+ */
12358
+ fps: number().positive().optional(),
12359
+ fpsSource: _enum(["published", "measured"]).optional()
12308
12360
  });
12309
12361
  DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), array(CameraStreamSchema).readonly()), method(object({ deviceId: number().int().nonnegative() }), array(ProfileSlotSchema).readonly()), method(object({
12310
12362
  deviceId: number().int().nonnegative(),
@@ -13278,6 +13330,70 @@ var LocationIconAssignmentSchema = object({
13278
13330
  locationKey: string(),
13279
13331
  icon: LocationIconIdSchema
13280
13332
  });
13333
+ /**
13334
+ * One (location, description) assignment as it travels.
13335
+ *
13336
+ * Same key discipline as {@link LocationIconAssignmentSchema}, and for the same
13337
+ * reason: this lived for a while in the post-analysis addon's own settings,
13338
+ * keyed by a HAND-TYPED label matched exactly and case-sensitively. A rename in
13339
+ * the Locations page carried the icon and silently orphaned the description —
13340
+ * two authorities for one thing, joined by two different rules. Now both hang
13341
+ * off the location itself, on `locationIconKey`.
13342
+ */
13343
+ var LocationDescriptionAssignmentSchema = object({
13344
+ locationKey: string(),
13345
+ description: string()
13346
+ });
13347
+ /**
13348
+ * A SITE ZONE — a named part of the property that several locations belong to.
13349
+ *
13350
+ * "Zona notte" holds every bedroom; "Zona giorno" the living room and the
13351
+ * kitchen. A camera belongs to exactly one location, and a location to at most
13352
+ * one zone, so a camera's zone is derived and never stored on the device: the
13353
+ * whole point of this entity is that grouping rooms touches no device row.
13354
+ *
13355
+ * ## Why not `zone`
13356
+ *
13357
+ * Because `zone` is already the most loaded word in this product: 612 source
13358
+ * files and 24 Italian strings where it means a DETECTION zone drawn on a
13359
+ * camera. The two are unrelated — one is a polygon in a frame, the other is a
13360
+ * set of rooms — and a reader who confuses them will look for a camera's
13361
+ * bedrooms. So the code says `siteZone` everywhere, and the UI frees the plain
13362
+ * word by calling the drawn one what it actually is: a detection zone.
13363
+ *
13364
+ * ## The key
13365
+ *
13366
+ * `siteZoneKey(label)` — trimmed, lower-cased, the SAME derivation locations
13367
+ * use (`locationIconKey`). Membership and the icon both hang off it, so a
13368
+ * case-only rename keeps them, which is exactly the orphaning that cost us a
13369
+ * silently-dropped location description.
13370
+ *
13371
+ * The icon vocabulary is the location one, unchanged: a zone is drawn on the
13372
+ * same two surfaces by the same glyph map, so a second vocabulary would be a
13373
+ * second thing to keep drawable (`scripts/check-location-icons-drawable.ts`).
13374
+ */
13375
+ /**
13376
+ * One zone as it travels: its key, the label the operator typed, its icon and
13377
+ * the locations inside it.
13378
+ *
13379
+ * The LABEL is carried alongside the key because the key is lossy on purpose —
13380
+ * a surface must show "Zona notte", not "zona notte". Locations are carried
13381
+ * here, rather than left to a second call, because every consumer wants both
13382
+ * at once and a viewer that asked twice could render a zone whose membership
13383
+ * it has not fetched yet.
13384
+ *
13385
+ * `icon: null` means nobody chose one, which is NOT the fallback pin: only one
13386
+ * of those two is a choice, and a picker has to draw them differently.
13387
+ */
13388
+ var SiteZoneSchema = object({
13389
+ zoneKey: string(),
13390
+ label: string(),
13391
+ icon: LocationIconIdSchema.nullable(),
13392
+ /** Folded location keys, sorted. A location listed here need not be
13393
+ * REGISTERED — devices carry labels nobody registered, and those rooms are
13394
+ * the ones that most want grouping. */
13395
+ locationKeys: array(string())
13396
+ });
13281
13397
  var ProviderStatusSchema = object({
13282
13398
  connected: boolean(),
13283
13399
  deviceCount: number(),
@@ -13876,6 +13992,33 @@ method(object({
13876
13992
  }), _void(), {
13877
13993
  kind: "mutation",
13878
13994
  auth: "admin"
13995
+ }), method(_void(), array(LocationDescriptionAssignmentSchema)), method(object({
13996
+ location: string(),
13997
+ description: string().max(400).nullable()
13998
+ }), _void(), {
13999
+ kind: "mutation",
14000
+ auth: "admin"
14001
+ }), method(_void(), array(SiteZoneSchema)), method(object({
14002
+ name: string(),
14003
+ icon: LocationIconIdSchema.nullable().optional()
14004
+ }), _void(), {
14005
+ kind: "mutation",
14006
+ auth: "admin"
14007
+ }), method(object({ name: string() }), _void(), {
14008
+ kind: "mutation",
14009
+ auth: "admin"
14010
+ }), method(object({
14011
+ from: string(),
14012
+ to: string()
14013
+ }), _void(), {
14014
+ kind: "mutation",
14015
+ auth: "admin"
14016
+ }), method(object({
14017
+ location: string(),
14018
+ zone: string().nullable()
14019
+ }), _void(), {
14020
+ kind: "mutation",
14021
+ auth: "admin"
13879
14022
  }), method(object({
13880
14023
  deviceId: number(),
13881
14024
  disabled: boolean()
@@ -33671,6 +33814,12 @@ Object.freeze({
33671
33814
  addonId: null,
33672
33815
  access: "view"
33673
33816
  },
33817
+ "deviceManager.listLocationDescriptions": {
33818
+ capName: "device-manager",
33819
+ capScope: "system",
33820
+ addonId: null,
33821
+ access: "view"
33822
+ },
33674
33823
  "deviceManager.listLocationIcons": {
33675
33824
  capName: "device-manager",
33676
33825
  capScope: "system",
@@ -33689,6 +33838,12 @@ Object.freeze({
33689
33838
  addonId: null,
33690
33839
  access: "view"
33691
33840
  },
33841
+ "deviceManager.listSiteZones": {
33842
+ capName: "device-manager",
33843
+ capScope: "system",
33844
+ addonId: null,
33845
+ access: "view"
33846
+ },
33692
33847
  "deviceManager.listWrappersForCap": {
33693
33848
  capName: "device-manager",
33694
33849
  capScope: "system",
@@ -33773,12 +33928,24 @@ Object.freeze({
33773
33928
  addonId: null,
33774
33929
  access: "delete"
33775
33930
  },
33931
+ "deviceManager.removeSiteZone": {
33932
+ capName: "device-manager",
33933
+ capScope: "system",
33934
+ addonId: null,
33935
+ access: "delete"
33936
+ },
33776
33937
  "deviceManager.renameLocation": {
33777
33938
  capName: "device-manager",
33778
33939
  capScope: "system",
33779
33940
  addonId: null,
33780
33941
  access: "create"
33781
33942
  },
33943
+ "deviceManager.renameSiteZone": {
33944
+ capName: "device-manager",
33945
+ capScope: "system",
33946
+ addonId: null,
33947
+ access: "create"
33948
+ },
33782
33949
  "deviceManager.runDeviceAction": {
33783
33950
  capName: "device-manager",
33784
33951
  capScope: "system",
@@ -33821,12 +33988,24 @@ Object.freeze({
33821
33988
  addonId: null,
33822
33989
  access: "create"
33823
33990
  },
33991
+ "deviceManager.setLocationDescription": {
33992
+ capName: "device-manager",
33993
+ capScope: "system",
33994
+ addonId: null,
33995
+ access: "create"
33996
+ },
33824
33997
  "deviceManager.setLocationIcon": {
33825
33998
  capName: "device-manager",
33826
33999
  capScope: "system",
33827
34000
  addonId: null,
33828
34001
  access: "create"
33829
34002
  },
34003
+ "deviceManager.setLocationZone": {
34004
+ capName: "device-manager",
34005
+ capScope: "system",
34006
+ addonId: null,
34007
+ access: "create"
34008
+ },
33830
34009
  "deviceManager.setMetadata": {
33831
34010
  capName: "device-manager",
33832
34011
  capScope: "system",
@@ -33857,6 +34036,12 @@ Object.freeze({
33857
34036
  addonId: null,
33858
34037
  access: "create"
33859
34038
  },
34039
+ "deviceManager.setSiteZone": {
34040
+ capName: "device-manager",
34041
+ capScope: "system",
34042
+ addonId: null,
34043
+ access: "create"
34044
+ },
33860
34045
  "deviceManager.setStreamProfileMap": {
33861
34046
  capName: "device-manager",
33862
34047
  capScope: "system",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-onvif",
3
- "version": "1.2.105",
3
+ "version": "1.2.107",
4
4
  "description": "ONVIF camera device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",