yoto-nodejs-client 0.0.5 → 0.0.7

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 (52) hide show
  1. package/README.md +73 -40
  2. package/bin/auth.js +4 -3
  3. package/bin/device-model.js +25 -5
  4. package/bin/device-tui.js +25 -3
  5. package/bin/devices.js +25 -9
  6. package/bin/lib/cli-helpers.d.ts.map +1 -1
  7. package/bin/lib/cli-helpers.js +3 -1
  8. package/bin/lib/token-helpers.d.ts +4 -2
  9. package/bin/lib/token-helpers.d.ts.map +1 -1
  10. package/bin/lib/token-helpers.js +9 -8
  11. package/bin/refresh-token.js +4 -2
  12. package/bin/token-info.js +2 -2
  13. package/lib/api-client.d.ts +11 -10
  14. package/lib/api-client.d.ts.map +1 -1
  15. package/lib/api-client.js +12 -14
  16. package/lib/api-endpoints/auth.test.js +4 -4
  17. package/lib/api-endpoints/content.test.js +32 -32
  18. package/lib/api-endpoints/devices.d.ts +4 -4
  19. package/lib/api-endpoints/devices.js +2 -2
  20. package/lib/api-endpoints/devices.test.js +45 -45
  21. package/lib/api-endpoints/endpoint-test-helpers.d.ts +3 -4
  22. package/lib/api-endpoints/endpoint-test-helpers.d.ts.map +1 -1
  23. package/lib/api-endpoints/endpoint-test-helpers.js +21 -5
  24. package/lib/api-endpoints/family-library-groups.d.ts +3 -3
  25. package/lib/api-endpoints/family-library-groups.d.ts.map +1 -1
  26. package/lib/api-endpoints/family-library-groups.js +3 -3
  27. package/lib/api-endpoints/family-library-groups.test.js +29 -29
  28. package/lib/api-endpoints/family.test.js +11 -11
  29. package/lib/api-endpoints/icons.test.js +14 -14
  30. package/lib/mqtt/client.d.ts +123 -48
  31. package/lib/mqtt/client.d.ts.map +1 -1
  32. package/lib/mqtt/client.js +131 -49
  33. package/lib/mqtt/factory.d.ts +12 -5
  34. package/lib/mqtt/factory.d.ts.map +1 -1
  35. package/lib/mqtt/factory.js +39 -11
  36. package/lib/mqtt/index.js +2 -1
  37. package/lib/mqtt/mqtt.test.js +25 -22
  38. package/lib/test-helpers/device-model-test-helpers.d.ts +29 -0
  39. package/lib/test-helpers/device-model-test-helpers.d.ts.map +1 -0
  40. package/lib/test-helpers/device-model-test-helpers.js +116 -0
  41. package/lib/token.d.ts +44 -2
  42. package/lib/token.d.ts.map +1 -1
  43. package/lib/token.js +142 -2
  44. package/lib/yoto-account.d.ts +339 -9
  45. package/lib/yoto-account.d.ts.map +1 -1
  46. package/lib/yoto-account.js +411 -39
  47. package/lib/yoto-account.test.js +139 -0
  48. package/lib/yoto-device.d.ts +418 -30
  49. package/lib/yoto-device.d.ts.map +1 -1
  50. package/lib/yoto-device.js +670 -104
  51. package/lib/yoto-device.test.js +88 -0
  52. package/package.json +1 -1
@@ -3,10 +3,12 @@
3
3
  */
4
4
 
5
5
  import { join } from 'node:path'
6
+ import { RefreshableToken } from '../token.js'
7
+ import { saveTokensToEnv } from '../../bin/lib/token-helpers.js'
6
8
 
7
9
  /**
8
10
  * Load tokens from .env file for testing
9
- * @returns {{accessToken: string, refreshToken: string, clientId: string}}
11
+ * @returns {{ token: RefreshableToken }}
10
12
  */
