yoto-nodejs-client 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/README.md +523 -30
- package/bin/auth.js +36 -46
- package/bin/content.js +0 -0
- package/bin/device-model.d.ts +3 -0
- package/bin/device-model.d.ts.map +1 -0
- package/bin/device-model.js +360 -0
- package/bin/device-tui.TODO.md +125 -0
- package/bin/device-tui.d.ts +31 -0
- package/bin/device-tui.d.ts.map +1 -0
- package/bin/device-tui.js +1123 -0
- package/bin/devices.js +166 -28
- package/bin/groups.js +0 -0
- package/bin/icons.js +0 -0
- package/bin/lib/cli-helpers.d.ts +33 -1
- package/bin/lib/cli-helpers.d.ts.map +1 -1
- package/bin/lib/cli-helpers.js +5 -5
- package/bin/lib/token-helpers.d.ts +32 -0
- package/bin/lib/token-helpers.d.ts.map +1 -1
- package/bin/refresh-token.js +6 -6
- package/bin/token-info.js +3 -3
- package/index.d.ts +4 -217
- package/index.d.ts.map +1 -1
- package/index.js +11 -689
- package/lib/api-client.d.ts +576 -0
- package/lib/api-client.d.ts.map +1 -0
- package/lib/api-client.js +681 -0
- package/lib/api-endpoints/auth.d.ts +280 -4
- package/lib/api-endpoints/auth.d.ts.map +1 -1
- package/lib/api-endpoints/auth.js +224 -7
- package/lib/api-endpoints/auth.test.js +54 -2
- package/lib/api-endpoints/constants.d.ts +30 -2
- package/lib/api-endpoints/constants.d.ts.map +1 -1
- package/lib/api-endpoints/constants.js +17 -10
- package/lib/api-endpoints/content.d.ts +760 -0
- package/lib/api-endpoints/content.d.ts.map +1 -1
- package/lib/api-endpoints/content.test.js +1 -1
- package/lib/api-endpoints/devices.d.ts +917 -48
- package/lib/api-endpoints/devices.d.ts.map +1 -1
- package/lib/api-endpoints/devices.js +114 -52
- package/lib/api-endpoints/devices.test.js +1 -1
- package/lib/api-endpoints/endpoint-test-helpers.d.ts +28 -0
- package/lib/api-endpoints/endpoint-test-helpers.d.ts.map +1 -0
- package/lib/api-endpoints/family-library-groups.d.ts +187 -0
- package/lib/api-endpoints/family-library-groups.d.ts.map +1 -1
- package/lib/api-endpoints/family-library-groups.test.js +1 -1
- package/lib/api-endpoints/family.d.ts +88 -0
- package/lib/api-endpoints/family.d.ts.map +1 -1
- package/lib/api-endpoints/family.test.js +1 -1
- package/lib/api-endpoints/helpers.d.ts +37 -3
- package/lib/api-endpoints/helpers.d.ts.map +1 -1
- package/lib/api-endpoints/icons.d.ts +196 -0
- package/lib/api-endpoints/icons.d.ts.map +1 -1
- package/lib/api-endpoints/icons.test.js +1 -1
- package/lib/api-endpoints/media.d.ts +83 -0
- package/lib/api-endpoints/media.d.ts.map +1 -1
- package/lib/helpers/power-state.d.ts +53 -0
- package/lib/helpers/power-state.d.ts.map +1 -0
- package/lib/helpers/power-state.js +73 -0
- package/lib/helpers/power-state.test.js +100 -0
- package/lib/helpers/temperature.d.ts +24 -0
- package/lib/helpers/temperature.d.ts.map +1 -0
- package/lib/helpers/temperature.js +61 -0
- package/lib/helpers/temperature.test.js +58 -0
- package/lib/helpers/typed-keys.d.ts +7 -0
- package/lib/helpers/typed-keys.d.ts.map +1 -0
- package/lib/helpers/typed-keys.js +8 -0
- package/lib/mqtt/client.d.ts +610 -7
- package/lib/mqtt/client.d.ts.map +1 -1
- package/lib/mqtt/client.js +213 -31
- package/lib/mqtt/commands.d.ts +195 -0
- package/lib/mqtt/commands.d.ts.map +1 -1
- package/lib/mqtt/factory.d.ts +62 -1
- package/lib/mqtt/factory.d.ts.map +1 -1
- package/lib/mqtt/factory.js +27 -5
- package/lib/mqtt/mqtt.test.js +85 -28
- package/lib/mqtt/topics.d.ts +186 -1
- package/lib/mqtt/topics.d.ts.map +1 -1
- package/lib/mqtt/topics.js +54 -20
- package/lib/pkg.d.cts +9 -0
- package/lib/token.d.ts +106 -3
- package/lib/token.d.ts.map +1 -1
- package/lib/token.js +30 -23
- package/lib/yoto-account.d.ts +163 -0
- package/lib/yoto-account.d.ts.map +1 -0
- package/lib/yoto-account.js +340 -0
- package/lib/yoto-device.d.ts +656 -0
- package/lib/yoto-device.d.ts.map +1 -0
- package/lib/yoto-device.js +2850 -0
- package/package.json +22 -15
- package/lib/api-endpoints/test-helpers.d.ts +0 -7
- package/lib/api-endpoints/test-helpers.d.ts.map +0 -1
- /package/lib/api-endpoints/{test-helpers.js → endpoint-test-helpers.js} +0 -0
|
@@ -0,0 +1,681 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import { YotoContentResponse, YotoCreateOrUpdateContentRequest, YotoMyoContentResponse, YotoCreateOrUpdateContentResponse, YotoDeleteContentResponse } from './api-endpoints/content.js'
|
|
3
|
+
* @import { YotoDevicesResponse, YotoDeviceStatusResponse, YotoDeviceConfigResponse, YotoUpdateDeviceConfigRequest, YotoUpdateDeviceConfigResponse, YotoUpdateShortcutsRequest, YotoUpdateShortcutsResponse, YotoDeviceCommand, YotoDeviceCommandResponse } from './api-endpoints/devices.js'
|
|
4
|
+
* @import { YotoGroup, YotoCreateGroupRequest, YotoUpdateGroupRequest, YotoDeleteGroupResponse } from './api-endpoints/family-library-groups.js'
|
|
5
|
+
* @import { YotoFamilyImagesResponse, YotoFamilyImageResponse, YotoUploadFamilyImageResponse } from './api-endpoints/family.js'
|
|
6
|
+
* @import { YotoPublicIconsResponse, YotoUserIconsResponse, YotoUploadIconResponse } from './api-endpoints/icons.js'
|
|
7
|
+
* @import { YotoAudioUploadUrlResponse, YotoUploadCoverImageResponse, YotoCoverType } from './api-endpoints/media.js'
|
|
8
|
+
* @import { YotoTokenResponse, YotoDeviceCodeResponse, YotoDevicePollResult } from './api-endpoints/auth.js'
|
|
9
|
+
* @import { YotoMqttClient } from './mqtt/client.js'
|
|
10
|
+
* @import { MqttClientOptions, YotoMqttOptions } from './mqtt/factory.js'
|
|
11
|
+
* @import { RequestOptions } from './api-endpoints/helpers.js'
|
|
12
|
+
* @import { RefreshSuccessEvent } from './token.js'
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { RefreshableToken } from './token.js'
|
|
16
|
+
import * as Auth from './api-endpoints/auth.js'
|
|
17
|
+
import * as Content from './api-endpoints/content.js'
|
|
18
|
+
import * as Devices from './api-endpoints/devices.js'
|
|
19
|
+
import * as FamilyLibraryGroups from './api-endpoints/family-library-groups.js'
|
|
20
|
+
import * as Family from './api-endpoints/family.js'
|
|
21
|
+
import * as Icons from './api-endpoints/icons.js'
|
|
22
|
+
import * as Media from './api-endpoints/media.js'
|
|
23
|
+
import { createYotoMqttClient } from './mqtt/index.js'
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {Object} YotoClientConstructorOptions
|
|
27
|
+
* @property {string} clientId - OAuth client ID
|
|
28
|
+
* @property {string} refreshToken - OAuth refresh token
|
|
29
|
+
* @property {string} accessToken - Initial OAuth access token (JWT)
|
|
30
|
+
* @property {(refreshedTokenData: RefreshSuccessEvent) => void | Promise<void>} onTokenRefresh - **REQUIRED** Callback invoked when tokens are refreshed. You MUST persist these tokens (to file, database, etc.) as the refresh can happen at any time during API calls. The refresh token may be rotated by the auth server. **DO NOT STUB THIS CALLBACK** - always implement proper persistence logic.
|
|
31
|
+
* @property {number} [bufferSeconds=30] - Seconds before expiration to consider token expired
|
|
32
|
+
* @property {() => void | Promise<void>} [onRefreshStart] - Optional callback invoked when token refresh starts. Defaults to console.log.
|
|
33
|
+
* @property {(error: Error) => void | Promise<void>} [onRefreshError] - Optional callback invoked when token refresh fails with a transient error. Defaults to console.warn.
|
|
34
|
+
* @property {(error: Error) => void | Promise<void>} [onInvalid] - Optional callback invoked when refresh token is permanently invalid. Defaults to console.error.
|
|
35
|
+
* @property {string} [userAgent] - Optional user agent string to identify your application
|
|
36
|
+
* @property {RequestOptions} [defaultRequestOptions] - Default undici request options for all requests (dispatcher, timeouts, etc.)
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Yoto API Client with automatic token refresh
|
|
41
|
+
*/
|
|
42
|
+
export class YotoClient {
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// Authentication Static Methods
|
|
45
|
+
// ============================================================================
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get authorization URL for browser-based OAuth flow
|
|
49
|
+
* @see https://yoto.dev/api/get-authorize/
|
|
50
|
+
* @param {object} params
|
|
51
|
+
* @param {string} params.clientId - OAuth client ID
|
|
52
|
+
* @param {string} params.redirectUri - Redirect URI after authorization
|
|
53
|
+
* @param {'code' | 'token' | 'id_token' | 'code token' | 'code id_token' | 'token id_token' | 'code token id_token'} params.responseType - OAuth response type
|
|
54
|
+
* @param {string} params.state - State parameter for CSRF protection
|
|
55
|
+
* @param {string} [params.audience] - Audience for the token
|
|
56
|
+
* @param {string} [params.scope] - Requested scopes
|
|
57
|
+
* @param {string} [params.nonce] - Nonce for replay attack prevention
|
|
58
|
+
* @param {'none' | 'login' | 'consent' | 'select_account'} [params.prompt] - Authorization prompt behavior
|
|
59
|
+
* @param {number} [params.maxAge] - Maximum authentication age in seconds
|
|
60
|
+
* @param {string} [params.codeChallenge] - PKCE code challenge
|
|
61
|
+
* @param {'S256' | 'plain'} [params.codeChallengeMethod] - PKCE code challenge method
|
|
62
|
+
* @returns {string} Authorization URL
|
|
63
|
+
*/
|
|
64
|
+
static getAuthorizeUrl (params) {
|
|
65
|
+
return Auth.getAuthorizeUrl(params)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Exchange authorization code or refresh token for access tokens
|
|
70
|
+
* @see https://yoto.dev/api/post-oauth-token/
|
|
71
|
+
* @param {object} params
|
|
72
|
+
* @param {'authorization_code' | 'refresh_token' | 'client_credentials' | 'urn:ietf:params:oauth:grant-type:device_code'} params.grantType - OAuth grant type
|
|
73
|
+
* @param {string} [params.code] - Authorization code (required for authorization_code grant)
|
|
74
|
+
* @param {string} [params.redirectUri] - Redirect URI (required for authorization_code grant if used in authorize request)
|
|
75
|
+
* @param {string} [params.refreshToken] - Refresh token (required for refresh_token grant)
|
|
76
|
+
* @param {string} [params.clientId] - OAuth client ID
|
|
77
|
+
* @param {string} [params.clientSecret] - OAuth client secret
|
|
78
|
+
* @param {string} [params.scope] - Requested scope
|
|
79
|
+
* @param {string} [params.codeVerifier] - PKCE code verifier
|
|
80
|
+
* @param {string} [params.deviceCode] - Device code (required for device_code grant)
|
|
81
|
+
* @param {string} [params.audience] - Audience for the token
|
|
82
|
+
* @returns {Promise<YotoTokenResponse>}
|
|
83
|
+
*/
|
|
84
|
+
static async exchangeToken (params) {
|
|
85
|
+
return await Auth.exchangeToken(params)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Request device code for device authorization flow
|
|
90
|
+
* @see https://yoto.dev/api/post-oauth-device-code/
|
|
91
|
+
* @param {object} params
|
|
92
|
+
* @param {string} params.clientId - OAuth client ID
|
|
93
|
+
* @param {string} [params.scope] - Requested scopes
|
|
94
|
+
* @param {string} [params.audience] - Audience for the token
|
|
95
|
+
* @returns {Promise<YotoDeviceCodeResponse>}
|
|
96
|
+
*/
|
|
97
|
+
static async requestDeviceCode (params) {
|
|
98
|
+
return await Auth.requestDeviceCode(params)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Poll for device authorization completion with automatic error handling (single poll attempt).
|
|
103
|
+
* This function handles common polling errors (authorization_pending, slow_down)
|
|
104
|
+
* and only throws for unrecoverable errors (expired_token, access_denied, etc).
|
|
105
|
+
*
|
|
106
|
+
* Non-blocking - returns immediately with poll result. Suitable for:
|
|
107
|
+
* - Manual polling loops in CLI applications
|
|
108
|
+
* - Server-side endpoints that poll on behalf of clients (e.g., Homebridge UI server)
|
|
109
|
+
* - Custom UI implementations with specific polling behavior
|
|
110
|
+
*
|
|
111
|
+
* For the simplest approach (automatic polling loop), use waitForDeviceAuthorization() instead.
|
|
112
|
+
*
|
|
113
|
+
* @see https://yoto.dev/api/post-oauth-token/
|
|
114
|
+
* @param {object} params
|
|
115
|
+
* @param {string} params.deviceCode - Device code from requestDeviceCode()
|
|
116
|
+
* @param {string} params.clientId - OAuth client ID
|
|
117
|
+
* @param {string} [params.audience] - Audience for the token
|
|
118
|
+
* @param {number} [params.currentInterval=5000] - Current polling interval in milliseconds
|
|
119
|
+
* @param {string} [params.userAgent] - Optional user agent string
|
|
120
|
+
* @param {RequestOptions} [params.requestOptions] - Additional undici request options
|
|
121
|
+
* @returns {Promise<YotoDevicePollResult>} Poll result with status and data
|
|
122
|
+
* @throws {YotoAPIError} For unrecoverable errors (expired_token, access_denied, invalid_grant, etc)
|
|
123
|
+
*/
|
|
124
|
+
static async pollForDeviceToken (params) {
|
|
125
|
+
return await Auth.pollForDeviceToken(params)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Wait for device authorization to complete with automatic polling.
|
|
130
|
+
* This function wraps the entire polling loop - just call it and await the result.
|
|
131
|
+
* It handles all polling logic internally including interval adjustments.
|
|
132
|
+
*
|
|
133
|
+
* Designed for CLI usage where you want to block until authorization completes.
|
|
134
|
+
* For UI implementations with progress feedback, use pollForDeviceToken() directly.
|
|
135
|
+
*
|
|
136
|
+
* @see https://yoto.dev/api/post-oauth-token/
|
|
137
|
+
* @param {object} params
|
|
138
|
+
* @param {string} params.deviceCode - Device code from requestDeviceCode()
|
|
139
|
+
* @param {string} params.clientId - OAuth client ID
|
|
140
|
+
* @param {string} [params.audience] - Audience for the token
|
|
141
|
+
* @param {number} [params.initialInterval=5000] - Initial polling interval in milliseconds
|
|
142
|
+
* @param {number} [params.expiresIn] - Seconds until device code expires (for timeout calculation)
|
|
143
|
+
* @param {string} [params.userAgent] - Optional user agent string
|
|
144
|
+
* @param {RequestOptions} [params.requestOptions] - Additional undici request options
|
|
145
|
+
* @param {(result: YotoDevicePollResult) => void} [params.onPoll] - Optional callback invoked after each poll attempt
|
|
146
|
+
* @returns {Promise<YotoTokenResponse>} Token response on successful authorization
|
|
147
|
+
* @throws {YotoAPIError} For unrecoverable errors (expired_token, access_denied, invalid_grant, etc)
|
|
148
|
+
* @throws {Error} If device code expires (timeout)
|
|
149
|
+
*/
|
|
150
|
+
static async waitForDeviceAuthorization (params) {
|
|
151
|
+
return await Auth.waitForDeviceAuthorization(params)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ============================================================================
|
|
155
|
+
// Instance Properties and Constructor
|
|
156
|
+
// ============================================================================
|
|
157
|
+
/** @type {RefreshableToken} */
|
|
158
|
+
#token
|
|
159
|
+
|
|
160
|
+
/** @type {string | undefined} */
|
|
161
|
+
#userAgent
|
|
162
|
+
|
|
163
|
+
/** @type {RequestOptions | undefined} */
|
|
164
|
+
#defaultRequestOptions
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Create a new Yoto API client
|
|
168
|
+
* @param {YotoClientConstructorOptions} options
|
|
169
|
+
*/
|
|
170
|
+
constructor ({
|
|
171
|
+
clientId,
|
|
172
|
+
refreshToken,
|
|
173
|
+
accessToken,
|
|
174
|
+
onTokenRefresh,
|
|
175
|
+
bufferSeconds,
|
|
176
|
+
onRefreshStart,
|
|
177
|
+
onRefreshError,
|
|
178
|
+
onInvalid,
|
|
179
|
+
userAgent,
|
|
180
|
+
defaultRequestOptions
|
|
181
|
+
}) {
|
|
182
|
+
if (!onTokenRefresh) {
|
|
183
|
+
throw new Error('onTokenRefresh callback is required. You must persist refreshed tokens as they can be updated at any time.')
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
this.#token = new RefreshableToken({
|
|
187
|
+
clientId,
|
|
188
|
+
refreshToken,
|
|
189
|
+
accessToken,
|
|
190
|
+
...(bufferSeconds !== undefined && { bufferSeconds })
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
this.#userAgent = userAgent
|
|
194
|
+
this.#defaultRequestOptions = defaultRequestOptions
|
|
195
|
+
|
|
196
|
+
// Listen for token refresh events and call the user's callbacks
|
|
197
|
+
this.#token.on('refresh:success', onTokenRefresh)
|
|
198
|
+
|
|
199
|
+
this.#token.on('refresh:start', onRefreshStart || (() => {
|
|
200
|
+
console.log('Token refresh started')
|
|
201
|
+
}))
|
|
202
|
+
|
|
203
|
+
this.#token.on('refresh:error', onRefreshError || ((error) => {
|
|
204
|
+
console.warn('Token refresh failed (transient error):', error.message)
|
|
205
|
+
}))
|
|
206
|
+
|
|
207
|
+
this.#token.on('invalid', onInvalid || ((error) => {
|
|
208
|
+
console.error('Refresh token is permanently invalid:', error.message)
|
|
209
|
+
}))
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get the underlying RefreshableToken instance
|
|
214
|
+
* @returns {RefreshableToken}
|
|
215
|
+
*/
|
|
216
|
+
get token () {
|
|
217
|
+
return this.#token
|
|
218
|
+
}
|
|
219
|
+
// ============================================================================
|
|
220
|
+
// Content API
|
|
221
|
+
// ============================================================================
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Get content/card details
|
|
225
|
+
* @see https://yoto.dev/api/getcontent/
|
|
226
|
+
* @param {object} params
|
|
227
|
+
* @param {string} params.cardId - The card/content ID
|
|
228
|
+
* @param {string} [params.timezone] - Timezone for schedule-based content
|
|
229
|
+
* @param {'full' | 'pre'} [params.signingType] - Type of URL signing
|
|
230
|
+
* @param {boolean} [params.playable] - Whether to include playback URLs
|
|
231
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
232
|
+
* @returns {Promise<YotoContentResponse>}
|
|
233
|
+
*/
|
|
234
|
+
async getContent ({ cardId, timezone, signingType, playable, requestOptions }) {
|
|
235
|
+
const accessToken = await this.#token.getAccessToken()
|
|
236
|
+
return await Content.getContent({
|
|
237
|
+
accessToken,
|
|
238
|
+
userAgent: this.#userAgent,
|
|
239
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
240
|
+
cardId,
|
|
241
|
+
timezone,
|
|
242
|
+
signingType,
|
|
243
|
+
playable
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Get user's MYO (Make Your Own) content
|
|
249
|
+
* @see https://yoto.dev/api/getusersmyocontent/
|
|
250
|
+
* @param {object} [params]
|
|
251
|
+
* @param {boolean} [params.showDeleted=false] - Include deleted content
|
|
252
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
253
|
+
* @returns {Promise<YotoMyoContentResponse>}
|
|
254
|
+
*/
|
|
255
|
+
async getUserMyoContent ({ showDeleted = false, requestOptions } = {}) {
|
|
256
|
+
const accessToken = await this.#token.getAccessToken()
|
|
257
|
+
return await Content.getUserMyoContent({
|
|
258
|
+
accessToken,
|
|
259
|
+
userAgent: this.#userAgent,
|
|
260
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
261
|
+
showDeleted
|
|
262
|
+
})
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Create or update content/card
|
|
267
|
+
* @see https://yoto.dev/api/createorupdatecontent/
|
|
268
|
+
* @param {object} params
|
|
269
|
+
* @param {YotoCreateOrUpdateContentRequest} params.content - Content data to create/update
|
|
270
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
271
|
+
* @returns {Promise<YotoCreateOrUpdateContentResponse>}
|
|
272
|
+
*/
|
|
273
|
+
async createOrUpdateContent ({ content, requestOptions }) {
|
|
274
|
+
const accessToken = await this.#token.getAccessToken()
|
|
275
|
+
return await Content.createOrUpdateContent({
|
|
276
|
+
accessToken,
|
|
277
|
+
userAgent: this.#userAgent,
|
|
278
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
279
|
+
content
|
|
280
|
+
})
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Delete content/card
|
|
285
|
+
* @see https://yoto.dev/api/deletecontent/
|
|
286
|
+
* @param {object} params
|
|
287
|
+
* @param {string} params.cardId - The card/content ID to delete
|
|
288
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
289
|
+
* @returns {Promise<YotoDeleteContentResponse>}
|
|
290
|
+
*/
|
|
291
|
+
async deleteContent ({ cardId, requestOptions }) {
|
|
292
|
+
const accessToken = await this.#token.getAccessToken()
|
|
293
|
+
return await Content.deleteContent({
|
|
294
|
+
accessToken,
|
|
295
|
+
userAgent: this.#userAgent,
|
|
296
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
297
|
+
cardId
|
|
298
|
+
})
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ============================================================================
|
|
302
|
+
// Devices API
|
|
303
|
+
// ============================================================================
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Get all devices for authenticated user
|
|
307
|
+
* @see https://yoto.dev/api/getdevices/
|
|
308
|
+
* @param {object} [params]
|
|
309
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
310
|
+
* @returns {Promise<YotoDevicesResponse>}
|
|
311
|
+
*/
|
|
312
|
+
async getDevices ({ requestOptions } = {}) {
|
|
313
|
+
const accessToken = await this.#token.getAccessToken()
|
|
314
|
+
return await Devices.getDevices({ accessToken, userAgent: this.#userAgent, requestOptions: requestOptions || this.#defaultRequestOptions })
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Get device status
|
|
319
|
+
* @see https://yoto.dev/api/getdevicestatus/
|
|
320
|
+
* @param {object} params
|
|
321
|
+
* @param {string} params.deviceId - Device ID
|
|
322
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
323
|
+
* @returns {Promise<YotoDeviceStatusResponse>}
|
|
324
|
+
*/
|
|
325
|
+
async getDeviceStatus ({ deviceId, requestOptions }) {
|
|
326
|
+
const accessToken = await this.#token.getAccessToken()
|
|
327
|
+
return await Devices.getDeviceStatus({
|
|
328
|
+
accessToken,
|
|
329
|
+
userAgent: this.#userAgent,
|
|
330
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
331
|
+
deviceId
|
|
332
|
+
})
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Get device configuration
|
|
337
|
+
* @see https://yoto.dev/api/getdeviceconfig/
|
|
338
|
+
* @param {object} params
|
|
339
|
+
* @param {string} params.deviceId - Device ID
|
|
340
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
341
|
+
* @returns {Promise<YotoDeviceConfigResponse>}
|
|
342
|
+
*/
|
|
343
|
+
async getDeviceConfig ({ deviceId, requestOptions }) {
|
|
344
|
+
const accessToken = await this.#token.getAccessToken()
|
|
345
|
+
return await Devices.getDeviceConfig({
|
|
346
|
+
accessToken,
|
|
347
|
+
userAgent: this.#userAgent,
|
|
348
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
349
|
+
deviceId
|
|
350
|
+
})
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Update device configuration
|
|
355
|
+
* @see https://yoto.dev/api/updatedeviceconfig/
|
|
356
|
+
* @param {object} params
|
|
357
|
+
* @param {string} params.deviceId - Device ID
|
|
358
|
+
* @param {YotoUpdateDeviceConfigRequest} params.configUpdate - Config updates
|
|
359
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
360
|
+
* @returns {Promise<YotoUpdateDeviceConfigResponse>}
|
|
361
|
+
*/
|
|
362
|
+
async updateDeviceConfig ({ deviceId, configUpdate, requestOptions }) {
|
|
363
|
+
const accessToken = await this.#token.getAccessToken()
|
|
364
|
+
return await Devices.updateDeviceConfig({
|
|
365
|
+
accessToken,
|
|
366
|
+
userAgent: this.#userAgent,
|
|
367
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
368
|
+
deviceId,
|
|
369
|
+
configUpdate
|
|
370
|
+
})
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Update device shortcuts
|
|
375
|
+
* @see https://yoto.dev/api/updateshortcutsbeta/
|
|
376
|
+
* @param {object} params
|
|
377
|
+
* @param {string} params.deviceId - Device ID
|
|
378
|
+
* @param {YotoUpdateShortcutsRequest} params.shortcutsUpdate - Shortcuts config
|
|
379
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
380
|
+
* @returns {Promise<YotoUpdateShortcutsResponse>}
|
|
381
|
+
*/
|
|
382
|
+
async updateDeviceShortcuts ({ deviceId, shortcutsUpdate, requestOptions }) {
|
|
383
|
+
const accessToken = await this.#token.getAccessToken()
|
|
384
|
+
return await Devices.updateDeviceShortcuts({
|
|
385
|
+
accessToken,
|
|
386
|
+
userAgent: this.#userAgent,
|
|
387
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
388
|
+
deviceId,
|
|
389
|
+
shortcutsUpdate
|
|
390
|
+
})
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Send command to device
|
|
395
|
+
* @see https://yoto.dev/api/senddevicecommand/
|
|
396
|
+
* @see https://yoto.dev/players-mqtt/mqtt-docs/
|
|
397
|
+
* @param {object} params
|
|
398
|
+
* @param {string} params.deviceId - Device ID
|
|
399
|
+
* @param {YotoDeviceCommand} params.command - Command to send
|
|
400
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
401
|
+
* @returns {Promise<YotoDeviceCommandResponse>}
|
|
402
|
+
*/
|
|
403
|
+
async sendDeviceCommand ({ deviceId, command, requestOptions }) {
|
|
404
|
+
const accessToken = await this.#token.getAccessToken()
|
|
405
|
+
return await Devices.sendDeviceCommand({
|
|
406
|
+
accessToken,
|
|
407
|
+
userAgent: this.#userAgent,
|
|
408
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
409
|
+
deviceId,
|
|
410
|
+
command
|
|
411
|
+
})
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// ============================================================================
|
|
415
|
+
// Family Library Groups API
|
|
416
|
+
// ============================================================================
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Get all family library groups
|
|
420
|
+
* @see https://yoto.dev/api/getgroups/
|
|
421
|
+
* @param {object} [params]
|
|
422
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
423
|
+
* @returns {Promise<YotoGroup[]>}
|
|
424
|
+
*/
|
|
425
|
+
async getGroups ({ requestOptions } = {}) {
|
|
426
|
+
const accessToken = await this.#token.getAccessToken()
|
|
427
|
+
return await FamilyLibraryGroups.getGroups({ accessToken, userAgent: this.#userAgent, requestOptions: requestOptions || this.#defaultRequestOptions })
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Create a family library group
|
|
432
|
+
* @see https://yoto.dev/api/createagroup/
|
|
433
|
+
* @param {object} params
|
|
434
|
+
* @param {YotoCreateGroupRequest} params.group - Group data
|
|
435
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
436
|
+
* @returns {Promise<YotoGroup>}
|
|
437
|
+
*/
|
|
438
|
+
async createGroup ({ group, requestOptions }) {
|
|
439
|
+
const accessToken = await this.#token.getAccessToken()
|
|
440
|
+
return await FamilyLibraryGroups.createGroup({
|
|
441
|
+
token: accessToken,
|
|
442
|
+
userAgent: this.#userAgent,
|
|
443
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
444
|
+
group
|
|
445
|
+
})
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Get a specific family library group
|
|
450
|
+
* @see https://yoto.dev/api/getgroup/
|
|
451
|
+
* @param {object} params
|
|
452
|
+
* @param {string} params.groupId - Group ID
|
|
453
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
454
|
+
* @returns {Promise<YotoGroup>}
|
|
455
|
+
*/
|
|
456
|
+
async getGroup ({ groupId, requestOptions }) {
|
|
457
|
+
const accessToken = await this.#token.getAccessToken()
|
|
458
|
+
return await FamilyLibraryGroups.getGroup({
|
|
459
|
+
accessToken,
|
|
460
|
+
userAgent: this.#userAgent,
|
|
461
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
462
|
+
groupId
|
|
463
|
+
})
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Update a family library group
|
|
468
|
+
* @see https://yoto.dev/api/updateagroup/
|
|
469
|
+
* @param {object} params
|
|
470
|
+
* @param {string} params.groupId - Group ID
|
|
471
|
+
* @param {YotoUpdateGroupRequest} params.group - Updated group data
|
|
472
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
473
|
+
* @returns {Promise<YotoGroup>}
|
|
474
|
+
*/
|
|
475
|
+
async updateGroup ({ groupId, group, requestOptions }) {
|
|
476
|
+
const accessToken = await this.#token.getAccessToken()
|
|
477
|
+
return await FamilyLibraryGroups.updateGroup({
|
|
478
|
+
accessToken,
|
|
479
|
+
userAgent: this.#userAgent,
|
|
480
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
481
|
+
groupId,
|
|
482
|
+
group
|
|
483
|
+
})
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Delete a family library group
|
|
488
|
+
* @see https://yoto.dev/api/deleteagroup/
|
|
489
|
+
* @param {object} params
|
|
490
|
+
* @param {string} params.groupId - Group ID
|
|
491
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
492
|
+
* @returns {Promise<YotoDeleteGroupResponse>}
|
|
493
|
+
*/
|
|
494
|
+
async deleteGroup ({ groupId, requestOptions }) {
|
|
495
|
+
const accessToken = await this.#token.getAccessToken()
|
|
496
|
+
return await FamilyLibraryGroups.deleteGroup({
|
|
497
|
+
accessToken,
|
|
498
|
+
userAgent: this.#userAgent,
|
|
499
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
500
|
+
groupId
|
|
501
|
+
})
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// ============================================================================
|
|
505
|
+
// Family Images API
|
|
506
|
+
// ============================================================================
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Get all family images
|
|
510
|
+
* @see https://yoto.dev/api/getfamilyimages/
|
|
511
|
+
* @param {object} [params]
|
|
512
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
513
|
+
* @returns {Promise<YotoFamilyImagesResponse>}
|
|
514
|
+
*/
|
|
515
|
+
async getFamilyImages ({ requestOptions } = {}) {
|
|
516
|
+
const accessToken = await this.#token.getAccessToken()
|
|
517
|
+
return await Family.getFamilyImages({ accessToken, userAgent: this.#userAgent, requestOptions: requestOptions || this.#defaultRequestOptions })
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Get a specific family image
|
|
522
|
+
* @see https://yoto.dev/api/getafamilyimage/
|
|
523
|
+
* @param {object} params
|
|
524
|
+
* @param {string} params.imageId - Image ID
|
|
525
|
+
* @param {'640x480' | '320x320'} params.size - Image size
|
|
526
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
527
|
+
* @returns {Promise<YotoFamilyImageResponse>}
|
|
528
|
+
*/
|
|
529
|
+
async getAFamilyImage ({ imageId, size, requestOptions }) {
|
|
530
|
+
const accessToken = await this.#token.getAccessToken()
|
|
531
|
+
return await Family.getAFamilyImage({
|
|
532
|
+
accessToken,
|
|
533
|
+
userAgent: this.#userAgent,
|
|
534
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
535
|
+
imageId,
|
|
536
|
+
size
|
|
537
|
+
})
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Upload a family image
|
|
542
|
+
* @see https://yoto.dev/api/uploadafamilyimage/
|
|
543
|
+
* @param {object} params
|
|
544
|
+
* @param {Buffer} params.imageData - Image binary data
|
|
545
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
546
|
+
* @returns {Promise<YotoUploadFamilyImageResponse>}
|
|
547
|
+
*/
|
|
548
|
+
async uploadAFamilyImage ({ imageData, requestOptions }) {
|
|
549
|
+
const accessToken = await this.#token.getAccessToken()
|
|
550
|
+
return await Family.uploadAFamilyImage({
|
|
551
|
+
accessToken,
|
|
552
|
+
userAgent: this.#userAgent,
|
|
553
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
554
|
+
imageData
|
|
555
|
+
})
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// ============================================================================
|
|
559
|
+
// Icons API
|
|
560
|
+
// ============================================================================
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Get public Yoto icons
|
|
564
|
+
* @see https://yoto.dev/api/getpublicicons/
|
|
565
|
+
* @param {object} [params]
|
|
566
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
567
|
+
* @returns {Promise<YotoPublicIconsResponse>}
|
|
568
|
+
*/
|
|
569
|
+
async getPublicIcons ({ requestOptions } = {}) {
|
|
570
|
+
const accessToken = await this.#token.getAccessToken()
|
|
571
|
+
return await Icons.getPublicIcons({ accessToken, userAgent: this.#userAgent, requestOptions: requestOptions || this.#defaultRequestOptions })
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Get user's custom icons
|
|
576
|
+
* @see https://yoto.dev/api/getusericons/
|
|
577
|
+
* @param {object} [params]
|
|
578
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
579
|
+
* @returns {Promise<YotoUserIconsResponse>}
|
|
580
|
+
*/
|
|
581
|
+
async getUserIcons ({ requestOptions } = {}) {
|
|
582
|
+
const accessToken = await this.#token.getAccessToken()
|
|
583
|
+
return await Icons.getUserIcons({ accessToken, userAgent: this.#userAgent, requestOptions: requestOptions || this.#defaultRequestOptions })
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Upload a custom icon
|
|
588
|
+
* @see https://yoto.dev/api/uploadicon/
|
|
589
|
+
* @param {object} params
|
|
590
|
+
* @param {Buffer} params.imageData - Image binary data
|
|
591
|
+
* @param {boolean} [params.autoConvert=true] - Auto-convert to proper format
|
|
592
|
+
* @param {string} [params.filename] - Optional filename
|
|
593
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
594
|
+
* @returns {Promise<YotoUploadIconResponse>}
|
|
595
|
+
*/
|
|
596
|
+
async uploadIcon ({ imageData, autoConvert = true, filename, requestOptions }) {
|
|
597
|
+
const accessToken = await this.#token.getAccessToken()
|
|
598
|
+
return await Icons.uploadIcon({
|
|
599
|
+
accessToken,
|
|
600
|
+
userAgent: this.#userAgent,
|
|
601
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
602
|
+
imageData,
|
|
603
|
+
autoConvert,
|
|
604
|
+
filename
|
|
605
|
+
})
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// ============================================================================
|
|
609
|
+
// Media API
|
|
610
|
+
// ============================================================================
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Get audio upload URL
|
|
614
|
+
* @see https://yoto.dev/api/getaudiouploadurl/
|
|
615
|
+
* @param {object} params
|
|
616
|
+
* @param {string} params.sha256 - SHA256 hash of audio file
|
|
617
|
+
* @param {string} [params.filename] - Optional filename
|
|
618
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
619
|
+
* @returns {Promise<YotoAudioUploadUrlResponse>}
|
|
620
|
+
*/
|
|
621
|
+
async getAudioUploadUrl ({ sha256, filename, requestOptions }) {
|
|
622
|
+
const accessToken = await this.#token.getAccessToken()
|
|
623
|
+
return await Media.getAudioUploadUrl({
|
|
624
|
+
accessToken,
|
|
625
|
+
userAgent: this.#userAgent,
|
|
626
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
627
|
+
sha256,
|
|
628
|
+
filename
|
|
629
|
+
})
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Upload a cover image
|
|
634
|
+
* @see https://yoto.dev/api/uploadcoverimage/
|
|
635
|
+
* @param {object} params
|
|
636
|
+
* @param {Buffer} [params.imageData] - Image binary data
|
|
637
|
+
* @param {string} [params.imageUrl] - URL to image
|
|
638
|
+
* @param {boolean} [params.autoConvert] - Auto-convert to proper format
|
|
639
|
+
* @param {YotoCoverType} [params.coverType] - Cover image type
|
|
640
|
+
* @param {string} [params.filename] - Optional filename
|
|
641
|
+
* @param {RequestOptions} [params.requestOptions] - Request options that override defaults
|
|
642
|
+
* @returns {Promise<YotoUploadCoverImageResponse>}
|
|
643
|
+
*/
|
|
644
|
+
async uploadCoverImage ({ imageData, imageUrl, autoConvert, coverType, filename, requestOptions }) {
|
|
645
|
+
const accessToken = await this.#token.getAccessToken()
|
|
646
|
+
return await Media.uploadCoverImage({
|
|
647
|
+
accessToken,
|
|
648
|
+
userAgent: this.#userAgent,
|
|
649
|
+
requestOptions: requestOptions || this.#defaultRequestOptions,
|
|
650
|
+
imageData,
|
|
651
|
+
imageUrl,
|
|
652
|
+
autoConvert,
|
|
653
|
+
coverType,
|
|
654
|
+
filename
|
|
655
|
+
})
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// ============================================================================
|
|
659
|
+
// MQTT Client
|
|
660
|
+
// ============================================================================
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Create an MQTT client for a device
|
|
664
|
+
* @param {Object} params
|
|
665
|
+
* @param {string} params.deviceId - Device ID to connect to
|
|
666
|
+
* @param {MqttClientOptions} [params.mqttOptions] - MQTT.js client options (excluding deviceId and accessToken which are provided automatically)
|
|
667
|
+
* @returns {Promise<YotoMqttClient>}
|
|
668
|
+
*/
|
|
669
|
+
async createMqttClient ({ deviceId, mqttOptions }) {
|
|
670
|
+
const accessToken = await this.#token.getAccessToken()
|
|
671
|
+
|
|
672
|
+
/** @type {YotoMqttOptions} */
|
|
673
|
+
const opts = {
|
|
674
|
+
deviceId,
|
|
675
|
+
accessToken,
|
|
676
|
+
...mqttOptions
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
return createYotoMqttClient(opts)
|
|
680
|
+
}
|
|
681
|
+
}
|