homebridge-yoto 0.0.1 → 0.0.3

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/AGENTS.md ADDED
@@ -0,0 +1,253 @@
1
+ # Agent Development Notes
2
+
3
+ This document contains patterns, conventions, and guidelines for developing the homebridge-yoto plugin.
4
+
5
+ ## JSDoc Typing Patterns
6
+
7
+ ### Use TypeScript-in-JavaScript (ts-in-js)
8
+
9
+ All source files use `.js` extensions with JSDoc comments for type safety. This provides type checking without TypeScript compilation overhead.
10
+
11
+ ### Avoid `any` types
12
+
13
+ Always provide specific types. Use `unknown` when the type is truly unknown, then narrow it with type guards.
14
+
15
+ **Bad:**
16
+ ```javascript
17
+ /**
18
+ * @param {any} data
19
+ */
20
+ function processData(data) {
21
+ return data.value;
22
+ }
23
+ ```
24
+
25
+ **Good:**
26
+ ```javascript
27
+ /**
28
+ * @param {YotoDeviceStatus} status
29
+ * @returns {number}
30
+ */
31
+ function getBatteryLevel(status) {
32
+ return status.batteryLevelPercentage;
33
+ }
34
+ ```
35
+
36
+ ### Use @ts-expect-error over @ts-ignore
37
+
38
+ When you must suppress a TypeScript error, use `@ts-expect-error` with a comment explaining why. This will error if the issue is fixed, prompting cleanup.
39
+
40
+ **Bad:**
41
+ ```javascript
42
+ // @ts-ignore
43
+ const value = accessory.context.device.unknownProperty;
44
+ ```
45
+
46
+ **Good:**
47
+ ```javascript
48
+ // @ts-expect-error - API may return undefined for offline devices
49
+ const lastSeen = accessory.context.device.lastSeenAt;
50
+ ```
51
+
52
+ ### Use newer @import syntax in jsdoc/ts-in-js for types only
53
+
54
+ Import types using the `@import` JSDoc tag to avoid runtime imports of type-only dependencies.
55
+
56
+ ```javascript
57
+ /** @import { API, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service, Characteristic } from 'homebridge' */
58
+ /** @import { YotoDevice, YotoDeviceStatus, YotoDeviceConfig } from './types.js' */
59
+
60
+ /**
61
+ * @param {Logger} log
62
+ * @param {PlatformConfig} config
63
+ * @param {API} api
64
+ */
65
+ export function YotoPlatform(log, config, api) {
66
+ this.log = log;
67
+ this.config = config;
68
+ this.api = api;
69
+ }
70
+ ```
71
+
72
+ ### Import Consolidation
73
+
74
+ Keep regular imports and type imports separate. Use single-line imports for types when possible.
75
+
76
+ ```javascript
77
+ import { EventEmitter } from 'events';
78
+
79
+ /** @import { YotoDevice } from './types.js' */
80
+ /** @import { API, PlatformAccessory } from 'homebridge' */
81
+ ```
82
+
83
+ ### Homebridge Type Import Patterns
84
+
85
+ Homebridge types are available from the `homebridge` package:
86
+
87
+ ```javascript
88
+ /** @import { API, Characteristic, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service } from 'homebridge' */
89
+ /** @import { CharacteristicValue } from 'homebridge' */
90
+ ```
91
+
92
+ For HAP (HomeKit Accessory Protocol) types:
93
+
94
+ ```javascript
95
+ /** @import { HAPStatus } from 'homebridge' */
96
+
97
+ /**
98
+ * @throws {import('homebridge').HapStatusError}
99
+ */
100
+ function throwNotResponding() {
101
+ throw new this.api.hap.HapStatusError(this.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE);
102
+ }
103
+ ```
104
+
105
+ ### Prefer Schema-Based Types
106
+
107
+ Define types for API responses and configuration objects using JSDoc typedef.
108
+
109
+ ```javascript
110
+ /**
111
+ * @typedef {Object} YotoDeviceStatus
112
+ * @property {string} deviceId
113
+ * @property {number} batteryLevelPercentage
114
+ * @property {boolean} isCharging
115
+ * @property {boolean} isOnline
116
+ * @property {string | null} activeCard
117
+ * @property {number} userVolumePercentage
118
+ * @property {number} systemVolumePercentage
119
+ * @property {number} temperatureCelcius
120
+ * @property {number} wifiStrength
121
+ * @property {0 | 1 | 2} cardInsertionState - 0=none, 1=physical, 2=remote
122
+ * @property {-1 | 0 | 1} dayMode - -1=unknown, 0=night, 1=day
123
+ * @property {0 | 1 | 2 | 3} powerSource - 0=battery, 1=V2 dock, 2=USB-C, 3=Qi
124
+ */
125
+
126
+ /**
127
+ * @typedef {Object} YotoDevice
128
+ * @property {string} deviceId
129
+ * @property {string} name
130
+ * @property {string} description
131
+ * @property {boolean} online
132
+ * @property {string} releaseChannel
133
+ * @property {string} deviceType
134
+ * @property {string} deviceFamily
135
+ * @property {string} deviceGroup
136
+ */
137
+
138
+ /**
139
+ * @typedef {Object} YotoDeviceConfig
140
+ * @property {string} name
141
+ * @property {YotoDeviceConfigSettings} config
142
+ */
143
+
144
+ /**
145
+ * @typedef {Object} YotoDeviceConfigSettings
146
+ * @property {any[]} alarms
147
+ * @property {string} ambientColour
148
+ * @property {string} bluetoothEnabled
149
+ * @property {boolean} btHeadphonesEnabled
150
+ * @property {string} clockFace
151
+ * @property {string} dayDisplayBrightness
152
+ * @property {string} dayTime
153
+ * @property {string} maxVolumeLimit
154
+ * @property {string} nightAmbientColour
155
+ * @property {string} nightDisplayBrightness
156
+ * @property {string} nightMaxVolumeLimit
157
+ * @property {string} nightTime
158
+ * @property {boolean} repeatAll
159
+ * @property {string} shutdownTimeout
160
+ * @property {string} volumeLevel
161
+ */
162
+ ```
163
+
164
+ ### API Response Typing
165
+
166
+ Type API responses explicitly:
167
+
168
+ ```javascript
169
+ /**
170
+ * @typedef {Object} YotoApiDevicesResponse
171
+ * @property {YotoDevice[]} devices
172
+ */
173
+
174
+ /**
175
+ * Get all devices for authenticated user
176
+ * @returns {Promise<YotoDevice[]>}
177
+ */
178
+ async function getDevices() {
179
+ const response = await fetch('https://api.yotoplay.com/device-v2/devices/mine', {
180
+ headers: { 'Authorization': `Bearer ${this.accessToken}` }
181
+ });
182
+
183
+ /** @type {YotoApiDevicesResponse} */
184
+ const data = await response.json();
185
+ return data.devices;
186
+ }
187
+ ```
188
+
189
+ ### Platform Accessory Context Typing
190
+
191
+ Define the context object structure stored in accessories:
192
+
193
+ ```javascript
194
+ /**
195
+ * @typedef {Object} YotoAccessoryContext
196
+ * @property {YotoDevice} device
197
+ * @property {YotoDeviceStatus | null} lastStatus
198
+ * @property {number} lastUpdate
199
+ */
200
+
201
+ /**
202
+ * @param {PlatformAccessory<YotoAccessoryContext>} accessory
203
+ */
204
+ function configureAccessory(accessory) {
205
+ const device = accessory.context.device;
206
+ this.log.info('Restoring device:', device.name);
207
+ }
208
+ ```
209
+
210
+ ### Nullable Fields in API Responses
211
+
212
+ Use union types with `null` for fields that may be absent:
213
+
214
+ ```javascript
215
+ /**
216
+ * @typedef {Object} YotoCardContent
217
+ * @property {string} cardId
218
+ * @property {string} title
219
+ * @property {string | null} author
220
+ * @property {string | null} description
221
+ * @property {YotoChapter[] | null} chapters
222
+ */
223
+ ```
224
+
225
+ ### Optional vs Nullable
226
+
227
+ Distinguish between optional fields (may not exist) and nullable fields (exists but may be null):
228
+
229
+ ```javascript
230
+ /**
231
+ * @typedef {Object} YotoPlayerState
232
+ * @property {string} deviceId - Always present
233
+ * @property {string | null} activeCard - Present but may be null
234
+ * @property {string} [lastPlayedCard] - May not be present in response
235
+ */
236
+ ```
237
+
238
+ ## Changelog Management
239
+
240
+ **NEVER manually edit CHANGELOG.md**
241
+
242
+ The changelog is automatically generated using `auto-changelog` during the version bump process:
243
+
244
+ - When running `npm version [patch|minor|major]`, the `version:changelog` script runs automatically
245
+ - It uses the keepachangelog template
246
+ - Detects breaking changes via `BREAKING CHANGE:` pattern in commit messages
247
+ - Generates entries from git commits
248
+
249
+ To ensure proper changelog generation:
250
+ - Write meaningful git commit messages
251
+ - Use conventional commit format when possible
252
+ - Mark breaking changes with `BREAKING CHANGE:` in commit body
253
+ - Let the automation handle changelog updates during `npm version`