edilkamin 1.6.2 → 1.7.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.
@@ -8,7 +8,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { strict as assert } from "assert";
11
- import axios from "axios";
12
11
  import pako from "pako";
13
12
  import sinon from "sinon";
14
13
  import { configure, createAuthService } from "../src/library";
@@ -24,15 +23,20 @@ const createGzippedBuffer = (data) => {
24
23
  data: Array.from(compressed),
25
24
  };
26
25
  };
26
+ /**
27
+ * Helper to create a mock Response object for fetch.
28
+ */
29
+ const mockResponse = (data, status = 200) => ({
30
+ ok: status >= 200 && status < 300,
31
+ status,
32
+ statusText: status >= 200 && status < 300 ? "OK" : "Error",
33
+ json: () => Promise.resolve(data),
34
+ });
27
35
  describe("library", () => {
28
- let axiosStub;
36
+ let fetchStub;
29
37
  const expectedToken = "mockJwtToken";
30
38
  beforeEach(() => {
31
- axiosStub = sinon.stub(axios, "create").returns({
32
- get: sinon.stub(),
33
- put: sinon.stub(),
34
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
- });
39
+ fetchStub = sinon.stub(globalThis, "fetch");
36
40
  });
37
41
  afterEach(() => {
38
42
  sinon.restore();
@@ -81,8 +85,7 @@ describe("library", () => {
81
85
  };
82
86
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
83
87
  const authService = createAuthService(authStub);
84
- const token = yield authService.signIn(expectedUsername, expectedPassword, true // legacy mode
85
- );
88
+ const token = yield authService.signIn(expectedUsername, expectedPassword, true);
86
89
  assert.equal(token, expectedToken);
87
90
  }));
88
91
  it("should throw an error if sign-in fails", () => __awaiter(void 0, void 0, void 0, function* () {
@@ -108,6 +111,68 @@ describe("library", () => {
108
111
  });
109
112
  }));
110
113
  });
