@camstack/addon-provider-dreame 0.2.51 → 0.2.53

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
@@ -58223,7 +58223,8 @@ var OpsLogReasonSchema = _enum([
58223
58223
  "quota",
58224
58224
  "manual",
58225
58225
  "operator",
58226
- "maintenance"
58226
+ "maintenance",
58227
+ "orphaned-device"
58227
58228
  ]);
58228
58229
  /** One audit row, shared verbatim by both domains. */
58229
58230
  var OpsLogEntrySchema = object({
@@ -63535,10 +63536,39 @@ var DevicePersistConfigPayloadSchema = object({
63535
63536
  deviceId: number(),
63536
63537
  data: record(string(), unknown())
63537
63538
  });
63539
+ /** What a migration actually did, per switch. `unreachable` is a first-class
63540
+ * answer: a camera that could not be asked is not a camera that was silenced. */
63541
+ var MigrateSwitchOutcomeSchema = _enum([
63542
+ "off",
63543
+ "on",
63544
+ "not-offered",
63545
+ "unreachable"
63546
+ ]);
63547
+ var MigrateSwitchReportSchema = object({
63548
+ deviceId: number(),
63549
+ switchId: CameraSwitchIdSchema,
63550
+ outcome: MigrateSwitchOutcomeSchema,
63551
+ detail: string().optional()
63552
+ });
63553
+ var MigrateDeviceResultSchema = object({
63554
+ sourceId: number(),
63555
+ targetId: number(),
63556
+ switches: array(MigrateSwitchReportSchema).readonly(),
63557
+ /** Switches that could NOT be turned off on the source. Empty is the only
63558
+ * value meaning the replaced hardware is quiet. */
63559
+ sourceStillLive: array(CameraSwitchIdSchema).readonly(),
63560
+ swapped: boolean()
63561
+ });
63538
63562
  method(object({
63539
63563
  addonId: string(),
63540
63564
  stableId: string()
63541
- }), object({ id: number() }), { kind: "mutation" }), method(DeviceRegisterPayloadSchema, _void(), { kind: "mutation" }), method(DeviceRemovePayloadSchema, _void(), { kind: "mutation" }), method(DevicePersistConfigPayloadSchema, _void(), { kind: "mutation" }), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), DeviceMetaSchema.nullable()), method(object({
63565
+ }), object({ id: number() }), { kind: "mutation" }), method(object({
63566
+ sourceId: number(),
63567
+ targetId: number()
63568
+ }), MigrateDeviceResultSchema, {
63569
+ kind: "mutation",
63570
+ auth: "admin"
63571
+ }), method(DeviceRegisterPayloadSchema, _void(), { kind: "mutation" }), method(DeviceRemovePayloadSchema, _void(), { kind: "mutation" }), method(DevicePersistConfigPayloadSchema, _void(), { kind: "mutation" }), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), DeviceMetaSchema.nullable()), method(object({
63542
63572
  deviceId: number(),
63543
63573
  name: string()
63544
63574
  }), _void(), {
@@ -69713,6 +69743,34 @@ var KeyEventsForDeviceSchema = object({
69713
69743
  deviceId: number(),
69714
69744
  events: array(KeyEventSchema).readonly()
69715
69745
  });
69746
+ /** One non-empty bucket of the timeline histogram. */
69747
+ var EventDensityBucketSchema = object({
69748
+ bucketStart: number(),
69749
+ motion: number().int(),
69750
+ object: number().int(),
69751
+ audio: number().int()
69752
+ });
69753
+ /**
69754
+ * One camera's row in a `getEventDensityBatch` answer.
69755
+ *
69756
+ * TWO facts, and the timeline draws them differently:
69757
+ *
69758
+ * - `read: 'read'` — the histogram for this camera. `buckets: []` is a real
69759
+ * claim: read, and nothing happened in the window.
69760
+ * - `read: 'unreadable'` — nobody could answer for this camera. `buckets` is
69761
+ * empty and that emptiness means NOTHING; the timeline must render unknown,
69762
+ * not quiet.
69763
+ *
69764
+ * Fanned out per camera the difference was free — one query rejected while the
69765
+ * others resolved — and collapsing to a batch is the exact moment it is lost
69766
+ * silently. Every requested id gets a row: a caller that asked for twelve and
69767
+ * got eleven cannot tell which one is missing, or that any is.
69768
+ */
69769
+ var EventDensityForDeviceSchema = object({
69770
+ deviceId: number(),
69771
+ read: _enum(["read", "unreadable"]),
69772
+ buckets: array(EventDensityBucketSchema).readonly()
69773
+ });
69716
69774
  object({
69717
69775
  trackId: string(),
69718
69776
  className: string(),
@@ -70023,12 +70081,12 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
70023
70081
  since: number(),
70024
70082
  until: number(),
70025
70083
  bucketMs: number().int().positive()
70026
- }), array(object({
70027
- bucketStart: number(),
70028
- motion: number().int(),
70029
- object: number().int(),
70030
- audio: number().int()
70031
- })).readonly()), method(object({
70084
+ }), array(EventDensityBucketSchema).readonly()), method(object({
70085
+ deviceIds: array(number()).min(1).max(200),
70086
+ since: number(),
70087
+ until: number(),
70088
+ bucketMs: number().int().positive()
70089
+ }), array(EventDensityForDeviceSchema).readonly()), method(object({
70032
70090
  deviceId: number(),
70033
70091
  cutoffMs: number()
70034
70092
  }), object({
@@ -79078,6 +79136,39 @@ var RecordingDaysSchema = object({
79078
79136
  /** Local-midnight epochs (UTC ms) of days that have ≥1 recorded segment. */
79079
79137
  days: array(number())
79080
79138
  });
79139
+ /**
79140
+ * One camera's row in a `getAvailabilityBatch` answer.
79141
+ *
79142
+ * `ranges` is EXACTLY what `getAvailability` returns for that camera — the
79143
+ * batch collapses the transport, not the work — plus the one thing the singular
79144
+ * method never had to say:
79145
+ *
79146
+ * - `read: 'read'` — answered. `ranges: []` means "read, and this camera has
79147
+ * no footage in the window", which is a real claim.
79148
+ * - `read: 'unreadable'` — the recorder could not answer for this camera (its
79149
+ * calendar rung threw, its location is unmounted). `ranges` is empty and
79150
+ * that emptiness means NOTHING.
79151
+ *
79152
+ * A timeline that renders the second as the first tells an operator there is no
79153
+ * footage when the truth is that nobody looked.
79154
+ */
79155
+ var RecordingAvailabilityForDeviceSchema = object({
79156
+ deviceId: number(),
79157
+ read: _enum(["read", "unreadable"]),
79158
+ ranges: array(RecordingRangeSchema).readonly()
79159
+ });
79160
+ /**
79161
+ * One camera's row in a `getDaysWithRecordingsBatch` answer. Same rule as
79162
+ * {@link RecordingAvailabilityForDeviceSchema}: `days: []` on a `'read'` row is
79163
+ * "no footage in this month", `read: 'unreadable'` is "nobody could look", and
79164
+ * the date-picker's day dots must not spell them the same.
79165
+ */
79166
+ var RecordingDaysForDeviceSchema = object({
79167
+ deviceId: number(),
79168
+ read: _enum(["read", "unreadable"]),
79169
+ /** Local-midnight epochs (UTC ms) of days that have ≥1 recorded segment. */
79170
+ days: array(number()).readonly()
79171
+ });
79081
79172
  var RecordingManifestSchema = object({
79082
79173
  deviceId: number(),
79083
79174
  /** Local filesystem path to the master playlist; null when no recording exists for the requested range. */
@@ -79312,6 +79403,13 @@ method(object({
79312
79403
  }), RecordingAvailabilitySchema, {
79313
79404
  kind: "query",
79314
79405
  auth: "protected"
79406
+ }), method(object({
79407
+ deviceIds: array(number()).min(1).max(200),
79408
+ fromMs: number(),
79409
+ toMs: number()
79410
+ }), array(RecordingAvailabilityForDeviceSchema).readonly(), {
79411
+ kind: "query",
79412
+ auth: "protected"
79315
79413
  }), method(object({
79316
79414
  deviceId: number(),
79317
79415
  fromMs: number(),
@@ -79320,6 +79418,14 @@ method(object({
79320
79418
  }), RecordingDaysSchema, {
79321
79419
  kind: "query",
79322
79420
  auth: "protected"
79421
+ }), method(object({
79422
+ deviceIds: array(number()).min(1).max(200),
79423
+ fromMs: number(),
79424
+ toMs: number(),
79425
+ tzOffsetMinutes: number()
79426
+ }), array(RecordingDaysForDeviceSchema).readonly(), {
79427
+ kind: "query",
79428
+ auth: "protected"
79323
79429
  }), method(object({
79324
79430
  deviceId: number(),
79325
79431
  fromMs: number(),
@@ -84482,6 +84588,12 @@ Object.freeze({
84482
84588
  addonId: null,
84483
84589
  access: "view"
84484
84590
  },
84591
+ "deviceManager.migrateDevice": {
84592
+ capName: "device-manager",
84593
+ capScope: "system",
84594
+ addonId: null,
84595
+ access: "create"
84596
+ },
84485
84597
  "deviceManager.persistConfig": {
84486
84598
  capName: "device-manager",
84487
84599
  capScope: "system",
@@ -86216,6 +86328,12 @@ Object.freeze({
86216
86328
  addonId: null,
86217
86329
  access: "view"
86218
86330
  },
86331
+ "pipelineAnalytics.getEventDensityBatch": {
86332
+ capName: "pipeline-analytics",
86333
+ capScope: "device",
86334
+ addonId: null,
86335
+ access: "view"
86336
+ },
86219
86337
  "pipelineAnalytics.getEventMedia": {
86220
86338
  capName: "pipeline-analytics",
86221
86339
  capScope: "device",
@@ -87338,12 +87456,24 @@ Object.freeze({
87338
87456
  addonId: null,
87339
87457
  access: "view"
87340
87458
  },
87459
+ "recording.getAvailabilityBatch": {
87460
+ capName: "recording",
87461
+ capScope: "system",
87462
+ addonId: null,
87463
+ access: "view"
87464
+ },
87341
87465
  "recording.getDaysWithRecordings": {
87342
87466
  capName: "recording",
87343
87467
  capScope: "system",
87344
87468
  addonId: null,
87345
87469
  access: "view"
87346
87470
  },
87471
+ "recording.getDaysWithRecordingsBatch": {
87472
+ capName: "recording",
87473
+ capScope: "system",
87474
+ addonId: null,
87475
+ access: "view"
87476
+ },
87347
87477
  "recording.getDeviceConfig": {
87348
87478
  capName: "recording",
87349
87479
  capScope: "system",
@@ -89948,6 +90078,11 @@ Object.freeze({
89948
90078
  form: "single",
89949
90079
  optional: false
89950
90080
  }],
90081
+ "pipelineAnalytics.getEventDensityBatch": [{
90082
+ name: "deviceIds",
90083
+ form: "array",
90084
+ optional: false
90085
+ }],
89951
90086
  "pipelineAnalytics.getEventMedia": [{
89952
90087
  name: "deviceId",
89953
90088
  form: "single",
@@ -90363,11 +90498,21 @@ Object.freeze({
90363
90498
  form: "single",
90364
90499
  optional: false
90365
90500
  }],
90501
+ "recording.getAvailabilityBatch": [{
90502
+ name: "deviceIds",
90503
+ form: "array",
90504
+ optional: false
90505
+ }],
90366
90506
  "recording.getDaysWithRecordings": [{
90367
90507
  name: "deviceId",
90368
90508
  form: "single",
90369
90509
  optional: false
90370
90510
  }],
90511
+ "recording.getDaysWithRecordingsBatch": [{
90512
+ name: "deviceIds",
90513
+ form: "array",
90514
+ optional: false
90515
+ }],
90371
90516
  "recording.getDeviceConfig": [{
90372
90517
  name: "deviceId",
90373
90518
  form: "single",
package/dist/addon.mjs CHANGED
@@ -58223,7 +58223,8 @@ var OpsLogReasonSchema = _enum([
58223
58223
  "quota",
58224
58224
  "manual",
58225
58225
  "operator",
58226
- "maintenance"
58226
+ "maintenance",
58227
+ "orphaned-device"
58227
58228
  ]);
58228
58229
  /** One audit row, shared verbatim by both domains. */
58229
58230
  var OpsLogEntrySchema = object({
@@ -63535,10 +63536,39 @@ var DevicePersistConfigPayloadSchema = object({
63535
63536
  deviceId: number(),
63536
63537
  data: record(string(), unknown())
63537
63538
  });
63539
+ /** What a migration actually did, per switch. `unreachable` is a first-class
63540
+ * answer: a camera that could not be asked is not a camera that was silenced. */
63541
+ var MigrateSwitchOutcomeSchema = _enum([
63542
+ "off",
63543
+ "on",
63544
+ "not-offered",
63545
+ "unreachable"
63546
+ ]);
63547
+ var MigrateSwitchReportSchema = object({
63548
+ deviceId: number(),
63549
+ switchId: CameraSwitchIdSchema,
63550
+ outcome: MigrateSwitchOutcomeSchema,
63551
+ detail: string().optional()
63552
+ });
63553
+ var MigrateDeviceResultSchema = object({
63554
+ sourceId: number(),
63555
+ targetId: number(),
63556
+ switches: array(MigrateSwitchReportSchema).readonly(),
63557
+ /** Switches that could NOT be turned off on the source. Empty is the only
63558
+ * value meaning the replaced hardware is quiet. */
63559
+ sourceStillLive: array(CameraSwitchIdSchema).readonly(),
63560
+ swapped: boolean()
63561
+ });
63538
63562
  method(object({
63539
63563
  addonId: string(),
63540
63564
  stableId: string()
63541
- }), object({ id: number() }), { kind: "mutation" }), method(DeviceRegisterPayloadSchema, _void(), { kind: "mutation" }), method(DeviceRemovePayloadSchema, _void(), { kind: "mutation" }), method(DevicePersistConfigPayloadSchema, _void(), { kind: "mutation" }), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), DeviceMetaSchema.nullable()), method(object({
63565
+ }), object({ id: number() }), { kind: "mutation" }), method(object({
63566
+ sourceId: number(),
63567
+ targetId: number()
63568
+ }), MigrateDeviceResultSchema, {
63569
+ kind: "mutation",
63570
+ auth: "admin"
63571
+ }), method(DeviceRegisterPayloadSchema, _void(), { kind: "mutation" }), method(DeviceRemovePayloadSchema, _void(), { kind: "mutation" }), method(DevicePersistConfigPayloadSchema, _void(), { kind: "mutation" }), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), record(string(), unknown())), method(object({ deviceId: number() }), DeviceMetaSchema.nullable()), method(object({
63542
63572
  deviceId: number(),
63543
63573
  name: string()
63544
63574
  }), _void(), {
@@ -69713,6 +69743,34 @@ var KeyEventsForDeviceSchema = object({
69713
69743
  deviceId: number(),
69714
69744
  events: array(KeyEventSchema).readonly()
69715
69745
  });
69746
+ /** One non-empty bucket of the timeline histogram. */
69747
+ var EventDensityBucketSchema = object({
69748
+ bucketStart: number(),
69749
+ motion: number().int(),
69750
+ object: number().int(),
69751
+ audio: number().int()
69752
+ });
69753
+ /**
69754
+ * One camera's row in a `getEventDensityBatch` answer.
69755
+ *
69756
+ * TWO facts, and the timeline draws them differently:
69757
+ *
69758
+ * - `read: 'read'` — the histogram for this camera. `buckets: []` is a real
69759
+ * claim: read, and nothing happened in the window.
69760
+ * - `read: 'unreadable'` — nobody could answer for this camera. `buckets` is
69761
+ * empty and that emptiness means NOTHING; the timeline must render unknown,
69762
+ * not quiet.
69763
+ *
69764
+ * Fanned out per camera the difference was free — one query rejected while the
69765
+ * others resolved — and collapsing to a batch is the exact moment it is lost
69766
+ * silently. Every requested id gets a row: a caller that asked for twelve and
69767
+ * got eleven cannot tell which one is missing, or that any is.
69768
+ */
69769
+ var EventDensityForDeviceSchema = object({
69770
+ deviceId: number(),
69771
+ read: _enum(["read", "unreadable"]),
69772
+ buckets: array(EventDensityBucketSchema).readonly()
69773
+ });
69716
69774
  object({
69717
69775
  trackId: string(),
69718
69776
  className: string(),
@@ -70023,12 +70081,12 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
70023
70081
  since: number(),
70024
70082
  until: number(),
70025
70083
  bucketMs: number().int().positive()
70026
- }), array(object({
70027
- bucketStart: number(),
70028
- motion: number().int(),
70029
- object: number().int(),
70030
- audio: number().int()
70031
- })).readonly()), method(object({
70084
+ }), array(EventDensityBucketSchema).readonly()), method(object({
70085
+ deviceIds: array(number()).min(1).max(200),
70086
+ since: number(),
70087
+ until: number(),
70088
+ bucketMs: number().int().positive()
70089
+ }), array(EventDensityForDeviceSchema).readonly()), method(object({
70032
70090
  deviceId: number(),
70033
70091
  cutoffMs: number()
70034
70092
  }), object({
@@ -79078,6 +79136,39 @@ var RecordingDaysSchema = object({
79078
79136
  /** Local-midnight epochs (UTC ms) of days that have ≥1 recorded segment. */
79079
79137
  days: array(number())
79080
79138
  });
79139
+ /**
79140
+ * One camera's row in a `getAvailabilityBatch` answer.
79141
+ *
79142
+ * `ranges` is EXACTLY what `getAvailability` returns for that camera — the
79143
+ * batch collapses the transport, not the work — plus the one thing the singular
79144
+ * method never had to say:
79145
+ *
79146
+ * - `read: 'read'` — answered. `ranges: []` means "read, and this camera has
79147
+ * no footage in the window", which is a real claim.
79148
+ * - `read: 'unreadable'` — the recorder could not answer for this camera (its
79149
+ * calendar rung threw, its location is unmounted). `ranges` is empty and
79150
+ * that emptiness means NOTHING.
79151
+ *
79152
+ * A timeline that renders the second as the first tells an operator there is no
79153
+ * footage when the truth is that nobody looked.
79154
+ */
79155
+ var RecordingAvailabilityForDeviceSchema = object({
79156
+ deviceId: number(),
79157
+ read: _enum(["read", "unreadable"]),
79158
+ ranges: array(RecordingRangeSchema).readonly()
79159
+ });
79160
+ /**
79161
+ * One camera's row in a `getDaysWithRecordingsBatch` answer. Same rule as
79162
+ * {@link RecordingAvailabilityForDeviceSchema}: `days: []` on a `'read'` row is
79163
+ * "no footage in this month", `read: 'unreadable'` is "nobody could look", and
79164
+ * the date-picker's day dots must not spell them the same.
79165
+ */
79166
+ var RecordingDaysForDeviceSchema = object({
79167
+ deviceId: number(),
79168
+ read: _enum(["read", "unreadable"]),
79169
+ /** Local-midnight epochs (UTC ms) of days that have ≥1 recorded segment. */
79170
+ days: array(number()).readonly()
79171
+ });
79081
79172
  var RecordingManifestSchema = object({
79082
79173
  deviceId: number(),
79083
79174
  /** Local filesystem path to the master playlist; null when no recording exists for the requested range. */
@@ -79312,6 +79403,13 @@ method(object({
79312
79403
  }), RecordingAvailabilitySchema, {
79313
79404
  kind: "query",
79314
79405
  auth: "protected"
79406
+ }), method(object({
79407
+ deviceIds: array(number()).min(1).max(200),
79408
+ fromMs: number(),
79409
+ toMs: number()
79410
+ }), array(RecordingAvailabilityForDeviceSchema).readonly(), {
79411
+ kind: "query",
79412
+ auth: "protected"
79315
79413
  }), method(object({
79316
79414
  deviceId: number(),
79317
79415
  fromMs: number(),
@@ -79320,6 +79418,14 @@ method(object({
79320
79418
  }), RecordingDaysSchema, {
79321
79419
  kind: "query",
79322
79420
  auth: "protected"
79421
+ }), method(object({
79422
+ deviceIds: array(number()).min(1).max(200),
79423
+ fromMs: number(),
79424
+ toMs: number(),
79425
+ tzOffsetMinutes: number()
79426
+ }), array(RecordingDaysForDeviceSchema).readonly(), {
79427
+ kind: "query",
79428
+ auth: "protected"
79323
79429
  }), method(object({
79324
79430
  deviceId: number(),
79325
79431
  fromMs: number(),
@@ -84482,6 +84588,12 @@ Object.freeze({
84482
84588
  addonId: null,
84483
84589
  access: "view"
84484
84590
  },
84591
+ "deviceManager.migrateDevice": {
84592
+ capName: "device-manager",
84593
+ capScope: "system",
84594
+ addonId: null,
84595
+ access: "create"
84596
+ },
84485
84597
  "deviceManager.persistConfig": {
84486
84598
  capName: "device-manager",
84487
84599
  capScope: "system",
@@ -86216,6 +86328,12 @@ Object.freeze({
86216
86328
  addonId: null,
86217
86329
  access: "view"
86218
86330
  },
86331
+ "pipelineAnalytics.getEventDensityBatch": {
86332
+ capName: "pipeline-analytics",
86333
+ capScope: "device",
86334
+ addonId: null,
86335
+ access: "view"
86336
+ },
86219
86337
  "pipelineAnalytics.getEventMedia": {
86220
86338
  capName: "pipeline-analytics",
86221
86339
  capScope: "device",
@@ -87338,12 +87456,24 @@ Object.freeze({
87338
87456
  addonId: null,
87339
87457
  access: "view"
87340
87458
  },
87459
+ "recording.getAvailabilityBatch": {
87460
+ capName: "recording",
87461
+ capScope: "system",
87462
+ addonId: null,
87463
+ access: "view"
87464
+ },
87341
87465
  "recording.getDaysWithRecordings": {
87342
87466
  capName: "recording",
87343
87467
  capScope: "system",
87344
87468
  addonId: null,
87345
87469
  access: "view"
87346
87470
  },
87471
+ "recording.getDaysWithRecordingsBatch": {
87472
+ capName: "recording",
87473
+ capScope: "system",
87474
+ addonId: null,
87475
+ access: "view"
87476
+ },
87347
87477
  "recording.getDeviceConfig": {
87348
87478
  capName: "recording",
87349
87479
  capScope: "system",
@@ -89948,6 +90078,11 @@ Object.freeze({
89948
90078
  form: "single",
89949
90079
  optional: false
89950
90080
  }],
90081
+ "pipelineAnalytics.getEventDensityBatch": [{
90082
+ name: "deviceIds",
90083
+ form: "array",
90084
+ optional: false
90085
+ }],
89951
90086
  "pipelineAnalytics.getEventMedia": [{
89952
90087
  name: "deviceId",
89953
90088
  form: "single",
@@ -90363,11 +90498,21 @@ Object.freeze({
90363
90498
  form: "single",
90364
90499
  optional: false
90365
90500
  }],
90501
+ "recording.getAvailabilityBatch": [{
90502
+ name: "deviceIds",
90503
+ form: "array",
90504
+ optional: false
90505
+ }],
90366
90506
  "recording.getDaysWithRecordings": [{
90367
90507
  name: "deviceId",
90368
90508
  form: "single",
90369
90509
  optional: false
90370
90510
  }],
90511
+ "recording.getDaysWithRecordingsBatch": [{
90512
+ name: "deviceIds",
90513
+ form: "array",
90514
+ optional: false
90515
+ }],
90371
90516
  "recording.getDeviceConfig": [{
90372
90517
  name: "deviceId",
90373
90518
  form: "single",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-dreame",
3
- "version": "0.2.51",
3
+ "version": "0.2.53",
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",