yoto-nodejs-client 0.0.6 → 0.0.8

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.
@@ -171,6 +171,10 @@ export const YotoPlaybackStateType: {};
171
171
  * MQTT disconnect event metadata (from MQTT disconnect packet)
172
172
  * @typedef {YotoMqttClientDisconnectMetadata} YotoMqttDisconnectMetadata
173
173
  */
174
+ /**
175
+ * MQTT connect event metadata (from MQTT CONNACK)
176
+ * @typedef {IConnackPacket} YotoMqttConnectMetadata
177
+ */
174
178
  /**
175
179
  * MQTT close event metadata (from connection close)
176
180
  * @typedef {YotoMqttClientCloseMetadata} YotoMqttCloseMetadata
@@ -196,12 +200,17 @@ export const YotoPlaybackStateType: {};
196
200
  * 'playbackUpdate': [YotoPlaybackState, Set<keyof YotoPlaybackState>],
197
201
  * 'online': [YotoDeviceOnlineMetadata],
198
202
  * 'offline': [YotoDeviceOfflineMetadata],
199
- * 'mqttConnect': [],
203
+ * 'mqttConnect': [YotoMqttConnectMetadata],
200
204
  * 'mqttDisconnect': [YotoMqttDisconnectMetadata],
201
205
  * 'mqttClose': [YotoMqttCloseMetadata],
202
206
  * 'mqttReconnect': [],
203
207
  * 'mqttOffline': [],
204
208
  * 'mqttEnd': [],
209
+ * 'mqttStatus': [string, YotoStatusMessage],
210
+ * 'mqttEvents': [string, YotoEventsMessage],
211
+ * 'mqttStatusLegacy': [string, YotoStatusLegacyMessage],
212
+ * 'mqttResponse': [string, YotoResponseMessage],
213
+ * 'mqttUnknown': [string, unknown],
205
214
  * 'error': [Error]
206
215
  * }} YotoDeviceModelEventMap
207
216
  */
@@ -223,12 +232,17 @@ export const YotoPlaybackStateType: {};
223
232
  * - 'playbackUpdate' - Emitted when playback state changes, passes (playback, changedFields)
224
233
  * - 'online' - Emitted when device comes online, passes metadata with reason and optional upTime
225
234
  * - 'offline' - Emitted when device goes offline, passes metadata with reason and optional shutDownReason or timeSinceLastSeen
226
- * - 'mqttConnect' - Emitted when MQTT client connects
235
+ * - 'mqttConnect' - Emitted when MQTT client connects, passes CONNACK metadata
227
236
  * - 'mqttDisconnect' - Emitted when MQTT disconnect packet received, passes metadata with disconnect packet
228
237
  * - 'mqttClose' - Emitted when MQTT connection closes, passes metadata with close reason
229
238
  * - 'mqttReconnect' - Emitted when MQTT client is reconnecting
230
239
  * - 'mqttOffline' - Emitted when MQTT client goes offline
231
240
  * - 'mqttEnd' - Emitted when MQTT client end is called
241
+ * - 'mqttStatus' - Emitted with raw MQTT status messages, passes (topic, message)
242
+ * - 'mqttEvents' - Emitted with raw MQTT events messages, passes (topic, message)
243
+ * - 'mqttStatusLegacy' - Emitted with raw legacy MQTT status messages, passes (topic, message)
244
+ * - 'mqttResponse' - Emitted with raw MQTT response messages, passes (topic, message)
245
+ * - 'mqttUnknown' - Emitted with unknown MQTT messages, passes (topic, message)
232
246
  * - 'error' - Emitted when an error occurs, passes error
233
247
  *
234
248
  * @extends {EventEmitter<YotoDeviceModelEventMap>}
