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.
Files changed (92) hide show
  1. package/README.md +523 -30
  2. package/bin/auth.js +36 -46
  3. package/bin/content.js +0 -0
  4. package/bin/device-model.d.ts +3 -0
  5. package/bin/device-model.d.ts.map +1 -0
  6. package/bin/device-model.js +360 -0
  7. package/bin/device-tui.TODO.md +125 -0
  8. package/bin/device-tui.d.ts +31 -0
  9. package/bin/device-tui.d.ts.map +1 -0
  10. package/bin/device-tui.js +1123 -0
  11. package/bin/devices.js +166 -28
  12. package/bin/groups.js +0 -0
  13. package/bin/icons.js +0 -0
  14. package/bin/lib/cli-helpers.d.ts +33 -1
  15. package/bin/lib/cli-helpers.d.ts.map +1 -1
  16. package/bin/lib/cli-helpers.js +5 -5
  17. package/bin/lib/token-helpers.d.ts +32 -0
  18. package/bin/lib/token-helpers.d.ts.map +1 -1
  19. package/bin/refresh-token.js +6 -6
  20. package/bin/token-info.js +3 -3
  21. package/index.d.ts +4 -217
  22. package/index.d.ts.map +1 -1
  23. package/index.js +11 -689
  24. package/lib/api-client.d.ts +576 -0
  25. package/lib/api-client.d.ts.map +1 -0
  26. package/lib/api-client.js +681 -0
  27. package/lib/api-endpoints/auth.d.ts +280 -4
  28. package/lib/api-endpoints/auth.d.ts.map +1 -1
  29. package/lib/api-endpoints/auth.js +224 -7
  30. package/lib/api-endpoints/auth.test.js +54 -2
  31. package/lib/api-endpoints/constants.d.ts +30 -2
  32. package/lib/api-endpoints/constants.d.ts.map +1 -1
  33. package/lib/api-endpoints/constants.js +17 -10
  34. package/lib/api-endpoints/content.d.ts +760 -0
  35. package/lib/api-endpoints/content.d.ts.map +1 -1
  36. package/lib/api-endpoints/content.test.js +1 -1
  37. package/lib/api-endpoints/devices.d.ts +917 -48
  38. package/lib/api-endpoints/devices.d.ts.map +1 -1
  39. package/lib/api-endpoints/devices.js +114 -52
  40. package/lib/api-endpoints/devices.test.js +1 -1
  41. package/lib/api-endpoints/endpoint-test-helpers.d.ts +28 -0
  42. package/lib/api-endpoints/endpoint-test-helpers.d.ts.map +1 -0
  43. package/lib/api-endpoints/family-library-groups.d.ts +187 -0
  44. package/lib/api-endpoints/family-library-groups.d.ts.map +1 -1
  45. package/lib/api-endpoints/family-library-groups.test.js +1 -1
  46. package/lib/api-endpoints/family.d.ts +88 -0
  47. package/lib/api-endpoints/family.d.ts.map +1 -1
  48. package/lib/api-endpoints/family.test.js +1 -1
  49. package/lib/api-endpoints/helpers.d.ts +37 -3
  50. package/lib/api-endpoints/helpers.d.ts.map +1 -1
  51. package/lib/api-endpoints/icons.d.ts +196 -0
  52. package/lib/api-endpoints/icons.d.ts.map +1 -1
  53. package/lib/api-endpoints/icons.test.js +1 -1
  54. package/lib/api-endpoints/media.d.ts +83 -0
  55. package/lib/api-endpoints/media.d.ts.map +1 -1
  56. package/lib/helpers/power-state.d.ts +53 -0
  57. package/lib/helpers/power-state.d.ts.map +1 -0
  58. package/lib/helpers/power-state.js +73 -0
  59. package/lib/helpers/power-state.test.js +100 -0
  60. package/lib/helpers/temperature.d.ts +24 -0
  61. package/lib/helpers/temperature.d.ts.map +1 -0
  62. package/lib/helpers/temperature.js +61 -0
  63. package/lib/helpers/temperature.test.js +58 -0
  64. package/lib/helpers/typed-keys.d.ts +7 -0
  65. package/lib/helpers/typed-keys.d.ts.map +1 -0
  66. package/lib/helpers/typed-keys.js +8 -0
  67. package/lib/mqtt/client.d.ts +610 -7
  68. package/lib/mqtt/client.d.ts.map +1 -1
  69. package/lib/mqtt/client.js +213 -31
  70. package/lib/mqtt/commands.d.ts +195 -0
  71. package/lib/mqtt/commands.d.ts.map +1 -1
  72. package/lib/mqtt/factory.d.ts +62 -1
  73. package/lib/mqtt/factory.d.ts.map +1 -1
  74. package/lib/mqtt/factory.js +27 -5
  75. package/lib/mqtt/mqtt.test.js +85 -28
  76. package/lib/mqtt/topics.d.ts +186 -1
  77. package/lib/mqtt/topics.d.ts.map +1 -1
  78. package/lib/mqtt/topics.js +54 -20
  79. package/lib/pkg.d.cts +9 -0
  80. package/lib/token.d.ts +106 -3
  81. package/lib/token.d.ts.map +1 -1
  82. package/lib/token.js +30 -23
  83. package/lib/yoto-account.d.ts +163 -0
  84. package/lib/yoto-account.d.ts.map +1 -0
  85. package/lib/yoto-account.js +340 -0
  86. package/lib/yoto-device.d.ts +656 -0
  87. package/lib/yoto-device.d.ts.map +1 -0
  88. package/lib/yoto-device.js +2850 -0
  89. package/package.json +22 -15
  90. package/lib/api-endpoints/test-helpers.d.ts +0 -7
  91. package/lib/api-endpoints/test-helpers.d.ts.map +0 -1
  92. /package/lib/api-endpoints/{test-helpers.js → endpoint-test-helpers.js} +0 -0