11
13
  export function loadTestTokens () {
12
14
  const testDir = import.meta.dirname
@@ -26,18 +28,32 @@ export function loadTestTokens () {
26
28
  const refreshToken = process.env['YOTO_REFRESH_TOKEN']
27
29
  const clientId = process.env['YOTO_CLIENT_ID']
28
30
 
29
- if (!accessToken || !refreshToken) {
31
+ if (!accessToken || !refreshToken || !clientId) {
30
32
  console.error('Missing required environment variables:')
31
33
  console.error(' YOTO_ACCESS_TOKEN:', accessToken ? '✓' : '✗')
32
34
  console.error(' YOTO_REFRESH_TOKEN:', refreshToken ? '✓' : '✗')
35
+ console.error(' YOTO_CLIENT_ID:', clientId ? '✓' : '✗')
33
36
  console.error('\nRun `yoto-auth` to authenticate first')
34
37
  process.exit(1)
35
38
  }
36
39
 
37
- return {
38
- accessToken,
40
+ const token = new RefreshableToken({
41
+ clientId,
39
42
  refreshToken,
40
- clientId: clientId || ''
43
+ accessToken,
44
+ async onTokenRefresh (tokens) {
45
+ const { resolvedPath } = await saveTokensToEnv(envPath, {
46
+ access_token: tokens.updatedAccessToken,
47
+ refresh_token: tokens.updatedRefreshToken,
48
+ token_type: 'Bearer',
49
+ expires_in: tokens.updatedExpiresAt - Math.floor(Date.now() / 1000)
50
+ }, tokens.clientId)
51
+ console.log(`Token Refreshed: ${resolvedPath}`)
52
+ }
53
+ })
54
+
55
+ return {
56
+ token
41
57
  }
42
58
  }
43
59
 
@@ -67,7 +67,7 @@ export function getGroups({ accessToken, userAgent, requestOptions }: {
67
67
  * Max 20 groups per family. ContentIds must be in family's library (invalid ones filtered out).
68
68
  * @see https://yoto.dev/api/createagroup/
69
69
  * @param {object} options
70
- * @param {string} options.token The API token to request with
70
+ * @param {string} options.accessToken The API token to request with
71
71
  * @param {YotoCreateGroupRequest} options.group The group data to create
72
72
  * @param {string} [options.userAgent] Optional user agent string
73
73
  * @param {RequestOptions} [options.requestOptions] Additional undici request options
@@ -86,8 +86,8 @@ export function getGroups({ accessToken, userAgent, requestOptions }: {
86
86
  * }
87
87
  * })
88
88
  */
89
- export function createGroup({ token, userAgent, group, requestOptions }: {
90
- token: string;
89
+ export function createGroup({ accessToken, userAgent, group, requestOptions }: {
90
+ accessToken: string;
91
91
  group: YotoCreateGroupRequest;
92
92
  userAgent?: string | undefined;
93
93
  requestOptions?: ({
@@ -1 +1 @@
1
- {"version":3,"file":"family-library-groups.d.ts","sourceRoot":"","sources":["family-library-groups.js"],"names":[],"mappings":"AAWA;;;;GAIG;AAEH;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,sEAhBG;IAAyB,WAAW,EAA3B,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,SAAS,EAAE,CAAC,CA6B/B;AAED;;;;;;GAMG;AAEH;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,yEAnBG;IAAyB,KAAK,EAArB,MAAM;IAC0B,KAAK,EAArC,sBAAsB;IACL,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,SAAS,CAAC,CAoC7B;AAED;;;;;;;;;;GAUG;AACH,8EANG;IAAyB,WAAW,EAA3B,MAAM;IACU,OAAO,EAAvB,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,SAAS,CAAC,CAmB7B;AAED;;;;;;GAMG;AAEH;;;;;;;;;;;GAWG;AACH,wFAPG;IAAyB,WAAW,EAA3B,MAAM;IACU,OAAO,EAAvB,MAAM;IAC0B,KAAK,EAArC,sBAAsB;IACL,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,SAAS,CAAC,CAwB7B;AAED;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,iFANG;IAAyB,WAAW,EAA3B,MAAM;IACU,OAAO,EAAvB,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,uBAAuB,CAAC,CAmB3C;;;;;YAxOa,SAAS,EAAE;;;;;;QAMX,MAAM;;;;UACN,MAAM;;;;cACN,MAAM;;;;aACN,MAAM;;;;cACN,MAAM;;;;WACN,aAAa,EAAE;;;;WACf,GAAG,EAAE;;;;eACL,MAAM;;;;oBACN,MAAM;;;;;;eAMN,MAAM;;;;aACN,MAAM;;;;;;UA6CN,MAAM;;;;aACN,MAAM;;;;WACN,kBAAkB,EAAE;;;;;;eAMpB,MAAM;;;;;;UAmFN,MAAM;;;;aACN,MAAM;;;;WACN,kBAAkB,EAAE;;;;;;QA0CpB,MAAM"}
1
+ {"version":3,"file":"family-library-groups.d.ts","sourceRoot":"","sources":["family-library-groups.js"],"names":[],"mappings":"AAWA;;;;GAIG;AAEH;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,sEAhBG;IAAyB,WAAW,EAA3B,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,SAAS,EAAE,CAAC,CA6B/B;AAED;;;;;;GAMG;AAEH;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,+EAnBG;IAAyB,WAAW,EAA3B,MAAM;IAC0B,KAAK,EAArC,sBAAsB;IACL,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,SAAS,CAAC,CAoC7B;AAED;;;;;;;;;;GAUG;AACH,8EANG;IAAyB,WAAW,EAA3B,MAAM;IACU,OAAO,EAAvB,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,SAAS,CAAC,CAmB7B;AAED;;;;;;GAMG;AAEH;;;;;;;;;;;GAWG;AACH,wFAPG;IAAyB,WAAW,EAA3B,MAAM;IACU,OAAO,EAAvB,MAAM;IAC0B,KAAK,EAArC,sBAAsB;IACL,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,SAAS,CAAC,CAwB7B;AAED;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,iFANG;IAAyB,WAAW,EAA3B,MAAM;IACU,OAAO,EAAvB,MAAM;IACW,SAAS;IACD,cAAc;;;CAChD,GAAS,OAAO,CAAC,uBAAuB,CAAC,CAmB3C;;;;;YAxOa,SAAS,EAAE;;;;;;QAMX,MAAM;;;;UACN,MAAM;;;;cACN,MAAM;;;;aACN,MAAM;;;;cACN,MAAM;;;;WACN,aAAa,EAAE;;;;WACf,GAAG,EAAE;;;;eACL,MAAM;;;;oBACN,MAAM;;;;;;eAMN,MAAM;;;;aACN,MAAM;;;;;;UA6CN,MAAM;;;;aACN,MAAM;;;;WACN,kBAAkB,EAAE;;;;;;eAMpB,MAAM;;;;;;UAmFN,MAAM;;;;aACN,MAAM;;;;WACN,kBAAkB,EAAE;;;;;;QA0CpB,MAAM"}
@@ -94,7 +94,7 @@ export async function getGroups ({
94
94
  * Max 20 groups per family. ContentIds must be in family's library (invalid ones filtered out).
95
95
  * @see https://yoto.dev/api/createagroup/
96
96
  * @param {object} options
97
- * @param {string} options.token The API token to request with
97
+ * @param {string} options.accessToken The API token to request with
98
98
  * @param {YotoCreateGroupRequest} options.group The group data to create
99
99
  * @param {string} [options.userAgent] Optional user agent string
100
100
  * @param {RequestOptions} [options.requestOptions] Additional undici request options
@@ -114,7 +114,7 @@ export async function getGroups ({
114
114
  * })
115
115
  */
116
116
  export async function createGroup ({
117
- token,
117
+ accessToken,
118
118
  userAgent,
119
119
  group,
120
120
  requestOptions
@@ -124,7 +124,7 @@ export async function createGroup ({
124
124
  const response = await request(requestUrl, mergeRequestOptions({
125
125
  method: 'POST',
126
126
  headers: {
127
- ...defaultAuthHeaders({ accessToken: token, userAgent }),
127
+ ...defaultAuthHeaders({ accessToken, userAgent }),
128
128
  'Content-Type': 'application/json'
129
129
  },
130
130
  body: JSON.stringify(group)
@@ -4,12 +4,12 @@ import { getGroups, createGroup, getGroup, updateGroup, deleteGroup } from './fa
4
4
  import { YotoAPIError } from './helpers.js'
5
5
  import { loadTestTokens, logResponse } from './endpoint-test-helpers.js'
6
6
 
7
- const { accessToken } = loadTestTokens()
7
+ const { token } = loadTestTokens()
8
8
 
9
9
  test('getGroups', async (t) => {
10
10
  await t.test('should fetch family library groups', async () => {
11
11
  const response = await getGroups({
12
- accessToken
12
+ accessToken: await token.getAccessToken()
13
13
  })
14
14
 
15
15
  // Log response for type verification and documentation
@@ -23,22 +23,22 @@ test('getGroups', async (t) => {
23
23
  if (response.length > 0) {
24
24
  const group = response[0]
25
25
  assert.ok(group, 'Group should exist')
26
- assert.ok(typeof group.id === 'string', 'Group should have id string')
27
- assert.ok(typeof group.name === 'string', 'Group should have name string')
28
- assert.ok(typeof group.familyId === 'string', 'Group should have familyId string')
29
- assert.ok(typeof group.imageId === 'string', 'Group should have imageId string')
30
- assert.ok(typeof group.imageUrl === 'string', 'Group should have imageUrl string')
26
+ assert.equal(typeof group.id, 'string', 'Group should have id string')
27
+ assert.equal(typeof group.name, 'string', 'Group should have name string')
28
+ assert.equal(typeof group.familyId, 'string', 'Group should have familyId string')
29
+ assert.equal(typeof group.imageId, 'string', 'Group should have imageId string')
30
+ assert.equal(typeof group.imageUrl, 'string', 'Group should have imageUrl string')
31
31
  assert.ok(Array.isArray(group.items), 'Group should have items array')
32
32
  assert.ok(Array.isArray(group.cards), 'Group should have cards array')
33
- assert.ok(typeof group.createdAt === 'string', 'Group should have createdAt string')
34
- assert.ok(typeof group.lastModifiedAt === 'string', 'Group should have lastModifiedAt string')
33
+ assert.equal(typeof group.createdAt, 'string', 'Group should have createdAt string')
34
+ assert.equal(typeof group.lastModifiedAt, 'string', 'Group should have lastModifiedAt string')
35
35
 
36
36
  // Validate items structure if items exist
37
37
  if (group.items.length > 0) {
38
38
  const item = group.items[0]
39
39
  assert.ok(item, 'Item should exist')
40
- assert.ok(typeof item.contentId === 'string', 'Item should have contentId string')
41
- assert.ok(typeof item.addedAt === 'string', 'Item should have addedAt string')
40
+ assert.equal(typeof item.contentId, 'string', 'Item should have contentId string')
41
+ assert.equal(typeof item.addedAt, 'string', 'Item should have addedAt string')
42
42
  }
43
43
  }
44
44
  })
@@ -73,7 +73,7 @@ test('CRUD operations - full lifecycle', async (t) => {
73
73
  console.log('\n🧹 Cleaning up test groups...')
74
74
  for (const groupId of createdGroupIds) {
75
75
  try {
76
- await deleteGroup({ accessToken, groupId })
76
+ await deleteGroup({ accessToken: await token.getAccessToken(), groupId })
77
77
  console.log(` ✓ Deleted group: ${groupId}`)
78
78
  } catch (err) {
79
79
  console.log(` ⚠️ Failed to delete group ${groupId}:`, /** @type {Error} */(err).message)
@@ -83,7 +83,7 @@ test('CRUD operations - full lifecycle', async (t) => {
83
83
 
84
84
  await t.test('should create first group', async () => {
85
85
  const group = await createGroup({
86
- token: accessToken,
86
+ accessToken: await token.getAccessToken(),
87
87
  group: {
88
88
  name: 'Test Group 1',
89
89
  imageId: 'fp-cards',
@@ -95,15 +95,15 @@ test('CRUD operations - full lifecycle', async (t) => {
95
95
 
96
96
  // Validate response structure
97
97
  assert.ok(group, 'Response should exist')
98
- assert.ok(typeof group.id === 'string', 'Group should have id string')
98
+ assert.equal(typeof group.id, 'string', 'Group should have id string')
99
99
  assert.strictEqual(group.name, 'Test Group 1', 'Group name should match')
100
100
  assert.strictEqual(group.imageId, 'fp-cards', 'Image ID should match')
101
101
  assert.ok(Array.isArray(group.items), 'Group should have items array')
102
102
  assert.strictEqual(group.items.length, 0, 'Items should be empty')
103
103
  assert.ok(Array.isArray(group.cards), 'Group should have cards array')
104
- assert.ok(typeof group.familyId === 'string', 'Group should have familyId')
105
- assert.ok(typeof group.createdAt === 'string', 'Group should have createdAt')
106
- assert.ok(typeof group.lastModifiedAt === 'string', 'Group should have lastModifiedAt')
104
+ assert.equal(typeof group.familyId, 'string', 'Group should have familyId')
105
+ assert.equal(typeof group.createdAt, 'string', 'Group should have createdAt')
106
+ assert.equal(typeof group.lastModifiedAt, 'string', 'Group should have lastModifiedAt')
107
107
 
108
108
  group1Id = group.id
109
109
  createdGroupIds.push(group.id)
@@ -111,7 +111,7 @@ test('CRUD operations - full lifecycle', async (t) => {
111
111
 
112
112
  await t.test('should create second group', async () => {
113
113
  const group = await createGroup({
114
- token: accessToken,
114
+ accessToken: await token.getAccessToken(),
115
115
  group: {
116
116
  name: 'Test Group 2',
117
117
  imageId: 'fp-cards',
@@ -123,7 +123,7 @@ test('CRUD operations - full lifecycle', async (t) => {
123
123
 
124
124
  // Validate response structure
125
125
  assert.ok(group, 'Response should exist')
126
- assert.ok(typeof group.id === 'string', 'Group should have id string')
126
+ assert.equal(typeof group.id, 'string', 'Group should have id string')
127
127
  assert.strictEqual(group.name, 'Test Group 2', 'Group name should match')
128
128
  assert.notStrictEqual(group.id, group1Id, 'Group IDs should be different')
129
129
 
@@ -133,7 +133,7 @@ test('CRUD operations - full lifecycle', async (t) => {
133
133
 
134
134
  await t.test('should list groups and find both created groups', async () => {
135
135
  const groups = await getGroups({
136
- accessToken
136
+ accessToken: await token.getAccessToken(),
137
137
  })
138
138
 
139
139
  logResponse('GET /card/family/library/groups (after creating 2)', groups)
@@ -153,7 +153,7 @@ test('CRUD operations - full lifecycle', async (t) => {
153
153
 
154
154
  await t.test('should get first group by ID', async () => {
155
155
  const group = await getGroup({
156
- accessToken,
156
+ accessToken: await token.getAccessToken(),
157
157
  groupId: group1Id
158
158
  })
159
159
 
@@ -169,7 +169,7 @@ test('CRUD operations - full lifecycle', async (t) => {
169
169
 
170
170
  await t.test('should get second group by ID', async () => {
171
171
  const group = await getGroup({
172
- accessToken,
172
+ accessToken: await token.getAccessToken(),
173
173
  groupId: group2Id
174
174
  })
175
175
 
@@ -182,7 +182,7 @@ test('CRUD operations - full lifecycle', async (t) => {
182
182
 
183
183
  await t.test('should update first group', async () => {
184
184
  const updatedGroup = await updateGroup({
185
- accessToken,
185
+ accessToken: await token.getAccessToken(),
186
186
  groupId: group1Id,
187
187
  group: {
188
188
  name: 'Test Group 1 - Updated',
@@ -196,12 +196,12 @@ test('CRUD operations - full lifecycle', async (t) => {
196
196
  assert.ok(updatedGroup, 'Response should exist')
197
197
  assert.strictEqual(updatedGroup.id, group1Id, 'Group ID should remain the same')
198
198
  assert.strictEqual(updatedGroup.name, 'Test Group 1 - Updated', 'Group name should be updated')
199
- assert.ok(typeof updatedGroup.lastModifiedAt === 'string', 'Should have lastModifiedAt')
199
+ assert.equal(typeof updatedGroup.lastModifiedAt, 'string', 'Should have lastModifiedAt')
200
200
  })
201
201
 
202
202
  await t.test('should get updated group and confirm changes', async () => {
203
203
  const group = await getGroup({
204
- accessToken,
204
+ accessToken: await token.getAccessToken(),
205
205
  groupId: group1Id
206
206
  })
207
207
 
@@ -212,7 +212,7 @@ test('CRUD operations - full lifecycle', async (t) => {
212
212
 
213
213
  await t.test('should delete first group', async () => {
214
214
  const response = await deleteGroup({
215
- accessToken,
215
+ accessToken: await token.getAccessToken(),
216
216
  groupId: group1Id
217
217
  })
218
218
 
@@ -227,7 +227,7 @@ test('CRUD operations - full lifecycle', async (t) => {
227
227
 
228
228
  await t.test('should delete second group', async () => {
229
229
  const response = await deleteGroup({
230
- accessToken,
230
+ accessToken: await token.getAccessToken(),
231
231
  groupId: group2Id
232
232
  })
233
233
 
@@ -242,7 +242,7 @@ test('CRUD operations - full lifecycle', async (t) => {
242
242
 
243
243
  await t.test('should verify groups are deleted from list', async () => {
244
244
  const groups = await getGroups({
245
- accessToken
245
+ accessToken: await token.getAccessToken()
246
246
  })
247
247
 
248
248
  logResponse('GET /card/family/library/groups (after deletion)', groups)
@@ -258,7 +258,7 @@ test('CRUD operations - full lifecycle', async (t) => {
258
258
  await assert.rejects(
259
259
  async () => {
260
260
  await getGroup({
261
- accessToken,
261
+ accessToken: await token.getAccessToken(),
262
262
  groupId: group1Id
263
263
  })
264
264
  },
@@ -4,12 +4,12 @@ import { getFamilyImages, getAFamilyImage } from './family.js'
4
4
  import { YotoAPIError } from './helpers.js'
5
5
  import { loadTestTokens, logResponse } from './endpoint-test-helpers.js'
6
6
 
7
- const { accessToken } = loadTestTokens()
7
+ const { token } = loadTestTokens()
8
8
 
9
9
  test('getFamilyImages', async (t) => {
10
10
  await t.test('should fetch user family images', async () => {
11
11
  const response = await getFamilyImages({
12
- accessToken
12
+ accessToken: await token.getAccessToken()
13
13
  })
14
14
 
15
15
  // Log response for type verification and documentation
@@ -23,7 +23,7 @@ test('getFamilyImages', async (t) => {
23
23
  if (response.images.length > 0) {
24
24
  const image = response.images[0]
25
25
  assert.ok(image, 'Image should exist')
26
- assert.ok(typeof image.imageId === 'string', 'Image should have imageId string')
26
+ assert.equal(typeof image.imageId, 'string', 'Image should have imageId string')
27
27
  }
28
28
  })
29
29
 
@@ -51,7 +51,7 @@ test('getAFamilyImage', async (t) => {
51
51
  // Get real image IDs to test with
52
52
  await t.test('setup - get image IDs from family images', async () => {
53
53
  const response = await getFamilyImages({
54
- accessToken
54
+ accessToken: await token.getAccessToken()
55
55
  })
56
56
 
57
57
  if (response.images.length === 0) {
@@ -73,7 +73,7 @@ test('getAFamilyImage', async (t) => {
73
73
  assert.ok(imageId, 'Image ID should exist')
74
74
 
75
75
  const response = await getAFamilyImage({
76
- accessToken,
76
+ accessToken: await token.getAccessToken(),
77
77
  imageId,
78
78
  size: '640x480'
79
79
  })
@@ -83,7 +83,7 @@ test('getAFamilyImage', async (t) => {
83
83
 
84
84
  // Validate response structure matches YotoFamilyImageResponse
85
85
  assert.ok(response, 'Response should exist')
86
- assert.ok(typeof response.imageUrl === 'string', 'Response should have imageUrl string')
86
+ assert.equal(typeof response.imageUrl, 'string', 'Response should have imageUrl string')
87
87
  assert.ok(response.imageUrl.startsWith('http'), 'Image URL should be a valid URL')
88
88
  })
89
89
 
@@ -97,13 +97,13 @@ test('getAFamilyImage', async (t) => {
97
97
  assert.ok(imageId, 'Image ID should exist')
98
98
 
99
99
  const response = await getAFamilyImage({
100
- accessToken,
100
+ accessToken: await token.getAccessToken(),
101
101
  imageId,
102
102
  size: '640x480'
103
103
  })
104
104
 
105
105
  assert.ok(response, 'Response should exist')
106
- assert.ok(typeof response.imageUrl === 'string', 'Response should have imageUrl string')
106
+ assert.equal(typeof response.imageUrl, 'string', 'Response should have imageUrl string')
107
107
  assert.ok(response.imageUrl.startsWith('http'), 'Image URL should be a valid URL')
108
108
  })
109
109
 
@@ -117,13 +117,13 @@ test('getAFamilyImage', async (t) => {
117
117
  assert.ok(imageId, 'Image ID should exist')
118
118
 
119
119
  const response = await getAFamilyImage({
120
- accessToken,
120
+ accessToken: await token.getAccessToken(),
121
121
  imageId,
122
122
  size: '320x320'
123
123
  })
124
124
 
125
125
  assert.ok(response, 'Response should exist')
126
- assert.ok(typeof response.imageUrl === 'string', 'Response should have imageUrl string')
126
+ assert.equal(typeof response.imageUrl, 'string', 'Response should have imageUrl string')
127
127
  assert.ok(response.imageUrl.startsWith('http'), 'Image URL should be a valid URL')
128
128
  })
129
129
 
@@ -131,7 +131,7 @@ test('getAFamilyImage', async (t) => {
131
131
  await assert.rejects(
132
132
  async () => {
133
133
  await getAFamilyImage({
134
- accessToken,
134
+ accessToken: await token.getAccessToken(),
135
135
  imageId: 'invalid-image-id-12345',
136
136
  size: '640x480'
137
137
  })
@@ -4,12 +4,12 @@ import { getPublicIcons, getUserIcons } from './icons.js'
4
4
  import { YotoAPIError } from './helpers.js'
5
5
  import { loadTestTokens, logResponse } from './endpoint-test-helpers.js'
6
6
 
7
- const { accessToken } = loadTestTokens()
7
+ const { token } = loadTestTokens()
8
8
 
9
9
  test('getPublicIcons', async (t) => {
10
10
  await t.test('should fetch public display icons', async () => {
11
11
  const response = await getPublicIcons({
12
- accessToken
12
+ accessToken: await token.getAccessToken(),
13
13
  })
14
14
 
15
15
  // Log response for type verification and documentation
@@ -24,13 +24,13 @@ test('getPublicIcons', async (t) => {
24
24
  // Validate icon structure
25
25
  const icon = response.displayIcons[0]
26
26
  assert.ok(icon, 'Icon should exist')
27
- assert.ok(typeof icon.displayIconId === 'string', 'Icon should have displayIconId string')
28
- assert.ok(typeof icon.mediaId === 'string', 'Icon should have mediaId string')
29
- assert.ok(typeof icon.userId === 'string', 'Icon should have userId string')
27
+ assert.equal(typeof icon.displayIconId, 'string', 'Icon should have displayIconId string')
28
+ assert.equal(typeof icon.mediaId, 'string', 'Icon should have mediaId string')
29
+ assert.equal(typeof icon.userId, 'string', 'Icon should have userId string')
30
30
  assert.strictEqual(icon.userId, 'yoto', 'Public icon userId should be "yoto"')
31
- assert.ok(typeof icon.createdAt === 'string', 'Icon should have createdAt string')
32
- assert.ok(typeof icon.title === 'string', 'Icon should have title string')
33
- assert.ok(typeof icon.url === 'string', 'Icon should have url string')
31
+ assert.equal(typeof icon.createdAt, 'string', 'Icon should have createdAt string')
32
+ assert.equal(typeof icon.title, 'string', 'Icon should have title string')
33
+ assert.equal(typeof icon.url, 'string', 'Icon should have url string')
34
34
  assert.ok(icon.url.startsWith('http'), 'Icon URL should be a valid URL')
35
35
  assert.strictEqual(icon.public, true, 'Public icon should have public=true')
36
36
  // Note: new field may not always be present in public icons
@@ -60,7 +60,7 @@ test('getPublicIcons', async (t) => {
60
60
  test('getUserIcons', async (t) => {
61
61
  await t.test('should fetch user custom icons', async () => {
62
62
  const response = await getUserIcons({
63
- accessToken
63
+ accessToken: await token.getAccessToken()
64
64
  })
65
65
 
66
66
  // Log response for type verification and documentation
@@ -75,11 +75,11 @@ test('getUserIcons', async (t) => {
75
75
  if (response.displayIcons.length > 0) {
76
76
  const icon = response.displayIcons[0]
77
77
  assert.ok(icon, 'Icon should exist')
78
- assert.ok(typeof icon.displayIconId === 'string', 'Icon should have displayIconId string')
79
- assert.ok(typeof icon.mediaId === 'string', 'Icon should have mediaId string')
80
- assert.ok(typeof icon.userId === 'string', 'Icon should have userId string')
81
- assert.ok(typeof icon.createdAt === 'string', 'Icon should have createdAt string')
82
- assert.ok(typeof icon.url === 'string', 'Icon should have url string')
78
+ assert.equal(typeof icon.displayIconId, 'string', 'Icon should have displayIconId string')
79
+ assert.equal(typeof icon.mediaId, 'string', 'Icon should have mediaId string')
80
+ assert.equal(typeof icon.userId, 'string', 'Icon should have userId string')
81
+ assert.equal(typeof icon.createdAt, 'string', 'Icon should have createdAt string')
82
+ assert.equal(typeof icon.url, 'string', 'Icon should have url string')
83
83
  assert.strictEqual(icon.public, false, 'User icon should have public=false')
84
84
  assert.strictEqual('title' in icon, false, 'User icon should not have title')
85
85
  assert.strictEqual('publicTags' in icon, false, 'User icon should not have publicTags')