@@ -375,23 +389,10 @@ export class YotoDeviceModel extends EventEmitter<YotoDeviceModelEventMap> {
375
389
  reboot(): Promise<void>;
376
390
  /**
377
391
  * Start card playback over MQTT
378
- * @param {Object} options - Card start options
379
- * @param {string} options.uri - Card URI (e.g., "https://yoto.io/<cardID>")
380
- * @param {string} [options.chapterKey] - Chapter to start from
381
- * @param {string} [options.trackKey] - Track to start from
382
- * @param {number} [options.secondsIn] - Playback start offset in seconds
383
- * @param {number} [options.cutOff] - Playback stop offset in seconds
384
- * @param {boolean} [options.anyButtonStop] - Whether button press stops playback
392
+ * @param {YotoCardStartOptions} options - Card start options
385
393
  * @returns {Promise<void>}
386
394
  */
387
- startCard(options: {
388
- uri: string;
389
- chapterKey?: string | undefined;
390
- trackKey?: string | undefined;
391
- secondsIn?: number | undefined;
392
- cutOff?: number | undefined;
393
- anyButtonStop?: boolean | undefined;
394
- }): Promise<void>;
395
+ startCard(options: YotoCardStartOptions): Promise<void>;
395
396
  /**
396
397
  * Stop card playback over MQTT
397
398
  * @returns {Promise<void>}
@@ -508,6 +509,35 @@ export type DayMode = "unknown" | "night" | "day";
508
509
  * Power source state
509
510
  */
510
511
  export type PowerSource = "battery" | "dock" | "usb-c" | "wireless";
512
+ /**
513
+ * Card start options for Yoto playback.
514
+ */
515
+ export type YotoCardStartOptions = {
516
+ /**
517
+ * - Card ID (used when uri is not provided)
518
+ */
519
+ cardId: string;
520
+ /**
521
+ * - Chapter to start from
522
+ */
523
+ chapterKey?: string;
524
+ /**
525
+ * - Track to start from
526
+ */
527
+ trackKey?: string;
528
+ /**
529
+ * - Playback start offset in seconds
530
+ */
531
+ secondsIn?: number;
532
+ /**
533
+ * - Playback stop offset in seconds
534
+ */
535
+ cutOff?: number;
536
+ /**
537
+ * - Whether button press stops playback
538
+ */
539
+ anyButtonStop?: boolean;
540
+ };
511
541
  /**
512
542
  * Canonical device status - normalized format for both HTTP and MQTT sources
513
543
  *
@@ -946,6 +976,10 @@ export type YotoDeviceOfflineMetadata = {
946
976
  * MQTT disconnect event metadata (from MQTT disconnect packet)
947
977
  */
948
978
  export type YotoMqttDisconnectMetadata = YotoMqttClientDisconnectMetadata;
979
+ /**
980
+ * MQTT connect event metadata (from MQTT CONNACK)
981
+ */
982
+ export type YotoMqttConnectMetadata = IConnackPacket;
949
983
  /**
950
984
  * MQTT close event metadata (from connection close)
951
985
  */
@@ -994,12 +1028,17 @@ export type YotoDeviceModelEventMap = {
994
1028
  "playbackUpdate": [YotoPlaybackState, Set<keyof YotoPlaybackState>];
995
1029
  "online": [YotoDeviceOnlineMetadata];
996
1030
  "offline": [YotoDeviceOfflineMetadata];
997
- "mqttConnect": [];
1031
+ "mqttConnect": [YotoMqttConnectMetadata];
998
1032
  "mqttDisconnect": [YotoMqttDisconnectMetadata];
999
1033
  "mqttClose": [YotoMqttCloseMetadata];
1000
1034
  "mqttReconnect": [];
1001
1035
  "mqttOffline": [];
1002
1036
  "mqttEnd": [];
1037
+ "mqttStatus": [string, YotoStatusMessage];
1038
+ "mqttEvents": [string, YotoEventsMessage];
1039
+ "mqttStatusLegacy": [string, YotoStatusLegacyMessage];
1040
+ "mqttResponse": [string, YotoResponseMessage];
1041
+ "mqttUnknown": [string, unknown];
1003
1042
  "error": [Error];
1004
1043
  };
1005
1044
  import { EventEmitter } from 'events';
@@ -1012,5 +1051,10 @@ import type { YotoClient } from './api-client.js';
1012
1051
  import type { PlaybackStatus } from './mqtt/client.js';
1013
1052
  import type { YotoMqttOptions } from './mqtt/factory.js';
1014
1053
  import type { YotoMqttClientDisconnectMetadata } from './mqtt/client.js';
1054
+ import type { IConnackPacket } from 'mqtt';
1015
1055
  import type { YotoMqttClientCloseMetadata } from './mqtt/client.js';
1056
+ import type { YotoStatusMessage } from './mqtt/client.js';
1057
+ import type { YotoEventsMessage } from './mqtt/client.js';
1058
+ import type { YotoStatusLegacyMessage } from './mqtt/client.js';
1059
+ import type { YotoResponseMessage } from './mqtt/client.js';
1016
1060
  //# sourceMappingURL=yoto-device.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"yoto-device.d.ts","sourceRoot":"","sources":["yoto-device.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"yoto-device.d.ts","sourceRoot":"","sources":["yoto-device.js"],"names":[],"mappings":"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"}
@@ -7,10 +7,12 @@
7
7
  */
8
8
 
9
9
  /**
10
+ * @import { IConnackPacket } from 'mqtt'
10
11
  * @import { YotoClient } from './api-client.js'
11
12
  * @import { YotoDevice, YotoDeviceConfig, YotoDeviceShortcuts, YotoDeviceFullStatus, YotoDeviceStatusResponse, YotoDeviceCommand, YotoDeviceCommandResponse } from './api-endpoints/devices.js'
12
- * @import { YotoMqttClient, YotoMqttStatus, YotoEventsMessage, YotoLegacyStatus, YotoMqttClientDisconnectMetadata, YotoMqttClientCloseMetadata, PlaybackStatus } from './mqtt/client.js'
13
+ * @import { YotoMqttClient, YotoMqttStatus, YotoEventsMessage, YotoLegacyStatus, YotoStatusMessage, YotoStatusLegacyMessage, YotoResponseMessage, YotoMqttClientDisconnectMetadata, YotoMqttClientCloseMetadata, PlaybackStatus } from './mqtt/client.js'
13
14
  * @import { YotoMqttOptions } from './mqtt/factory.js'
15
+ * @import { YotoCardStartCommand } from './mqtt/commands.js'
14
16
  */
15
17
 
16
18
  import { EventEmitter } from 'events'
@@ -80,6 +82,17 @@ function convertPowerSource (numericSource) {
80
82
  * @typedef {'battery' | 'dock' | 'usb-c' | 'wireless'} PowerSource
81
83
  */
82
84
 
85
+ /**
86
+ * Card start options for Yoto playback.
87
+ * @typedef {Object} YotoCardStartOptions
88
+ * @property {string} cardId - Card ID (used when uri is not provided)
89
+ * @property {string} [chapterKey] - Chapter to start from
90
+ * @property {string} [trackKey] - Track to start from
91
+ * @property {number} [secondsIn] - Playback start offset in seconds
92
+ * @property {number} [cutOff] - Playback stop offset in seconds
93
+ * @property {boolean} [anyButtonStop] - Whether button press stops playback
94
+ */
95
+
83
96
  /**
84
97
  * Normalize "0"/"1" booleans from config to true/false.
85
98
  * @param {string | boolean} value
@@ -459,6 +472,11 @@ export const YotoPlaybackStateType = {}
459
472
  * @typedef {YotoMqttClientDisconnectMetadata} YotoMqttDisconnectMetadata
460
473
  */
461
474
 
475
+ /**
476
+ * MQTT connect event metadata (from MQTT CONNACK)
477
+ * @typedef {IConnackPacket} YotoMqttConnectMetadata
478
+ */
479
+
462
480
  /**
463
481
  * MQTT close event metadata (from connection close)
464
482
  * @typedef {YotoMqttClientCloseMetadata} YotoMqttCloseMetadata
@@ -486,12 +504,17 @@ export const YotoPlaybackStateType = {}
486
504
  * 'playbackUpdate': [YotoPlaybackState, Set<keyof YotoPlaybackState>],
487
505
  * 'online': [YotoDeviceOnlineMetadata],
488
506
  * 'offline': [YotoDeviceOfflineMetadata],
489
- * 'mqttConnect': [],
507
+ * 'mqttConnect': [YotoMqttConnectMetadata],
490
508
  * 'mqttDisconnect': [YotoMqttDisconnectMetadata],
491
509
  * 'mqttClose': [YotoMqttCloseMetadata],
492
510
  * 'mqttReconnect': [],
493
511
  * 'mqttOffline': [],
494
512
  * 'mqttEnd': [],
513
+ * 'mqttStatus': [string, YotoStatusMessage],
514
+ * 'mqttEvents': [string, YotoEventsMessage],
515
+ * 'mqttStatusLegacy': [string, YotoStatusLegacyMessage],
516
+ * 'mqttResponse': [string, YotoResponseMessage],
517
+ * 'mqttUnknown': [string, unknown],
495
518
  * 'error': [Error]
496
519
  * }} YotoDeviceModelEventMap
497
520
  */
@@ -518,12 +541,17 @@ export const YotoPlaybackStateType = {}
518
541
  * - 'playbackUpdate' - Emitted when playback state changes, passes (playback, changedFields)
519
542
  * - 'online' - Emitted when device comes online, passes metadata with reason and optional upTime
520
543
  * - 'offline' - Emitted when device goes offline, passes metadata with reason and optional shutDownReason or timeSinceLastSeen
521
- * - 'mqttConnect' - Emitted when MQTT client connects
544
+ * - 'mqttConnect' - Emitted when MQTT client connects, passes CONNACK metadata
522
545
  * - 'mqttDisconnect' - Emitted when MQTT disconnect packet received, passes metadata with disconnect packet
523
546
  * - 'mqttClose' - Emitted when MQTT connection closes, passes metadata with close reason
524
547
  * - 'mqttReconnect' - Emitted when MQTT client is reconnecting
525
548
  * - 'mqttOffline' - Emitted when MQTT client goes offline
526
549
  * - 'mqttEnd' - Emitted when MQTT client end is called
550
+ * - 'mqttStatus' - Emitted with raw MQTT status messages, passes (topic, message)
551
+ * - 'mqttEvents' - Emitted with raw MQTT events messages, passes (topic, message)
552
+ * - 'mqttStatusLegacy' - Emitted with raw legacy MQTT status messages, passes (topic, message)
553
+ * - 'mqttResponse' - Emitted with raw MQTT response messages, passes (topic, message)
554
+ * - 'mqttUnknown' - Emitted with unknown MQTT messages, passes (topic, message)
527
555
  * - 'error' - Emitted when an error occurs, passes error
528
556
  *
529
557
  * @extends {EventEmitter<YotoDeviceModelEventMap>}
@@ -925,17 +953,26 @@ export class YotoDeviceModel extends EventEmitter {
925
953
 
926
954
  /**
927
955
  * Start card playback over MQTT
928
- * @param {Object} options - Card start options
929
- * @param {string} options.uri - Card URI (e.g., "https://yoto.io/<cardID>")
930
- * @param {string} [options.chapterKey] - Chapter to start from
931
- * @param {string} [options.trackKey] - Track to start from
932
- * @param {number} [options.secondsIn] - Playback start offset in seconds
933
- * @param {number} [options.cutOff] - Playback stop offset in seconds
934
- * @param {boolean} [options.anyButtonStop] - Whether button press stops playback
956
+ * @param {YotoCardStartOptions} options - Card start options
935
957
  * @returns {Promise<void>}
936
958
  */
937
959
  async startCard (options) {
938
- return await this.#mqttClient?.startCard(options)
960
+ const uri = `https://yoto.io/${options.cardId}`
961
+
962
+ if (!uri) {
963
+ throw new Error('Card URI or cardId is required')
964
+ }
965
+
966
+ /** @type {YotoCardStartCommand} */
967
+ const payload = { uri }
968
+
969
+ if (typeof options.chapterKey === 'string') payload.chapterKey = options.chapterKey
970
+ if (typeof options.trackKey === 'string') payload.trackKey = options.trackKey
971
+ if (typeof options.secondsIn === 'number') payload.secondsIn = options.secondsIn
972
+ if (typeof options.cutOff === 'number') payload.cutOff = options.cutOff
973
+ if (typeof options.anyButtonStop === 'boolean') payload.anyButtonStop = options.anyButtonStop
974
+
975
+ return await this.#mqttClient?.startCard(payload)
939
976
  }
940
977
 
941
978
  /**
@@ -1144,8 +1181,8 @@ export class YotoDeviceModel extends EventEmitter {
1144
1181
  if (!this.#mqttClient) return
1145
1182
 
1146
1183
  // Connection events
1147
- this.#mqttClient.on('connect', () => {
1148
- this.emit('mqttConnect')
1184
+ this.#mqttClient.on('connect', (metadata) => {
1185
+ this.emit('mqttConnect', metadata)
1149
1186
 
1150
1187
  // Request status and events after settling period
1151
1188
  this.#scheduleMqttRequests()
@@ -1186,8 +1223,9 @@ export class YotoDeviceModel extends EventEmitter {
1186
1223
  })
1187
1224
 
1188
1225
  // Status updates - PRIMARY source for status after initialization
1189
- this.#mqttClient.on('status', (_topic, message) => {
1226
+ this.#mqttClient.on('status', (topic, message) => {
1190
1227
  this.#recordDeviceActivity()
1228
+ this.emit('mqttStatus', topic, message)
1191
1229
  this.#updateStatusFromDocumentedMqtt(message.status)
1192
1230
  })
1193
1231
 
@@ -1195,20 +1233,25 @@ export class YotoDeviceModel extends EventEmitter {
1195
1233
  // This does NOT respond to requestStatus() - only emits on real-time events or 5-minute periodic updates
1196
1234
  // NOTE: Don't call #recordDeviceActivity() here - #handleLegacyStatus handles online/offline transitions
1197
1235
  // based on actual power state (shutdown/startup) which is more reliable than just "activity"
1198
- this.#mqttClient.on('status-legacy', (_topic, message) => {
1236
+ this.#mqttClient.on('status-legacy', (topic, message) => {
1237
+ this.emit('mqttStatusLegacy', topic, message)
1199
1238
  this.#handleLegacyStatus(message.status)
1200
1239
  })
1201
1240
 
1202
1241
  // Events updates (playback, volume, etc.)
1203
- this.#mqttClient.on('events', (_topic, message) => {
1242
+ this.#mqttClient.on('events', (topic, message) => {
1204
1243
  this.#recordDeviceActivity()
1244
+ this.emit('mqttEvents', topic, message)
1205
1245
  this.#handleEventMessage(message)
1206
1246
  })
1207
1247
 
1208
1248
  // Response messages (for debugging/logging)
1209
- this.#mqttClient.on('response', (_topic, _message) => {
1210
- // Could emit these for command confirmation
1211
- // For now just log internally
1249
+ this.#mqttClient.on('response', (topic, message) => {
1250
+ this.emit('mqttResponse', topic, message)
1251
+ })
1252
+
1253
+ this.#mqttClient.on('unknown', (topic, message) => {
1254
+ this.emit('mqttUnknown', topic, message)
1212
1255
  })
1213
1256
  }
1214
1257
 
@@ -1,15 +1,18 @@
1
- /** @import { YotoDeviceModelConfig, YotoPlaybackState } from './yoto-device.js' */
2
1
  /** @import { YotoDevice } from './api-endpoints/devices.js' */
3
2
 
4
3
  import test from 'node:test'
5
4
  import assert from 'node:assert/strict'
6
- import { once } from 'node:events'
7
- import { setTimeout as sleep } from 'node:timers/promises'
8
5
  import { join } from 'node:path'
9
6
  import { YotoClient } from './api-client.js'
10
7
  import { YotoDeviceModel } from './yoto-device.js'
11
8
  import { loadTestTokens } from './api-endpoints/endpoint-test-helpers.js'
12
9
  import { saveTokensToEnv } from '../bin/lib/token-helpers.js'
10
+ import {
11
+ assertConfigShape,
12
+ assertPlaybackShape,
13
+ toLower,
14
+ waitForModelReady
15
+ } from './test-helpers/device-model-test-helpers.js'
13
16
 
14
17
  const envPath = join(import.meta.dirname, '..', '.env')
15
18
 
@@ -41,109 +44,6 @@ function createTestClient () {
41
44
  })
42
45
  }
43
46
 
44
- /**
45
- * @param {Promise<unknown>} promise
46
- * @param {number} timeoutMs
47
- * @param {string} label
48
- * @returns {Promise<unknown>}
49
- */
50
- function withTimeout (promise, timeoutMs, label) {
51
- return Promise.race([
52
- promise,
53
- sleep(timeoutMs).then(() => {
54
- throw new Error(`${label} timed out after ${timeoutMs}ms`)
55
- })
56
- ])
57
- }
58
-
59
- /**
60
- * @param {YotoDeviceModel} model
61
- * @returns {Promise<void>}
62
- */
63
- async function waitForModelReady (model) {
64
- const started = withTimeout(once(model, 'started'), 15000, 'started')
65
- const statusUpdated = withTimeout(once(model, 'statusUpdate'), 15000, 'statusUpdate')
66
- const configUpdated = withTimeout(once(model, 'configUpdate'), 15000, 'configUpdate')
67
-
68
- await model.start()
69
- await Promise.all([started, statusUpdated, configUpdated])
70
- await sleep(1500)
71
- }
72
-
73
- /**
74
- * @param {YotoDeviceModelConfig} config
75
- */
76
- function assertConfigShape (config) {
77
- assert.ok(Array.isArray(config.alarms), 'alarms should be an array')
78
- assert.equal(typeof config.ambientColour, 'string', 'ambientColour should be string')
79
- assert.equal(typeof config.bluetoothEnabled, 'boolean', 'bluetoothEnabled should be boolean')
80
- assert.equal(typeof config.btHeadphonesEnabled, 'boolean', 'btHeadphonesEnabled should be boolean')
81
- assert.equal(typeof config.clockFace, 'string', 'clockFace should be string')
82
- assert.equal(typeof config.dayDisplayBrightnessAuto, 'boolean', 'dayDisplayBrightnessAuto should be boolean')
83
- if (config.dayDisplayBrightnessAuto) {
84
- assert.equal(config.dayDisplayBrightness, null, 'dayDisplayBrightness should be null when auto')
85
- } else {
86
- assert.equal(typeof config.dayDisplayBrightness, 'number', 'dayDisplayBrightness should be number when not auto')
87
- }
88
- assert.equal(typeof config.dayTime, 'string', 'dayTime should be string')
89
- assert.equal(typeof config.dayYotoDaily, 'string', 'dayYotoDaily should be string')
90
- assert.equal(typeof config.dayYotoRadio, 'string', 'dayYotoRadio should be string')
91
- assert.equal(typeof config.daySoundsOff, 'boolean', 'daySoundsOff should be boolean')
92
- assert.equal(typeof config.displayDimBrightness, 'number', 'displayDimBrightness should be number')
93
- assert.equal(typeof config.displayDimTimeout, 'number', 'displayDimTimeout should be number')
94
- assert.equal(typeof config.headphonesVolumeLimited, 'boolean', 'headphonesVolumeLimited should be boolean')
95
- assert.ok(config.hourFormat === 12 || config.hourFormat === 24, 'hourFormat should be 12 or 24')
96
- assert.equal(typeof config.locale, 'string', 'locale should be string')
97
- assert.equal(typeof config.logLevel, 'string', 'logLevel should be string')
98
- assert.equal(typeof config.maxVolumeLimit, 'number', 'maxVolumeLimit should be number')
99
- assert.equal(typeof config.nightAmbientColour, 'string', 'nightAmbientColour should be string')
100
- assert.equal(typeof config.nightDisplayBrightnessAuto, 'boolean', 'nightDisplayBrightnessAuto should be boolean')
101
- if (config.nightDisplayBrightnessAuto) {
102
- assert.equal(config.nightDisplayBrightness, null, 'nightDisplayBrightness should be null when auto')
103
- } else {
104
- assert.equal(typeof config.nightDisplayBrightness, 'number', 'nightDisplayBrightness should be number when not auto')
105
- }
106
- assert.equal(typeof config.nightMaxVolumeLimit, 'number', 'nightMaxVolumeLimit should be number')
107
- assert.equal(typeof config.nightTime, 'string', 'nightTime should be string')
108
- assert.equal(typeof config.nightYotoDaily, 'string', 'nightYotoDaily should be string')
109
- assert.equal(typeof config.nightYotoRadioEnabled, 'boolean', 'nightYotoRadioEnabled should be boolean')
110
- if (config.nightYotoRadioEnabled) {
111
- assert.equal(typeof config.nightYotoRadio, 'string', 'nightYotoRadio should be string when enabled')
112
- } else {
113
- assert.equal(config.nightYotoRadio, null, 'nightYotoRadio should be null when disabled')
114
- }
115
- assert.equal(typeof config.nightSoundsOff, 'boolean', 'nightSoundsOff should be boolean')
116
- assert.equal(typeof config.pausePowerButton, 'boolean', 'pausePowerButton should be boolean')
117
- assert.equal(typeof config.pauseVolumeDown, 'boolean', 'pauseVolumeDown should be boolean')
118
- assert.equal(typeof config.repeatAll, 'boolean', 'repeatAll should be boolean')
119
- assert.equal(typeof config.showDiagnostics, 'boolean', 'showDiagnostics should be boolean')
120
- assert.equal(typeof config.shutdownTimeout, 'number', 'shutdownTimeout should be number')
121
- assert.equal(typeof config.systemVolume, 'number', 'systemVolume should be number')
122
- assert.equal(typeof config.timezone, 'string', 'timezone should be string')
123
- assert.equal(typeof config.volumeLevel, 'string', 'volumeLevel should be string')
124
- }
125
-
126
- /**
127
- * @param {YotoPlaybackState} playback
128
- */
129
- function assertPlaybackShape (playback) {
130
- assert.ok(playback, 'playback should exist')
131
- assert.equal(typeof playback.updatedAt, 'string', 'playback.updatedAt should be string')
132
-
133
- assert.ok(playback.cardId === null || typeof playback.cardId === 'string', 'playback.cardId should be string or null')
134
- assert.ok(playback.source === null || typeof playback.source === 'string', 'playback.source should be string or null')
135
- assert.ok(playback.playbackStatus === null || typeof playback.playbackStatus === 'string', 'playback.playbackStatus should be string or null')
136
- assert.ok(playback.trackTitle === null || typeof playback.trackTitle === 'string', 'playback.trackTitle should be string or null')
137
- assert.ok(playback.trackKey === null || typeof playback.trackKey === 'string', 'playback.trackKey should be string or null')
138
- assert.ok(playback.chapterTitle === null || typeof playback.chapterTitle === 'string', 'playback.chapterTitle should be string or null')
139
- assert.ok(playback.chapterKey === null || typeof playback.chapterKey === 'string', 'playback.chapterKey should be string or null')
140
- assert.ok(playback.position === null || typeof playback.position === 'number', 'playback.position should be number or null')
141
- assert.ok(playback.trackLength === null || typeof playback.trackLength === 'number', 'playback.trackLength should be number or null')
142
- assert.ok(playback.streaming === null || typeof playback.streaming === 'boolean', 'playback.streaming should be boolean or null')
143
- assert.ok(playback.sleepTimerActive === null || typeof playback.sleepTimerActive === 'boolean', 'playback.sleepTimerActive should be boolean or null')
144
- assert.ok(playback.sleepTimerSeconds === null || typeof playback.sleepTimerSeconds === 'number', 'playback.sleepTimerSeconds should be number or null')
145
- }
146
-
147
47
  /**
148
48
  * @param {YotoClient} client
149
49
  * @param {YotoDevice} device
@@ -169,11 +69,6 @@ test('YotoDeviceModel - online devices', async (t) => {
169
69
  const client = createTestClient()
170
70
  const response = await client.getDevices()
171
71
 
172
- /**
173
- * @param {string | undefined} value
174
- * @returns {string}
175
- */
176
- const toLower = (value) => typeof value === 'string' ? value.toLowerCase() : ''
177
72
  const onlineMini = response.devices.find(device =>
178
73
  device.online && (toLower(device.deviceFamily) === 'mini' || toLower(device.deviceType).includes('mini'))
179
74
  )
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "yoto-nodejs-client",
3
3
  "description": "(Unofficial) Node.js client for the Yoto API with automatic token refresh, MQTT device communication, and TypeScript support",
4
- "version": "0.0.6",
4
+ "version": "0.0.8",
5
5
  "author": "Bret Comnes <bcomnes@gmail.com> (https://bret.io)",
6
6
  "bugs": {
7
7
  "url": "https://github.com/bcomnes/yoto-nodejs-client/issues"
@@ -69,17 +69,9 @@
69
69
  "type": "git",
70
70
  "url": "https://github.com/bcomnes/yoto-nodejs-client.git"
71
71
  },
72
- "funding": {
73
- "type": "individual",
74
- "url": "https://github.com/sponsors/bcomnes"
75
- },
76
- "c8": {
77
- "reporter": [
78
- "lcov",
79
- "text"
80
- ]
81
- },
82
72
  "scripts": {
73
+ "prepublishOnly": "npm run build && git push --follow-tags && gh-release -y",
74
+ "postpublish": "npm run clean",
83
75
  "test": "run-s test:*",
84
76
  "test:lint": "eslint",
85
77
  "test:tsc": "tsc",
@@ -93,5 +85,15 @@
93
85
  "clean:declarations-top": "rm -rf $(find . -maxdepth 1 -type f -name '*.d.ts*' -o -name '*.d.cts*' -o -name '*.d.mts*')",
94
86
  "clean:declarations-lib": "rm -rf $(find lib -type f \\( -name '*.d.ts*' -o -name '*.d.cts*' -o -name '*.d.mts*' \\) ! -name '*-types.d.ts')",
95
87
  "clean:declarations-bin": "rm -rf $(find bin -type f \\( -name '*.d.ts*' -o -name '*.d.cts*' -o -name '*.d.mts*' \\) ! -name '*-types.d.ts')"
88
+ },
89
+ "funding": {
90
+ "type": "individual",
91
+ "url": "https://github.com/sponsors/bcomnes"
92
+ },
93
+ "c8": {
94
+ "reporter": [
95
+ "lcov",
96
+ "text"
97
+ ]
96
98
  }
97
- }
99
+ }