@@ -1,3 +1,23 @@
1
+ /**
2
+ * @see https://yoto.dev/api/getfamilyimages/
3
+ * @typedef {Object} YotoFamilyImagesResponse
4
+ * @property {YotoFamilyImage[]} images
5
+ */
6
+ /**
7
+ * @see https://yoto.dev/api/getfamilyimages/
8
+ * @typedef {Object} YotoFamilyImage
9
+ * @property {string} imageId - The unique identifier for the family image (hash)
10
+ * @property {string} [name] - Optional name of the family image
11
+ */
12
+ /**
13
+ * Retrieves the list of families associated with the authenticated user.
14
+ * @see https://yoto.dev/api/getfamilyimages/
15
+ * @param {object} options
16
+ * @param {string} options.accessToken The API token to request with
17
+ * @param {string} [options.userAgent] Optional user agent string
18
+ * @param {RequestOptions} [options.requestOptions] Additional undici request options
19
+ * @return {Promise<YotoFamilyImagesResponse>} The user's families
20
+ */
1
21
  export function getFamilyImages({ accessToken, userAgent, requestOptions }: {
2
22
  accessToken: string;
3
23
  userAgent?: string | undefined;
@@ -5,6 +25,23 @@ export function getFamilyImages({ accessToken, userAgent, requestOptions }: {
5
25
  dispatcher?: import("undici").Dispatcher;
6
26
  } & Omit<import("undici").Dispatcher.RequestOptions<unknown>, "origin" | "path" | "method"> & Partial<Pick<import("undici").Dispatcher.RequestOptions<null>, "method">>) | undefined;
7
27
  }): Promise<YotoFamilyImagesResponse>;
28
+ /**
29
+ * @see https://yoto.dev/api/getafamilyimage/
30
+ * @typedef {Object} YotoFamilyImageResponse
31
+ * @property {string} imageUrl - The signed URL to the family image (expires after 7 days)
32
+ */
33
+ /**
34
+ * Retrieves a signed URL for a specific family image. Returns a 302 redirect with the image URL in the Location header.
35
+ * The signed URL expires after 7 days.
36
+ * @see https://yoto.dev/api/getafamilyimage/
37
+ * @param {object} options
38
+ * @param {string} options.accessToken The API token to request with
39
+ * @param {string} options.imageId The family image ID (hash) to get the image for
40
+ * @param {'640x480' | '320x320'} options.size Image dimensions (supported: '640x480' or '320x320')
41
+ * @param {string} [options.userAgent] Optional user agent string
42
+ * @param {RequestOptions} [options.requestOptions] Additional undici request options
43
+ * @return {Promise<YotoFamilyImageResponse>} The signed image URL
44
+ */
8
45
  export function getAFamilyImage({ accessToken, userAgent, imageId, size, requestOptions }: {
9
46
  accessToken: string;
10
47
  imageId: string;
@@ -14,6 +51,42 @@ export function getAFamilyImage({ accessToken, userAgent, imageId, size, request
14
51
  dispatcher?: import("undici").Dispatcher;
15
52
  } & Omit<import("undici").Dispatcher.RequestOptions<unknown>, "origin" | "path" | "method"> & Partial<Pick<import("undici").Dispatcher.RequestOptions<null>, "method">>) | undefined;
16
53
  }): Promise<YotoFamilyImageResponse>;