114
+ describe("getSession", () => {
115
+ it("should return idToken by default", () => __awaiter(void 0, void 0, void 0, function* () {
116
+ const mockAuth = {
117
+ signIn: sinon.stub().resolves({ isSignedIn: true }),
118
+ signOut: sinon.stub().resolves(),
119
+ fetchAuthSession: sinon.stub().resolves({
120
+ tokens: {
121
+ idToken: { toString: () => "mock-id-token" },
122
+ accessToken: { toString: () => "mock-access-token" },
123
+ },
124
+ }),
125
+ };
126
+ const { getSession, signIn } = createAuthService(mockAuth);
127
+ yield signIn("user", "pass");
128
+ const token = yield getSession();
129
+ assert.equal(token, "mock-id-token");
130
+ }));
131
+ it("should return accessToken when legacy=true", () => __awaiter(void 0, void 0, void 0, function* () {
132
+ const mockAuth = {
133
+ signIn: sinon.stub().resolves({ isSignedIn: true }),
134
+ signOut: sinon.stub().resolves(),
135
+ fetchAuthSession: sinon.stub().resolves({
136
+ tokens: {
137
+ idToken: { toString: () => "mock-id-token" },
138
+ accessToken: { toString: () => "mock-access-token" },
139
+ },
140
+ }),
141
+ };
142
+ const { getSession, signIn } = createAuthService(mockAuth);
143
+ yield signIn("user", "pass");
144
+ const token = yield getSession(false, true);
145
+ assert.equal(token, "mock-access-token");
146
+ }));
147
+ it("should throw error when no session exists", () => __awaiter(void 0, void 0, void 0, function* () {
148
+ const mockAuth = {
149
+ signIn: sinon.stub().resolves({ isSignedIn: true }),
150
+ signOut: sinon.stub().resolves(),
151
+ fetchAuthSession: sinon.stub().resolves({ tokens: null }),
152
+ };
153
+ const { getSession } = createAuthService(mockAuth);
154
+ yield assert.rejects(() => __awaiter(void 0, void 0, void 0, function* () { return getSession(); }), {
155
+ name: "AssertionError",
156
+ message: "No session found - please sign in first",
157
+ });
158
+ }));
159
+ it("should pass forceRefresh to fetchAuthSession", () => __awaiter(void 0, void 0, void 0, function* () {
160
+ const mockAuth = {
161
+ signIn: sinon.stub().resolves({ isSignedIn: true }),
162
+ signOut: sinon.stub().resolves(),
163
+ fetchAuthSession: sinon.stub().resolves({
164
+ tokens: {
165
+ idToken: { toString: () => "mock-id-token" },
166
+ accessToken: { toString: () => "mock-access-token" },
167
+ },
168
+ }),
169
+ };
170
+ const { getSession, signIn } = createAuthService(mockAuth);
171
+ yield signIn("user", "pass");
172
+ yield getSession(true);
173
+ assert.ok(mockAuth.fetchAuthSession.calledWith({ forceRefresh: true }));
174
+ }));
175
+ });
111
176
  describe("configure", () => {
112
177
  const expectedApi = [
113
178
  "deviceInfo",
@@ -121,29 +186,25 @@ describe("library", () => {
121
186
  "getTargetTemperature",
122
187
  "setTargetTemperature",
123
188
  ];
124
- it("should create API methods with the correct baseURL", () => {
125
- const baseURL = "https://example.com/api";
189
+ it("should create API methods with the correct baseURL", () => __awaiter(void 0, void 0, void 0, function* () {
190
+ const baseURL = "https://example.com/api/";
191
+ fetchStub.resolves(mockResponse({ test: "data" }));
126
192
  const api = configure(baseURL);
127
- assert.deepEqual(axiosStub.args, [
128
- [
129
- {
130
- baseURL,
131
- },
132
- ],
133
- ]);
134
193
  assert.deepEqual(Object.keys(api), expectedApi);
135
- });
136
- it("should create API methods with the default baseURL", () => {
194
+ // Verify baseURL is used when making a request
195
+ yield api.deviceInfo(expectedToken, "mockMac");
196
+ assert.ok(fetchStub.calledOnce);
197
+ assert.ok(fetchStub.firstCall.args[0].startsWith(baseURL));
198
+ }));
199
+ it("should create API methods with the default baseURL", () => __awaiter(void 0, void 0, void 0, function* () {
200
+ fetchStub.resolves(mockResponse({ test: "data" }));
137
201
  const api = configure();
138
- assert.deepEqual(axiosStub.args, [
139
- [
140
- {
141
- baseURL: API_URL,
142
- },
143
- ],
144
- ]);
145
202
  assert.deepEqual(Object.keys(api), expectedApi);
146
- });
203
+ // Verify default baseURL is used when making a request
204
+ yield api.deviceInfo(expectedToken, "mockMac");
205
+ assert.ok(fetchStub.calledOnce);
206
+ assert.ok(fetchStub.firstCall.args[0].startsWith(API_URL));
207
+ }));
147
208
  });
148
209
  describe("API Methods", () => {
149
210
  const mockDeviceInfo = {
@@ -161,19 +222,16 @@ describe("library", () => {
161
222
  },
162
223
  },
163
224
  };
164
- it("should call axios for deviceInfo", () => __awaiter(void 0, void 0, void 0, function* () {
165
- const mockAxios = {
166
- get: sinon.stub().resolves({ data: mockDeviceInfo }),
167
- };
168
- axiosStub.returns(mockAxios);
169
- const api = configure("https://example.com/api");
225
+ it("should call fetch for deviceInfo", () => __awaiter(void 0, void 0, void 0, function* () {
226
+ fetchStub.resolves(mockResponse(mockDeviceInfo));
227
+ const api = configure("https://example.com/api/");
170
228
  const result = yield api.deviceInfo(expectedToken, "mockMacAddress");
171
- assert.deepEqual(mockAxios.get.args, [
172
- [
173
- "device/mockMacAddress/info",
174
- { headers: { Authorization: `Bearer ${expectedToken}` } },
175
- ],
176
- ]);
229
+ assert.ok(fetchStub.calledOnce);
230
+ assert.equal(fetchStub.firstCall.args[0], "https://example.com/api/device/mockMacAddress/info");
231
+ assert.deepEqual(fetchStub.firstCall.args[1], {
232
+ method: "GET",
233
+ headers: { Authorization: `Bearer ${expectedToken}` },
234
+ });
177
235
  assert.deepEqual(result, mockDeviceInfo);
178
236
  }));
179
237
  // Tests for setPowerOn and setPowerOff
@@ -189,28 +247,25 @@ describe("library", () => {
189
247
  expectedValue: 0,
190
248
  },
191
249
  ].forEach(({ method, call, expectedValue }) => {
192
- it(`should call axios for ${method}`, () => __awaiter(void 0, void 0, void 0, function* () {
193
- const mockAxios = {
194
- put: sinon.stub().resolves({ status: 200 }),
195
- };
196
- axiosStub.returns(mockAxios);
197
- const api = configure("https://example.com/api");
250
+ it(`should call fetch for ${method}`, () => __awaiter(void 0, void 0, void 0, function* () {
251
+ fetchStub.resolves(mockResponse({ success: true }));
252
+ const api = configure("https://example.com/api/");
198
253
  // Invoke the method using the mapped call function
199
- const result = yield call(api);
200
- assert.deepEqual(mockAxios.put.args, [
201
- [
202
- "mqtt/command",
203
- {
204
- mac_address: "mockMacAddress",
205
- name: "power",
206
- value: expectedValue,
207
- },
208
- {
209
- headers: { Authorization: "Bearer mockToken" },
210
- },
211
- ],
212
- ]);
213
- assert.equal(result.status, 200);
254
+ yield call(api);
255
+ assert.ok(fetchStub.calledOnce);
256
+ assert.equal(fetchStub.firstCall.args[0], "https://example.com/api/mqtt/command");
257
+ assert.deepEqual(fetchStub.firstCall.args[1], {
258
+ method: "PUT",
259
+ headers: {
260
+ "Content-Type": "application/json",
261
+ Authorization: "Bearer mockToken",
262
+ },
263
+ body: JSON.stringify({
264
+ mac_address: "mockMacAddress",
265
+ name: "power",
266
+ value: expectedValue,
267
+ }),
268
+ });
214
269
  }));
215
270
  });
216
271
  const getterTests = [
@@ -231,19 +286,16 @@ describe("library", () => {
231
286
  },
232
287
  ];
233
288
  getterTests.forEach(({ method, call, expectedResult }) => {
234
- it(`should call axios and return the correct value for ${method}`, () => __awaiter(void 0, void 0, void 0, function* () {
235
- const mockAxios = {
236
- get: sinon.stub().resolves({ data: mockDeviceInfo }),
237
- };
238
- axiosStub.returns(mockAxios);
239
- const api = configure("https://example.com/api");
289
+ it(`should call fetch and return the correct value for ${method}`, () => __awaiter(void 0, void 0, void 0, function* () {
290
+ fetchStub.resolves(mockResponse(mockDeviceInfo));
291
+ const api = configure("https://example.com/api/");
240
292
  const result = yield call(api, expectedToken, "mockMacAddress");
241
- assert.deepEqual(mockAxios.get.args, [
242
- [
243
- "device/mockMacAddress/info",
244
- { headers: { Authorization: `Bearer ${expectedToken}` } },
245
- ],
246
- ]);
293
+ assert.ok(fetchStub.calledOnce);
294
+ assert.equal(fetchStub.firstCall.args[0], "https://example.com/api/device/mockMacAddress/info");
295
+ assert.deepEqual(fetchStub.firstCall.args[1], {
296
+ method: "GET",
297
+ headers: { Authorization: `Bearer ${expectedToken}` },
298
+ });
247
299
  assert.equal(result, expectedResult);
248
300
  }));
249
301
  });
@@ -259,119 +311,100 @@ describe("library", () => {
259
311
  },
260
312
  ];
261
313
  setterTests.forEach(({ method, call, payload }) => {
262
- it(`should call axios and send the correct payload for ${method}`, () => __awaiter(void 0, void 0, void 0, function* () {
263
- const mockAxios = {
264
- put: sinon.stub().resolves({ status: 200 }),
265
- };
266
- axiosStub.returns(mockAxios);
267
- const api = configure("https://example.com/api");
268
- const result = yield call(api, expectedToken, "mockMacAddress", payload.value);
269
- assert.deepEqual(mockAxios.put.args, [
270
- [
271
- "mqtt/command",
272
- Object.assign({ mac_address: "mockMacAddress" }, payload),
273
- {
274
- headers: { Authorization: `Bearer ${expectedToken}` },
275
- },
276
- ],
277
- ]);
278
- assert.equal(result.status, 200);
314
+ it(`should call fetch and send the correct payload for ${method}`, () => __awaiter(void 0, void 0, void 0, function* () {
315
+ fetchStub.resolves(mockResponse({ success: true }));
316
+ const api = configure("https://example.com/api/");
317
+ yield call(api, expectedToken, "mockMacAddress", payload.value);
318
+ assert.ok(fetchStub.calledOnce);
319
+ assert.equal(fetchStub.firstCall.args[0], "https://example.com/api/mqtt/command");
320
+ assert.deepEqual(fetchStub.firstCall.args[1], {
321
+ method: "PUT",
322
+ headers: {
323
+ "Content-Type": "application/json",
324
+ Authorization: `Bearer ${expectedToken}`,
325
+ },
326
+ body: JSON.stringify(Object.assign({ mac_address: "mockMacAddress" }, payload)),
327
+ });
279
328
  }));
280
329
  });
281
330
  });
282
331
  describe("registerDevice", () => {
283
332
  it("should call POST /device with correct payload", () => __awaiter(void 0, void 0, void 0, function* () {
284
- const mockResponse = {
333
+ const mockResponseData = {
285
334
  macAddress: "AABBCCDDEEFF",
286
335
  deviceName: "Test Stove",
287
336
  deviceRoom: "Living Room",
288
337
  serialNumber: "EDK123",
289
338
  };
290
- const mockAxios = {
291
- post: sinon.stub().resolves({ data: mockResponse }),
292
- get: sinon.stub(),
293
- put: sinon.stub(),
294
- };
295
- axiosStub.returns(mockAxios);
296
- const api = configure("https://example.com/api");
339
+ fetchStub.resolves(mockResponse(mockResponseData));
340
+ const api = configure("https://example.com/api/");
297
341
  const result = yield api.registerDevice(expectedToken, "AA:BB:CC:DD:EE:FF", "EDK123", "Test Stove", "Living Room");
298
- assert.deepEqual(mockAxios.post.args, [
299
- [
300
- "device",
301
- {
302
- macAddress: "AABBCCDDEEFF",
303
- deviceName: "Test Stove",
304
- deviceRoom: "Living Room",
305
- serialNumber: "EDK123",
306
- },
307
- { headers: { Authorization: `Bearer ${expectedToken}` } },
308
- ],
309
- ]);
310
- assert.deepEqual(result, mockResponse);
342
+ assert.ok(fetchStub.calledOnce);
343
+ assert.equal(fetchStub.firstCall.args[0], "https://example.com/api/device");
344
+ assert.deepEqual(fetchStub.firstCall.args[1], {
345
+ method: "POST",
346
+ headers: {
347
+ "Content-Type": "application/json",
348
+ Authorization: `Bearer ${expectedToken}`,
349
+ },
350
+ body: JSON.stringify({
351
+ macAddress: "AABBCCDDEEFF",
352
+ deviceName: "Test Stove",
353
+ deviceRoom: "Living Room",
354
+ serialNumber: "EDK123",
355
+ }),
356
+ });
357
+ assert.deepEqual(result, mockResponseData);
311
358
  }));
312
359
  it("should normalize MAC address by removing colons", () => __awaiter(void 0, void 0, void 0, function* () {
313
- const mockAxios = {
314
- post: sinon.stub().resolves({ data: {} }),
315
- get: sinon.stub(),
316
- put: sinon.stub(),
317
- };
318
- axiosStub.returns(mockAxios);
319
- const api = configure("https://example.com/api");
360
+ fetchStub.resolves(mockResponse({}));
361
+ const api = configure("https://example.com/api/");
320
362
  yield api.registerDevice(expectedToken, "AA:BB:CC:DD:EE:FF", "EDK123");
321
- assert.equal(mockAxios.post.args[0][1].macAddress, "AABBCCDDEEFF");
363
+ const body = JSON.parse(fetchStub.firstCall.args[1].body);
364
+ assert.equal(body.macAddress, "AABBCCDDEEFF");
322
365
  }));
323
366
  it("should use empty strings as defaults for name and room", () => __awaiter(void 0, void 0, void 0, function* () {
324
- const mockAxios = {
325
- post: sinon.stub().resolves({ data: {} }),
326
- get: sinon.stub(),
327
- put: sinon.stub(),
328
- };
329
- axiosStub.returns(mockAxios);
330
- const api = configure("https://example.com/api");
367
+ fetchStub.resolves(mockResponse({}));
368
+ const api = configure("https://example.com/api/");
331
369
  yield api.registerDevice(expectedToken, "AABBCCDDEEFF", "EDK123");
332
- assert.equal(mockAxios.post.args[0][1].deviceName, "");
333
- assert.equal(mockAxios.post.args[0][1].deviceRoom, "");
370
+ const body = JSON.parse(fetchStub.firstCall.args[1].body);
371
+ assert.equal(body.deviceName, "");
372
+ assert.equal(body.deviceRoom, "");
334
373
  }));
335
374
  });
336
375
  describe("editDevice", () => {
337
376
  it("should call PUT /device/{mac} with correct payload", () => __awaiter(void 0, void 0, void 0, function* () {
338
- const mockResponse = {
377
+ const mockResponseData = {
339
378
  macAddress: "AABBCCDDEEFF",
340
379
  deviceName: "Updated Name",
341
380
  deviceRoom: "Basement",
342
381
  serialNumber: "EDK123",
343
382
  };
344
- const mockAxios = {
345
- put: sinon.stub().resolves({ data: mockResponse }),
346
- get: sinon.stub(),
347
- post: sinon.stub(),
348
- };
349
- axiosStub.returns(mockAxios);
350
- const api = configure("https://example.com/api");
383
+ fetchStub.resolves(mockResponse(mockResponseData));
384
+ const api = configure("https://example.com/api/");
351
385
  const result = yield api.editDevice(expectedToken, "AA:BB:CC:DD:EE:FF", "Updated Name", "Basement");
352
- assert.deepEqual(mockAxios.put.args, [
353
- [
354
- "device/AABBCCDDEEFF",
355
- {
356
- deviceName: "Updated Name",
357
- deviceRoom: "Basement",
358
- },
359
- { headers: { Authorization: `Bearer ${expectedToken}` } },
360
- ],
361
- ]);
362
- assert.deepEqual(result, mockResponse);
386
+ assert.ok(fetchStub.calledOnce);
387
+ assert.equal(fetchStub.firstCall.args[0], "https://example.com/api/device/AABBCCDDEEFF");
388
+ assert.deepEqual(fetchStub.firstCall.args[1], {
389
+ method: "PUT",
390
+ headers: {
391
+ "Content-Type": "application/json",
392
+ Authorization: `Bearer ${expectedToken}`,
393
+ },
394
+ body: JSON.stringify({
395
+ deviceName: "Updated Name",
396
+ deviceRoom: "Basement",
397
+ }),
398
+ });
399
+ assert.deepEqual(result, mockResponseData);
363
400
  }));
364
401
  it("should use empty strings as defaults for name and room", () => __awaiter(void 0, void 0, void 0, function* () {
365
- const mockAxios = {
366
- put: sinon.stub().resolves({ data: {} }),
367
- get: sinon.stub(),
368
- post: sinon.stub(),
369
- };
370
- axiosStub.returns(mockAxios);
371
- const api = configure("https://example.com/api");
402
+ fetchStub.resolves(mockResponse({}));
403
+ const api = configure("https://example.com/api/");
372
404
  yield api.editDevice(expectedToken, "AABBCCDDEEFF");
373
- assert.equal(mockAxios.put.args[0][1].deviceName, "");
374
- assert.equal(mockAxios.put.args[0][1].deviceRoom, "");
405
+ const body = JSON.parse(fetchStub.firstCall.args[1].body);
406
+ assert.equal(body.deviceName, "");
407
+ assert.equal(body.deviceRoom, "");
375
408
  }));
376
409
  });
377
410
  describe("deviceInfo with compressed responses", () => {
@@ -380,7 +413,7 @@ describe("library", () => {
380
413
  commands: { power: true },
381
414
  temperatures: { enviroment: 19, board: 25 },
382
415
  };
383
- const mockResponse = {
416
+ const mockResponseData = {
384
417
  status: createGzippedBuffer(statusData),
385
418
  nvm: {
386
419
  user_parameters: {
@@ -388,11 +421,8 @@ describe("library", () => {
388
421
  },
389
422
  },
390
423
  };
391
- const mockAxios = {
392
- get: sinon.stub().resolves({ data: mockResponse }),
393
- };
394
- axiosStub.returns(mockAxios);
395
- const api = configure("https://example.com/api");
424
+ fetchStub.resolves(mockResponse(mockResponseData));
425
+ const api = configure("https://example.com/api/");
396
426
  const result = yield api.deviceInfo(expectedToken, "mockMacAddress");
397
427
  assert.deepEqual(result.status, statusData);
398
428
  }));
@@ -406,18 +436,15 @@ describe("library", () => {
406
436
  is_sound_active: true,
407
437
  },
408
438
  };
409
- const mockResponse = {
439
+ const mockResponseData = {
410
440
  status: {
411
441
  commands: { power: true },
412
442
  temperatures: { enviroment: 19 },
413
443
  },
414
444
  nvm: createGzippedBuffer(nvmData),
415
445
  };
416
- const mockAxios = {
417
- get: sinon.stub().resolves({ data: mockResponse }),
418
- };
419
- axiosStub.returns(mockAxios);
420
- const api = configure("https://example.com/api");
446
+ fetchStub.resolves(mockResponse(mockResponseData));
447
+ const api = configure("https://example.com/api/");
421
448
  const result = yield api.deviceInfo(expectedToken, "mockMacAddress");
422
449
  assert.deepEqual(result.nvm, nvmData);
423
450
  }));
@@ -435,15 +462,12 @@ describe("library", () => {
435
462
  is_sound_active: false,
436
463
  },
437
464
  };
438
- const mockResponse = {
465
+ const mockResponseData = {
439
466
  status: createGzippedBuffer(statusData),
440
467
  nvm: createGzippedBuffer(nvmData),
441
468
  };
442
- const mockAxios = {
443
- get: sinon.stub().resolves({ data: mockResponse }),
444
- };
445
- axiosStub.returns(mockAxios);
446
- const api = configure("https://example.com/api");
469
+ fetchStub.resolves(mockResponse(mockResponseData));
470
+ const api = configure("https://example.com/api/");
447
471
  const result = yield api.deviceInfo(expectedToken, "mockMacAddress");
448
472
  assert.deepEqual(result.status, statusData);
449
473
  assert.deepEqual(result.nvm, nvmData);
@@ -453,15 +477,12 @@ describe("library", () => {
453
477
  commands: { power: true },
454
478
  temperatures: { enviroment: 19 },
455
479
  };
456
- const mockResponse = {
480
+ const mockResponseData = {
457
481
  status: createGzippedBuffer(statusData),
458
482
  nvm: { user_parameters: { enviroment_1_temperature: 22 } },
459
483
  };
460
- const mockAxios = {
461
- get: sinon.stub().resolves({ data: mockResponse }),
462
- };
463
- axiosStub.returns(mockAxios);
464
- const api = configure("https://example.com/api");
484
+ fetchStub.resolves(mockResponse(mockResponseData));
485
+ const api = configure("https://example.com/api/");
465
486
  const result = yield api.getPower(expectedToken, "mockMacAddress");
466
487
  assert.equal(result, true);
467
488
  }));
@@ -470,15 +491,12 @@ describe("library", () => {
470
491
  commands: { power: true },
471
492
  temperatures: { enviroment: 19, board: 25 },
472
493
  };
473
- const mockResponse = {
494
+ const mockResponseData = {
474
495
  status: createGzippedBuffer(statusData),
475
496
  nvm: { user_parameters: { enviroment_1_temperature: 22 } },
476
497
  };
477
- const mockAxios = {
478
- get: sinon.stub().resolves({ data: mockResponse }),
479
- };
480
- axiosStub.returns(mockAxios);
481
- const api = configure("https://example.com/api");
498
+ fetchStub.resolves(mockResponse(mockResponseData));
499
+ const api = configure("https://example.com/api/");
482
500
  const result = yield api.getEnvironmentTemperature(expectedToken, "mockMacAddress");
483
501
  assert.equal(result, 19);
484
502
  }));
@@ -488,17 +506,37 @@ describe("library", () => {
488
506
  enviroment_1_temperature: 22,
489
507
  },
490
508
  };
491
- const mockResponse = {
509
+ const mockResponseData = {
492
510
  status: { commands: { power: true }, temperatures: { enviroment: 19 } },
493
511
  nvm: createGzippedBuffer(nvmData),
494
512
  };
495
- const mockAxios = {
496
- get: sinon.stub().resolves({ data: mockResponse }),
497
- };
498
- axiosStub.returns(mockAxios);
499
- const api = configure("https://example.com/api");
513
+ fetchStub.resolves(mockResponse(mockResponseData));
514
+ const api = configure("https://example.com/api/");
500
515
  const result = yield api.getTargetTemperature(expectedToken, "mockMacAddress");
501
516
  assert.equal(result, 22);
502
517
  }));
503
518
  });
519
+ describe("Error Handling", () => {
520
+ const errorTests = [
521
+ { status: 400, statusText: "Bad Request" },
522
+ { status: 401, statusText: "Unauthorized" },
523
+ { status: 404, statusText: "Not Found" },
524
+ { status: 500, statusText: "Internal Server Error" },
525
+ ];
526
+ errorTests.forEach(({ status, statusText }) => {
527
+ it(`should throw error when fetch returns ${status}`, () => __awaiter(void 0, void 0, void 0, function* () {
528
+ const errorResponse = {
529
+ ok: false,
530
+ status,
531
+ statusText,
532
+ json: () => Promise.resolve({ error: statusText }),
533
+ };
534
+ fetchStub.resolves(errorResponse);
535
+ const api = configure("https://example.com/api/");
536
+ yield assert.rejects(() => __awaiter(void 0, void 0, void 0, function* () { return api.deviceInfo(expectedToken, "mockMac"); }), {
537
+ message: `HTTP ${status}: ${statusText}`,
538
+ });
539
+ }));
540
+ });
541
+ });
504
542
  });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Custom storage adapter for AWS Amplify that persists to file system.
3
+ * Used for CLI to maintain sessions between invocations.
4
+ */
5
+ export declare const createFileStorage: () => {
6
+ setItem: (key: string, value: string) => Promise<void>;
7
+ getItem: (key: string) => Promise<string | null>;
8
+ removeItem: (key: string) => Promise<void>;
9
+ clear: () => Promise<void>;
10
+ };
11
+ /**
12
+ * Clears all stored session data.
13
+ */
14
+ export declare const clearSession: () => Promise<void>;