54
+ /**
55
+ * @see https://yoto.dev/api/uploadafamilyimage/
56
+ * @typedef {Object} YotoUploadFamilyImageResponse
57
+ * @property {string} imageId - The SHA256 checksum of the uploaded image
58
+ * @property {string} url - URL to the 'get a family image' endpoint (requires width/height params)
59
+ */
60
+ /**
61
+ * Uploads a family image for use across various features in Yoto.
62
+ * Images are deduplicated using SHA256 checksums.
63
+ *
64
+ * Constraints:
65
+ * - Max size: 8mb
66
+ * - Supported formats: JPEG, GIF, PNG
67
+ * - Limit: 500 images per family
68
+ * - No restrictions on resolution or aspect ratio
69
+ *
70
+ * @see https://yoto.dev/api/uploadafamilyimage/
71
+ * @param {object} options
72
+ * @param {string} options.accessToken The API token to request with
73
+ * @param {Buffer} options.imageData The binary image data (JPEG, GIF, or PNG)
74
+ * @param {string} [options.userAgent] Optional user agent string
75
+ * @param {RequestOptions} [options.requestOptions] Additional undici request options
76
+ * @return {Promise<YotoUploadFamilyImageResponse>} The uploaded image details
77
+ * @example
78
+ * import { readFile } from 'fs/promises'
79
+ * import { uploadAFamilyImage } from 'yoto-nodejs-client'
80
+ *
81
+ * const imageData = await readFile('./family-photo.jpg')
82
+ * const result = await uploadAFamilyImage({
83
+ * accessToken,
84
+ * imageData
85
+ * })
86
+ *
87
+ * console.log('Image ID:', result.imageId)
88
+ * console.log('Image URL:', result.url)
89
+ */
17
90
  export function uploadAFamilyImage({ accessToken, userAgent, imageData, requestOptions }: {
18
91
  accessToken: string;
19
92
  imageData: Buffer;
@@ -26,14 +99,29 @@ export type YotoFamilyImagesResponse = {
26
99
  images: YotoFamilyImage[];
27
100
  };
28
101
  export type YotoFamilyImage = {
102
+ /**
103
+ * - The unique identifier for the family image (hash)
104
+ */
29
105
  imageId: string;
106
+ /**
107
+ * - Optional name of the family image
108
+ */
30
109
  name?: string;
31
110
  };
32
111
  export type YotoFamilyImageResponse = {
112
+ /**
113
+ * - The signed URL to the family image (expires after 7 days)
114
+ */
33
115
  imageUrl: string;
34
116
  };
35
117
  export type YotoUploadFamilyImageResponse = {
118
+ /**
119
+ * - The SHA256 checksum of the uploaded image
120
+ */
36
121
  imageId: string;
122
+ /**
123
+ * - URL to the 'get a family image' endpoint (requires width/height params)
124
+ */
37
125
  url: string;
38
126
  };
39
127
  //# sourceMappingURL=family.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"family.d.ts","sourceRoot":"","sources":["family.js"],"names":[],"mappings":"AAiCA,4EALG;IAAyB,WAAW,EAA3B,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,wBAAwB,CAAC,CAkB5C;AAoBD,2FAPG;IAAyB,WAAW,EAA3B,MAAM;IACU,OAAO,EAAvB,MAAM;IACyB,IAAI,EAAnC,SAAS,GAAG,SAAS;IACJ,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,uBAAuB,CAAC,CAsC3C;AAuCD,0FAlBG;IAAyB,WAAW,EAA3B,MAAM;IACU,SAAS,EAAzB,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,6BAA6B,CAAC,CAmCjD;;YAvJa,eAAe,EAAE;;;aAMjB,MAAM;WACN,MAAM;;;cAiCN,MAAM;;;aAwDN,MAAM;SACN,MAAM"}
1
+ {"version":3,"file":"family.d.ts","sourceRoot":"","sources":["family.js"],"names":[],"mappings":"AAWA;;;;GAIG;AAEH;;;;;GAKG;AAEH;;;;;;;;GAQG;AACH,4EALG;IAAyB,WAAW,EAA3B,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,wBAAwB,CAAC,CAkB5C;AAED;;;;GAIG;AAEH;;;;;;;;;;;GAWG;AACH,2FAPG;IAAyB,WAAW,EAA3B,MAAM;IACU,OAAO,EAAvB,MAAM;IACyB,IAAI,EAAnC,SAAS,GAAG,SAAS;IACJ,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,uBAAuB,CAAC,CAsC3C;AAED;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,0FAlBG;IAAyB,WAAW,EAA3B,MAAM;IACU,SAAS,EAAzB,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,6BAA6B,CAAC,CAmCjD;;YAvJa,eAAe,EAAE;;;;;;aAMjB,MAAM;;;;WACN,MAAM;;;;;;cAiCN,MAAM;;;;;;aAwDN,MAAM;;;;SACN,MAAM"}
@@ -2,7 +2,7 @@ import test from 'node:test'
2
2
  import assert from 'node:assert'
3
3
  import { getFamilyImages, getAFamilyImage } from './family.js'
4
4
  import { YotoAPIError } from './helpers.js'
5
- import { loadTestTokens, logResponse } from './test-helpers.js'
5
+ import { loadTestTokens, logResponse } from './endpoint-test-helpers.js'
6
6
 
7
7
  const { accessToken } = loadTestTokens()
8
8
 
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Request options derived from undici.request
3
+ * @typedef {NonNullable<Parameters<typeof request>[1]>} RequestOptions
4
+ */
5
+ /**
6
+ * @param {object} [options]
7
+ * @param {string} [options.userAgent] - Optional user agent string to prepend to library user agent
8
+ * @param {RequestOptions} [options.requestOptions] - Additional undici request options
9
+ */
1
10
  export function defaultHeaders(options?: {
2
11
  userAgent?: string | undefined;
3
12
  requestOptions?: ({
@@ -7,6 +16,11 @@ export function defaultHeaders(options?: {
7
16
  Accept: string;
8
17
  'User-Agent': string;
9
18
  };
19
+ /**
20
+ * @param {object} params
21
+ * @param {string} params.accessToken
22
+ * @param {string} [params.userAgent] - Optional user agent string to prepend to library user agent
23
+ */
10
24
  export function defaultAuthHeaders({ accessToken: token, userAgent }: {
11
25
  accessToken: string;
12
26
  userAgent?: string | undefined;
@@ -15,14 +29,34 @@ export function defaultAuthHeaders({ accessToken: token, userAgent }: {
15
29
  Accept: string;
16
30
  'User-Agent': string;
17
31
  };
32
+ /**
33
+ * Merge undici request options with defaults
34
+ * Properly merges headers by supplementing rather than overriding
35
+ * Only supports object headers (not arrays)
36
+ * @param {RequestOptions} baseOptions - Base request options with headers
37
+ * @param {RequestOptions} [requestOptions] - Additional request options to merge
38
+ * @returns {object} Merged options
39
+ */
18
40
  export function mergeRequestOptions(baseOptions: RequestOptions, requestOptions?: RequestOptions): object;
41
+ /**
42
+ * @param {Dispatcher.ResponseData} response
43
+ * @param {any} [extra]
44
+ */
19
45
  export function handleBadResponse(response: Dispatcher.ResponseData, extra?: any): Promise<void>;
20
46
  export class YotoAPIError extends Error {
47
+ /**
48
+ * @param {Dispatcher.ResponseData} response A undici Response
49
+ * @param {string | object} body response body
50
+ * @param {any} [extra] any extra info to attach to the error
51
+ */
21
52
  constructor(response: Dispatcher.ResponseData, body: string | object, extra?: any);
22
- statusCode: number;
23
- body: string | object;
24
- extra: any;
53
+ /** @type { number } */ statusCode: number;
54
+ /** @type {string | object } */ body: string | object;
55
+ /** @type {any} */ extra: any;
25
56
  }
57
+ /**
58
+ * Request options derived from undici.request
59
+ */
26
60
  export type RequestOptions = NonNullable<Parameters<typeof request>[1]>;
27
61
  import type { Dispatcher } from 'undici';
28
62
  import type { request } from 'undici';
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["helpers.js"],"names":[],"mappings":"AAiBA,yCAHG;IAAyB,SAAS;IACD,cAAc;;;CACjD;;;EAWA;AAOD,sEAHG;IAAwB,WAAW,EAA1B,MAAM;IACS,SAAS;CACnC;;;;EAMA;AAUD,iDAJW,cAAc,mBACd,cAAc,GACZ,MAAM,CAoBlB;AAMD,4CAHY,uBAAuB,UACvB,GAAG,iBAWd;AAED;IAUE,sBAJY,uBAAuB,QACvB,MAAM,GAAG,MAAM,UACf,GAAG,EAUd;IAjBuB,YAAZ,MAAM,CAAgB;IACF,MAArB,MAAM,GAAG,MAAM,CAAU;IACjB,OAAR,GAAG,CAAU;CAgBzB;6BA9FY,WAAW,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;gCARxB,QAAQ;6BACX,QAAQ"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["helpers.js"],"names":[],"mappings":"AAOA;;;GAGG;AAEH;;;;GAIG;AACH,yCAHG;IAAyB,SAAS;IACD,cAAc;;;CACjD;;;EAWA;AAED;;;;GAIG;AACH,sEAHG;IAAwB,WAAW,EAA1B,MAAM;IACS,SAAS;CACnC;;;;EAMA;AAED;;;;;;;GAOG;AACH,iDAJW,cAAc,mBACd,cAAc,GACZ,MAAM,CAoBlB;AAED;;;GAGG;AACH,4CAHY,uBAAuB,UACvB,GAAG,iBAWd;AAED;IAKE;;;;OAIG;IACH,sBAJY,uBAAuB,QACvB,MAAM,GAAG,MAAM,UACf,GAAG,EAUd;IAjBD,uBAAuB,CAAC,YAAZ,MAAM,CAAgB;IAClC,+BAA+B,CAAC,MAArB,MAAM,GAAG,MAAM,CAAU;IACpC,kBAAkB,CAAC,OAAR,GAAG,CAAU;CAgBzB;;;;6BA9FY,WAAW,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;gCARxB,QAAQ;6BACX,QAAQ"}
@@ -1,3 +1,41 @@
1
+ /**
2
+ * @see https://yoto.dev/api/getpublicicons/
3
+ * @typedef {Object} YotoPublicIconsResponse
4
+ * @property {YotoPublicIcon[]} displayIcons - Array of public display icons
5
+ */
6
+ /**
7
+ * @see https://yoto.dev/api/getpublicicons/
8
+ * @typedef {Object} YotoPublicIcon
9
+ * @property {string} displayIconId - Unique identifier for the icon
10
+ * @property {string} mediaId - Unique identifier for the underlying icon file
11
+ * @property {string} userId - ID of the user who uploaded this icon (always "yoto" for public icons)
12
+ * @property {string} createdAt - ISO 8601 timestamp when icon record was created
13
+ * @property {string} title - Title of the display icon
14
+ * @property {string} url - URL of the display icon
15
+ * @property {boolean} public - Indicates if the icon is public (always true for public icons)
16
+ * @property {boolean} [new] - Indicates if this is a new icon (may not always be present)
17
+ * @property {string[]} publicTags - Public tags associated with the display icon
18
+ */
19
+ /**
20
+ * Retrieves the list of public icons that are available to every user.
21
+ * @see https://yoto.dev/api/getpublicicons/
22
+ * @param {object} options
23
+ * @param {string} options.accessToken The API token to request with
24
+ * @param {string} [options.userAgent] Optional user agent string
25
+ * @param {RequestOptions} [options.requestOptions] Additional undici request options
26
+ * @return {Promise<YotoPublicIconsResponse>} Public display icons
27
+ * @example
28
+ * import { getPublicIcons } from 'yoto-nodejs-client'
29
+ *
30
+ * const icons = await getPublicIcons({
31
+ * accessToken
32
+ * })
33
+ *
34
+ * console.log(`Found ${icons.displayIcons.length} public icons`)
35
+ * icons.displayIcons.forEach(icon => {
36
+ * console.log(`${icon.title} - Tags: ${icon.publicTags.join(', ')}`)
37
+ * })
38
+ */
1
39
  export function getPublicIcons({ accessToken, userAgent, requestOptions }: {
2
40
  accessToken: string;
3
41
  userAgent?: string | undefined;
@@ -5,6 +43,30 @@ export function getPublicIcons({ accessToken, userAgent, requestOptions }: {
5
43
  dispatcher?: import("undici").Dispatcher;
6
44
  } & Omit<import("undici").Dispatcher.RequestOptions<unknown>, "origin" | "path" | "method"> & Partial<Pick<import("undici").Dispatcher.RequestOptions<null>, "method">>) | undefined;
7
45
  }): Promise<YotoPublicIconsResponse>;
46
+ /**
47
+ * @see https://yoto.dev/api/getusericons/
48
+ * @typedef {Object} YotoUserIconsResponse
49
+ * @property {YotoUserIcon[]} displayIcons - Array of user's custom display icons
50
+ */
51
+ /**
52
+ * @see https://yoto.dev/api/getusericons/
53
+ * @typedef {Object} YotoUserIcon
54
+ * @property {string} displayIconId - Unique identifier for the icon
55
+ * @property {string} mediaId - Unique identifier for the underlying icon file
56
+ * @property {string} userId - ID of the user who uploaded this icon
57
+ * @property {string} createdAt - ISO 8601 timestamp when icon record was created
58
+ * @property {string} url - URL of the display icon
59
+ * @property {boolean} public - Indicates if the icon is public (always false for user icons)
60
+ */
61
+ /**
62
+ * Retrieves the authenticated user's custom uploaded icons.
63
+ * @see https://yoto.dev/api/getusericons/
64
+ * @param {object} options
65
+ * @param {string} options.accessToken The API token to request with
66
+ * @param {string} [options.userAgent] Optional user agent string
67
+ * @param {RequestOptions} [options.requestOptions] Additional undici request options
68
+ * @return {Promise<YotoUserIconsResponse>} User's custom display icons
69
+ */
8
70
  export function getUserIcons({ accessToken, userAgent, requestOptions }: {
9
71
  accessToken: string;
10
72
  userAgent?: string | undefined;
@@ -12,6 +74,65 @@ export function getUserIcons({ accessToken, userAgent, requestOptions }: {
12
74
  dispatcher?: import("undici").Dispatcher;
13
75
  } & Omit<import("undici").Dispatcher.RequestOptions<unknown>, "origin" | "path" | "method"> & Partial<Pick<import("undici").Dispatcher.RequestOptions<null>, "method">>) | undefined;
14
76
  }): Promise<YotoUserIconsResponse>;
77
+ /**
78
+ * @see https://yoto.dev/api/uploadcustomicon/
79
+ * @typedef {Object} YotoUploadIconResponse
80
+ * @property {YotoDisplayIcon} displayIcon - The uploaded or existing display icon
81
+ */
82
+ /**
83
+ * @see https://yoto.dev/api/uploadcustomicon/
84
+ * @typedef {Object} YotoDisplayIcon
85
+ * @property {string} displayIconId - Unique identifier for the icon
86
+ * @property {string} mediaId - Unique identifier for the underlying icon file
87
+ * @property {string} userId - ID of the user who uploaded this icon
88
+ * @property {string | object} url - URL of the display icon, or empty object {} for duplicates
89
+ * @property {boolean} [new] - True if this is a new upload, undefined for duplicates
90
+ * @property {string} [_id] - MongoDB ID (present for duplicate uploads)
91
+ * @property {string} [createdAt] - ISO 8601 timestamp (present for duplicate uploads)
92
+ */
93
+ /**
94
+ * Uploads a custom 16×16px icon for the authenticated user.
95
+ * Icons are deduplicated by content - re-uploading the same image returns the existing icon.
96
+ *
97
+ * Image processing with autoConvert=true (recommended):
98
+ * - Auto-resizes to 16×16px (crop/pad as needed)
99
+ * - Adjusts brightness if > ⅔
100
+ * - Converts to PNG
101
+ * - Accepts any image format
102
+ *
103
+ * Image requirements with autoConvert=false (strict):
104
+ * - Must be exactly 16×16px
105
+ * - Only PNG or GIF allowed
106
+ * - PNG must be 24-bit RGBA (sRGB, 4 channels, hasAlpha, no palette)
107
+ * - GIF accepted as-is
108
+ *
109
+ * @see https://yoto.dev/api/uploadcustomicon/
110
+ * @param {object} options
111
+ * @param {string} options.accessToken The API token to request with
112
+ * @param {Buffer} options.imageData The binary image data (16×16px icon)
113
+ * @param {boolean} [options.autoConvert=true] Auto-resize and process the image to 16×16px
114
+ * @param {string} [options.filename] Override the stored base filename
115
+ * @param {string} [options.userAgent] Optional user agent string
116
+ * @param {RequestOptions} [options.requestOptions] Additional undici request options
117
+ * @return {Promise<YotoUploadIconResponse>} The uploaded or existing display icon
118
+ * @example
119
+ * import { readFile } from 'fs/promises'
120
+ * import { uploadIcon } from 'yoto-nodejs-client'
121
+ *
122
+ * const imageData = await readFile('./my-icon.png')
123
+ * const result = await uploadIcon({
124
+ * accessToken,
125
+ * imageData,
126
+ * autoConvert: true,
127
+ * filename: 'my-custom-icon'
128
+ * })
129
+ *
130
+ * if (result.displayIcon.new) {
131
+ * console.log('New icon uploaded:', result.displayIcon.displayIconId)
132
+ * } else {
133
+ * console.log('Icon already exists:', result.displayIcon.displayIconId)
134
+ * }
135
+ */
15
136
  export function uploadIcon({ accessToken, userAgent, imageData, autoConvert, filename, requestOptions }: {
16
137
  accessToken: string;
17
138
  imageData: Buffer;
@@ -23,40 +144,115 @@ export function uploadIcon({ accessToken, userAgent, imageData, autoConvert, fil
23
144
  } & Omit<import("undici").Dispatcher.RequestOptions<unknown>, "origin" | "path" | "method"> & Partial<Pick<import("undici").Dispatcher.RequestOptions<null>, "method">>) | undefined;
24
145
  }): Promise<YotoUploadIconResponse>;
25
146
  export type YotoPublicIconsResponse = {
147
+ /**
148
+ * - Array of public display icons
149
+ */
26
150
  displayIcons: YotoPublicIcon[];
27
151
  };
28
152
  export type YotoPublicIcon = {
153
+ /**
154
+ * - Unique identifier for the icon
155
+ */
29
156
  displayIconId: string;
157
+ /**
158
+ * - Unique identifier for the underlying icon file
159
+ */
30
160
  mediaId: string;
161
+ /**
162
+ * - ID of the user who uploaded this icon (always "yoto" for public icons)
163
+ */
31
164
  userId: string;
165
+ /**
166
+ * - ISO 8601 timestamp when icon record was created
167
+ */
32
168
  createdAt: string;
169
+ /**
170
+ * - Title of the display icon
171
+ */
33
172
  title: string;
173
+ /**
174
+ * - URL of the display icon
175
+ */
34
176
  url: string;
177
+ /**
178
+ * - Indicates if the icon is public (always true for public icons)
179
+ */
35
180
  public: boolean;
181
+ /**
182
+ * - Indicates if this is a new icon (may not always be present)
183
+ */
36
184
  new?: boolean;
185
+ /**
186
+ * - Public tags associated with the display icon
187
+ */
37
188
  publicTags: string[];
38
189
  };
39
190
  export type YotoUserIconsResponse = {
191
+ /**
192
+ * - Array of user's custom display icons
193
+ */
40
194
  displayIcons: YotoUserIcon[];
41
195
  };
42
196
  export type YotoUserIcon = {
197
+ /**
198
+ * - Unique identifier for the icon
199
+ */
43
200
  displayIconId: string;
201
+ /**
202
+ * - Unique identifier for the underlying icon file
203
+ */
44
204
  mediaId: string;
205
+ /**
206
+ * - ID of the user who uploaded this icon
207
+ */
45
208
  userId: string;
209
+ /**
210
+ * - ISO 8601 timestamp when icon record was created
211
+ */
46
212
  createdAt: string;
213
+ /**
214
+ * - URL of the display icon
215
+ */
47
216
  url: string;
217
+ /**
218
+ * - Indicates if the icon is public (always false for user icons)
219
+ */
48
220
  public: boolean;
49
221
  };
50
222
  export type YotoUploadIconResponse = {
223
+ /**
224
+ * - The uploaded or existing display icon
225
+ */
51
226
  displayIcon: YotoDisplayIcon;
52
227
  };
53
228
  export type YotoDisplayIcon = {
229
+ /**
230
+ * - Unique identifier for the icon
231
+ */
54
232
  displayIconId: string;
233
+ /**
234
+ * - Unique identifier for the underlying icon file
235
+ */
55
236
  mediaId: string;
237
+ /**
238
+ * - ID of the user who uploaded this icon
239
+ */
56
240
  userId: string;
241
+ /**
242
+ * - URL of the display icon, or empty object {} for duplicates
243
+ */
57
244
  url: string | object;
245
+ /**
246
+ * - True if this is a new upload, undefined for duplicates
247
+ */
58
248
  new?: boolean;
249
+ /**
250
+ * - MongoDB ID (present for duplicate uploads)
251
+ */
59
252
  _id?: string;
253
+ /**
254
+ * - ISO 8601 timestamp (present for duplicate uploads)
255
+ */
60
256
  createdAt?: string;
61
257
  };
62
258
  //# sourceMappingURL=icons.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["icons.js"],"names":[],"mappings":"AAmDA,2EAhBG;IAAyB,WAAW,EAA3B,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,uBAAuB,CAAC,CA6B3C;AA4BD,yEALG;IAAyB,WAAW,EAA3B,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,qBAAqB,CAAC,CAkBzC;AA+DD,yGAzBG;IAAyB,WAAW,EAA3B,MAAM;IACU,SAAS,EAAzB,MAAM;IACY,WAAW;IACZ,QAAQ;IACR,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,sBAAsB,CAAC,CA6C1C;;kBA1La,cAAc,EAAE;;;mBAMhB,MAAM;aACN,MAAM;YACN,MAAM;eACN,MAAM;WACN,MAAM;SACN,MAAM;YACN,OAAO;UACP,OAAO;gBACP,MAAM,EAAE;;;kBA4CR,YAAY,EAAE;;;mBAMd,MAAM;aACN,MAAM;YACN,MAAM;eACN,MAAM;SACN,MAAM;YACN,OAAO;;;iBAiCP,eAAe;;;mBAMf,MAAM;aACN,MAAM;YACN,MAAM;SACN,MAAM,GAAG,MAAM;UACf,OAAO;UACP,MAAM;gBACN,MAAM"}
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["icons.js"],"names":[],"mappings":"AAWA;;;;GAIG;AAEH;;;;;;;;;;;;GAYG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,2EAhBG;IAAyB,WAAW,EAA3B,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,uBAAuB,CAAC,CA6B3C;AAED;;;;GAIG;AAEH;;;;;;;;;GASG;AAEH;;;;;;;;GAQG;AACH,yEALG;IAAyB,WAAW,EAA3B,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,qBAAqB,CAAC,CAkBzC;AAED;;;;GAIG;AAEH;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,yGAzBG;IAAyB,WAAW,EAA3B,MAAM;IACU,SAAS,EAAzB,MAAM;IACY,WAAW;IACZ,QAAQ;IACR,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,sBAAsB,CAAC,CA6C1C;;;;;kBA1La,cAAc,EAAE;;;;;;mBAMhB,MAAM;;;;aACN,MAAM;;;;YACN,MAAM;;;;eACN,MAAM;;;;WACN,MAAM;;;;SACN,MAAM;;;;YACN,OAAO;;;;UACP,OAAO;;;;gBACP,MAAM,EAAE;;;;;;kBA4CR,YAAY,EAAE;;;;;;mBAMd,MAAM;;;;aACN,MAAM;;;;YACN,MAAM;;;;eACN,MAAM;;;;SACN,MAAM;;;;YACN,OAAO;;;;;;iBAiCP,eAAe;;;;;;mBAMf,MAAM;;;;aACN,MAAM;;;;YACN,MAAM;;;;SACN,MAAM,GAAG,MAAM;;;;UACf,OAAO;;;;UACP,MAAM;;;;gBACN,MAAM"}
@@ -2,7 +2,7 @@ import test from 'node:test'
2
2
  import assert from 'node:assert'
3
3
  import { getPublicIcons, getUserIcons } from './icons.js'
4
4
  import { YotoAPIError } from './helpers.js'
5
- import { loadTestTokens, logResponse } from './test-helpers.js'
5
+ import { loadTestTokens, logResponse } from './endpoint-test-helpers.js'
6
6
 
7
7
  const { accessToken } = loadTestTokens()
8
8
 
@@ -1,3 +1,47 @@
1
+ /**
2
+ * @see https://yoto.dev/api/getanuploadurl/
3
+ * @typedef {Object} YotoAudioUpload
4
+ * @property {string} uploadId - Upload identifier
5
+ * @property {string | null} uploadUrl - Signed upload URL, or null if file already exists
6
+ */
7
+ /**
8
+ * @see https://yoto.dev/api/getanuploadurl/
9
+ * @typedef {Object} YotoAudioUploadUrlResponse
10
+ * @property {YotoAudioUpload} upload
11
+ */
12
+ /**
13
+ * @see https://yoto.dev/api/uploadcoverimage/
14
+ * @typedef {Object} YotoCoverImage
15
+ * @property {string} mediaId - Media identifier
16
+ * @property {string} mediaUrl - URL to access the uploaded cover image
17
+ */
18
+ /**
19
+ * @see https://yoto.dev/api/uploadcoverimage/
20
+ * @typedef {Object} YotoUploadCoverImageResponse
21
+ * @property {YotoCoverImage} coverImage
22
+ */
23
+ /**
24
+ * @see https://yoto.dev/api/uploadcoverimage/
25
+ * @typedef {'default' | 'activities' | 'music' | 'myo' | 'podcast' | 'radio' | 'sfx' | 'stories'} YotoCoverType
26
+ */
27
+ /**
28
+ * Get a signed URL for uploading an audio file. The SHA256 hash is used to check
29
+ * if a file with that checksum already exists (deduplication).
30
+ *
31
+ * Response behavior:
32
+ * - If file already exists: uploadUrl will be null (file is already in store)
33
+ * - If file doesn't exist: uploadUrl contains a signed URL for uploading
34
+ * - uploadId is always returned and can be used to reference the upload
35
+ *
36
+ * @see https://yoto.dev/api/getanuploadurl/
37
+ * @param {object} options
38
+ * @param {string} options.accessToken - Authentication token
39
+ * @param {string} options.sha256 - SHA256 hash of the file to upload
40
+ * @param {string} [options.filename] - Optional filename for the uploaded file
41
+ * @param {string} [options.userAgent] - Optional user agent string
42
+ * @param {RequestOptions} [options.requestOptions] - Additional undici request options
43
+ * @returns {Promise<YotoAudioUploadUrlResponse>}
44
+ */
1
45
  export function getAudioUploadUrl({ accessToken, userAgent, sha256, filename, requestOptions }: {
2
46
  accessToken: string;
3
47
  sha256: string;
@@ -7,6 +51,33 @@ export function getAudioUploadUrl({ accessToken, userAgent, sha256, filename, re
7
51
  dispatcher?: import("undici").Dispatcher;
8
52
  } & Omit<import("undici").Dispatcher.RequestOptions<unknown>, "origin" | "path" | "method"> & Partial<Pick<import("undici").Dispatcher.RequestOptions<null>, "method">>) | undefined;
9
53
  }): Promise<YotoAudioUploadUrlResponse>;
54
+ /**
55
+ * Upload a cover image to the user's media account. Supports both direct binary
56
+ * uploads and fetching from a URL. Images are automatically resized based on coverType.
57
+ *
58
+ * Image processing:
59
+ * - Images are resized according to coverType (default: 638x1011px)
60
+ * - Aspect ratio is preserved
61
+ * - Images are cropped to fit dimensions, positioned to center
62
+ * - Supports automatic image conversion with autoConvert flag
63
+ *
64
+ * Cover type dimensions:
65
+ * - default/activities/music/sfx/stories: 638×1011px
66
+ * - myo: 520×400px
67
+ * - podcast/radio: 600×600px
68
+ *
69
+ * @see https://yoto.dev/api/uploadcoverimage/
70
+ * @param {object} options
71
+ * @param {string} options.accessToken - Authentication token
72
+ * @param {Buffer | Uint8Array | string} [options.imageData] - Binary image data to upload (required if imageUrl not provided)
73
+ * @param {string} [options.imageUrl] - URL of image to fetch and upload (required if imageData not provided)
74
+ * @param {boolean} [options.autoConvert] - Whether to automatically convert the image
75
+ * @param {YotoCoverType} [options.coverType] - Type of cover image, determines dimensions
76
+ * @param {string} [options.filename] - Custom filename for the uploaded image
77
+ * @param {string} [options.userAgent] - Optional user agent string
78
+ * @param {RequestOptions} [options.requestOptions] - Additional undici request options
79
+ * @returns {Promise<YotoUploadCoverImageResponse>}
80
+ */
10
81
  export function uploadCoverImage({ accessToken, userAgent, imageData, imageUrl, autoConvert, coverType, filename, requestOptions }: {
11
82
  accessToken: string;
12
83
  imageData?: string | Buffer<ArrayBufferLike> | Uint8Array<ArrayBufferLike> | undefined;
@@ -20,14 +91,26 @@ export function uploadCoverImage({ accessToken, userAgent, imageData, imageUrl,
20
91
  } & Omit<import("undici").Dispatcher.RequestOptions<unknown>, "origin" | "path" | "method"> & Partial<Pick<import("undici").Dispatcher.RequestOptions<null>, "method">>) | undefined;
21
92
  }): Promise<YotoUploadCoverImageResponse>;
22
93
  export type YotoAudioUpload = {
94
+ /**
95
+ * - Upload identifier
96
+ */
23
97
  uploadId: string;
98
+ /**
99
+ * - Signed upload URL, or null if file already exists
100
+ */
24
101
  uploadUrl: string | null;
25
102
  };
26
103
  export type YotoAudioUploadUrlResponse = {
27
104
  upload: YotoAudioUpload;
28
105
  };
29
106
  export type YotoCoverImage = {
107
+ /**
108
+ * - Media identifier
109
+ */
30
110
  mediaId: string;
111
+ /**
112
+ * - URL to access the uploaded cover image
113
+ */
31
114
  mediaUrl: string;
32
115
  };
33
116
  export type YotoUploadCoverImageResponse = {
@@ -1 +1 @@
1
- {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["media.js"],"names":[],"mappings":"AAmEA,gGAPG;IAAwB,WAAW,EAA3B,MAAM;IACU,MAAM,EAAtB,MAAM;IACW,QAAQ;IACR,SAAS;IACD,cAAc;;;CAC/C,GAAU,OAAO,CAAC,0BAA0B,CAAC,CAuB/C;AA6BD,oIAVG;IAAwB,WAAW,EAA3B,MAAM;IACiC,SAAS;IAC/B,QAAQ;IACP,WAAW;IACL,SAAS;IAChB,QAAQ;IACR,SAAS;IACD,cAAc;;;CAC/C,GAAU,OAAO,CAAC,4BAA4B,CAAC,CAuCjD;;cArIa,MAAM;eACN,MAAM,GAAG,IAAI;;;YAMb,eAAe;;;aAMf,MAAM;cACN,MAAM;;;gBAMN,cAAc;;4BAKf,SAAS,GAAG,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS"}
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["media.js"],"names":[],"mappings":"AAkBA;;;;;GAKG;AAEH;;;;GAIG;AAEH;;;;;GAKG;AAEH;;;;GAIG;AAEH;;;GAGG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,gGAPG;IAAwB,WAAW,EAA3B,MAAM;IACU,MAAM,EAAtB,MAAM;IACW,QAAQ;IACR,SAAS;IACD,cAAc;;;CAC/C,GAAU,OAAO,CAAC,0BAA0B,CAAC,CAuB/C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,oIAVG;IAAwB,WAAW,EAA3B,MAAM;IACiC,SAAS;IAC/B,QAAQ;IACP,WAAW;IACL,SAAS;IAChB,QAAQ;IACR,SAAS;IACD,cAAc;;;CAC/C,GAAU,OAAO,CAAC,4BAA4B,CAAC,CAuCjD;;;;;cArIa,MAAM;;;;eACN,MAAM,GAAG,IAAI;;;YAMb,eAAe;;;;;;aAMf,MAAM;;;;cACN,MAAM;;;gBAMN,cAAc;;4BAKf,SAAS,GAAG,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Power state detection helper for Yoto device status
3
+ *
4
+ * Analyzes shutdown field and uptime to determine device power state changes
5
+ */
6
+ /**
7
+ * Power state detection result
8
+ * @typedef {Object} PowerStateResult
9
+ * @property {'running' | 'shutdown' | 'startup'} state - Device power state
10
+ * @property {string | null} shutDownReason - Shutdown reason if state is 'shutdown'
11
+ * @property {number | null} upTime - Device uptime in seconds if state is 'startup'
12
+ */
13
+ /**
14
+ * Detect device power state from legacy status
15
+ *
16
+ * @param {string | null | undefined} shutDown - shutDown field from legacy status
17
+ * @param {number | null | undefined} upTime - upTime field from legacy status in seconds
18
+ * @returns {PowerStateResult}
19
+ *
20
+ * @example
21
+ * // Device running normally
22
+ * detectPowerState('nA', 3600)
23
+ * // { state: 'running', shutDownReason: null, upTime: null }
24
+ *
25
+ * @example
26
+ * // Device just started (low uptime)
27
+ * detectPowerState('nA', 45)
28
+ * // { state: 'startup', shutDownReason: null, upTime: 45 }
29
+ *
30
+ * @example
31
+ * // Device shutting down
32
+ * detectPowerState('userShutdown', 3600)
33
+ * // { state: 'shutdown', shutDownReason: 'userShutdown', upTime: null }
34
+ */
35
+ export function detectPowerState(shutDown: string | null | undefined, upTime: number | null | undefined): PowerStateResult;
36
+ /**
37
+ * Power state detection result
38
+ */
39
+ export type PowerStateResult = {
40
+ /**
41
+ * - Device power state
42
+ */
43
+ state: "running" | "shutdown" | "startup";
44
+ /**
45
+ * - Shutdown reason if state is 'shutdown'
46
+ */
47
+ shutDownReason: string | null;
48
+ /**
49
+ * - Device uptime in seconds if state is 'startup'
50
+ */
51
+ upTime: number | null;
52
+ };
53
+ //# sourceMappingURL=power-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"power-state.d.ts","sourceRoot":"","sources":["power-state.js"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,2CAnBW,MAAM,GAAG,IAAI,GAAG,SAAS,UACzB,MAAM,GAAG,IAAI,GAAG,SAAS,GACvB,gBAAgB,CAqD5B;;;;;;;;WA/Da,SAAS,GAAG,UAAU,GAAG,SAAS;;;;oBAClC,MAAM,GAAG,IAAI;;;;YACb,MAAM,GAAG,IAAI"}