edilkamin 1.7.2 → 1.7.4
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/.github/workflows/cli-tests.yml +6 -0
- package/.github/workflows/publish.yml +1 -1
- package/README.md +1 -1
- package/dist/cjs/package.json +84 -0
- package/dist/cjs/src/browser-bundle.test.js +64 -0
- package/dist/cjs/src/buffer-utils.js +78 -0
- package/dist/cjs/src/buffer-utils.test.js +186 -0
- package/dist/cjs/src/cli.js +253 -0
- package/dist/cjs/src/configureAmplify.test.js +42 -0
- package/dist/cjs/src/constants.js +9 -0
- package/dist/{esm → cjs/src}/index.d.ts +1 -2
- package/dist/cjs/src/index.js +22 -0
- package/dist/{esm → cjs/src}/library.d.ts +4 -4
- package/dist/cjs/src/library.js +324 -0
- package/dist/cjs/src/library.test.js +547 -0
- package/dist/cjs/src/serial-utils.js +50 -0
- package/dist/cjs/src/serial-utils.test.d.ts +1 -0
- package/dist/cjs/src/serial-utils.test.js +50 -0
- package/dist/cjs/src/token-storage.js +119 -0
- package/dist/cjs/src/types.js +2 -0
- package/dist/esm/package.json +84 -0
- package/dist/esm/src/browser-bundle.test.d.ts +1 -0
- package/dist/esm/src/browser-bundle.test.js +29 -0
- package/dist/esm/src/buffer-utils.d.ts +25 -0
- package/dist/esm/src/buffer-utils.test.d.ts +1 -0
- package/dist/esm/src/cli.d.ts +3 -0
- package/dist/esm/src/configureAmplify.test.d.ts +1 -0
- package/dist/esm/src/configureAmplify.test.js +37 -0
- package/dist/esm/src/constants.d.ts +4 -0
- package/dist/esm/src/index.d.ts +6 -0
- package/dist/esm/{index.js → src/index.js} +0 -1
- package/dist/esm/src/library.d.ts +55 -0
- package/dist/esm/{library.js → src/library.js} +59 -51
- package/dist/esm/src/library.test.d.ts +1 -0
- package/dist/esm/{library.test.js → src/library.test.js} +167 -190
- package/dist/esm/src/serial-utils.d.ts +33 -0
- package/dist/esm/src/serial-utils.test.d.ts +1 -0
- package/dist/esm/src/token-storage.d.ts +14 -0
- package/dist/esm/src/types.d.ts +73 -0
- package/dist/esm/src/types.js +1 -0
- package/package.json +19 -7
- package/src/browser-bundle.test.ts +21 -0
- package/src/configureAmplify.test.ts +47 -0
- package/src/index.ts +0 -1
- package/src/library.test.ts +195 -197
- package/src/library.ts +76 -62
- package/tsconfig.cjs.json +2 -2
- package/tsconfig.json +2 -3
- /package/dist/{esm/buffer-utils.test.d.ts → cjs/src/browser-bundle.test.d.ts} +0 -0
- /package/dist/{esm → cjs/src}/buffer-utils.d.ts +0 -0
- /package/dist/{esm/library.test.d.ts → cjs/src/buffer-utils.test.d.ts} +0 -0
- /package/dist/{esm → cjs/src}/cli.d.ts +0 -0
- /package/dist/{esm/serial-utils.test.d.ts → cjs/src/configureAmplify.test.d.ts} +0 -0
- /package/dist/{esm → cjs/src}/constants.d.ts +0 -0
- /package/dist/{esm/types.js → cjs/src/library.test.d.ts} +0 -0
- /package/dist/{esm → cjs/src}/serial-utils.d.ts +0 -0
- /package/dist/{esm → cjs/src}/token-storage.d.ts +0 -0
- /package/dist/{esm → cjs/src}/types.d.ts +0 -0
- /package/dist/esm/{buffer-utils.js → src/buffer-utils.js} +0 -0
- /package/dist/esm/{buffer-utils.test.js → src/buffer-utils.test.js} +0 -0
- /package/dist/esm/{cli.js → src/cli.js} +0 -0
- /package/dist/esm/{constants.js → src/constants.js} +0 -0
- /package/dist/esm/{serial-utils.js → src/serial-utils.js} +0 -0
- /package/dist/esm/{serial-utils.test.js → src/serial-utils.test.js} +0 -0
- /package/dist/esm/{token-storage.js → src/token-storage.js} +0 -0
|
@@ -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
|
|
36
|
+
let fetchStub;
|
|
29
37
|
const expectedToken = "mockJwtToken";
|
|
30
38
|
beforeEach(() => {
|
|
31
|
-
|
|
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();
|
|
@@ -182,29 +186,25 @@ describe("library", () => {
|
|
|
182
186
|
"getTargetTemperature",
|
|
183
187
|
"setTargetTemperature",
|
|
184
188
|
];
|
|
185
|
-
it("should create API methods with the correct baseURL", () => {
|
|
186
|
-
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" }));
|
|
187
192
|
const api = configure(baseURL);
|
|
188
|
-
assert.deepEqual(axiosStub.args, [
|
|
189
|
-
[
|
|
190
|
-
{
|
|
191
|
-
baseURL,
|
|
192
|
-
},
|
|
193
|
-
],
|
|
194
|
-
]);
|
|
195
193
|
assert.deepEqual(Object.keys(api), expectedApi);
|
|
196
|
-
|
|
197
|
-
|
|
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" }));
|
|
198
201
|
const api = configure();
|
|
199
|
-
assert.deepEqual(axiosStub.args, [
|
|
200
|
-
[
|
|
201
|
-
{
|
|
202
|
-
baseURL: API_URL,
|
|
203
|
-
},
|
|
204
|
-
],
|
|
205
|
-
]);
|
|
206
202
|
assert.deepEqual(Object.keys(api), expectedApi);
|
|
207
|
-
|
|
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
|
+
}));
|
|
208
208
|
});
|
|
209
209
|
describe("API Methods", () => {
|
|
210
210
|
const mockDeviceInfo = {
|
|
@@ -222,19 +222,16 @@ describe("library", () => {
|
|
|
222
222
|
},
|
|
223
223
|
},
|
|
224
224
|
};
|
|
225
|
-
it("should call
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
};
|
|
229
|
-
axiosStub.returns(mockAxios);
|
|
230
|
-
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/");
|
|
231
228
|
const result = yield api.deviceInfo(expectedToken, "mockMacAddress");
|
|
232
|
-
assert.
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
|
+
});
|
|
238
235
|
assert.deepEqual(result, mockDeviceInfo);
|
|
239
236
|
}));
|
|
240
237
|
// Tests for setPowerOn and setPowerOff
|
|
@@ -250,28 +247,25 @@ describe("library", () => {
|
|
|
250
247
|
expectedValue: 0,
|
|
251
248
|
},
|
|
252
249
|
].forEach(({ method, call, expectedValue }) => {
|
|
253
|
-
it(`should call
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
};
|
|
257
|
-
axiosStub.returns(mockAxios);
|
|
258
|
-
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/");
|
|
259
253
|
// Invoke the method using the mapped call function
|
|
260
|
-
|
|
261
|
-
assert.
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
+
});
|
|
275
269
|
}));
|
|
276
270
|
});
|
|
277
271
|
const getterTests = [
|
|
@@ -292,19 +286,16 @@ describe("library", () => {
|
|
|
292
286
|
},
|
|
293
287
|
];
|
|
294
288
|
getterTests.forEach(({ method, call, expectedResult }) => {
|
|
295
|
-
it(`should call
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
};
|
|
299
|
-
axiosStub.returns(mockAxios);
|
|
300
|
-
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/");
|
|
301
292
|
const result = yield call(api, expectedToken, "mockMacAddress");
|
|
302
|
-
assert.
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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
|
+
});
|
|
308
299
|
assert.equal(result, expectedResult);
|
|
309
300
|
}));
|
|
310
301
|
});
|
|
@@ -320,119 +311,100 @@ describe("library", () => {
|
|
|
320
311
|
},
|
|
321
312
|
];
|
|
322
313
|
setterTests.forEach(({ method, call, payload }) => {
|
|
323
|
-
it(`should call
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
"
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
],
|
|
338
|
-
]);
|
|
339
|
-
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
|
+
});
|
|
340
328
|
}));
|
|
341
329
|
});
|
|
342
330
|
});
|
|
343
331
|
describe("registerDevice", () => {
|
|
344
332
|
it("should call POST /device with correct payload", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
345
|
-
const
|
|
333
|
+
const mockResponseData = {
|
|
346
334
|
macAddress: "AABBCCDDEEFF",
|
|
347
335
|
deviceName: "Test Stove",
|
|
348
336
|
deviceRoom: "Living Room",
|
|
349
337
|
serialNumber: "EDK123",
|
|
350
338
|
};
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
get: sinon.stub(),
|
|
354
|
-
put: sinon.stub(),
|
|
355
|
-
};
|
|
356
|
-
axiosStub.returns(mockAxios);
|
|
357
|
-
const api = configure("https://example.com/api");
|
|
339
|
+
fetchStub.resolves(mockResponse(mockResponseData));
|
|
340
|
+
const api = configure("https://example.com/api/");
|
|
358
341
|
const result = yield api.registerDevice(expectedToken, "AA:BB:CC:DD:EE:FF", "EDK123", "Test Stove", "Living Room");
|
|
359
|
-
assert.
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
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);
|
|
372
358
|
}));
|
|
373
359
|
it("should normalize MAC address by removing colons", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
get: sinon.stub(),
|
|
377
|
-
put: sinon.stub(),
|
|
378
|
-
};
|
|
379
|
-
axiosStub.returns(mockAxios);
|
|
380
|
-
const api = configure("https://example.com/api");
|
|
360
|
+
fetchStub.resolves(mockResponse({}));
|
|
361
|
+
const api = configure("https://example.com/api/");
|
|
381
362
|
yield api.registerDevice(expectedToken, "AA:BB:CC:DD:EE:FF", "EDK123");
|
|
382
|
-
|
|
363
|
+
const body = JSON.parse(fetchStub.firstCall.args[1].body);
|
|
364
|
+
assert.equal(body.macAddress, "AABBCCDDEEFF");
|
|
383
365
|
}));
|
|
384
366
|
it("should use empty strings as defaults for name and room", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
get: sinon.stub(),
|
|
388
|
-
put: sinon.stub(),
|
|
389
|
-
};
|
|
390
|
-
axiosStub.returns(mockAxios);
|
|
391
|
-
const api = configure("https://example.com/api");
|
|
367
|
+
fetchStub.resolves(mockResponse({}));
|
|
368
|
+
const api = configure("https://example.com/api/");
|
|
392
369
|
yield api.registerDevice(expectedToken, "AABBCCDDEEFF", "EDK123");
|
|
393
|
-
|
|
394
|
-
assert.equal(
|
|
370
|
+
const body = JSON.parse(fetchStub.firstCall.args[1].body);
|
|
371
|
+
assert.equal(body.deviceName, "");
|
|
372
|
+
assert.equal(body.deviceRoom, "");
|
|
395
373
|
}));
|
|
396
374
|
});
|
|
397
375
|
describe("editDevice", () => {
|
|
398
376
|
it("should call PUT /device/{mac} with correct payload", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
399
|
-
const
|
|
377
|
+
const mockResponseData = {
|
|
400
378
|
macAddress: "AABBCCDDEEFF",
|
|
401
379
|
deviceName: "Updated Name",
|
|
402
380
|
deviceRoom: "Basement",
|
|
403
381
|
serialNumber: "EDK123",
|
|
404
382
|
};
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
get: sinon.stub(),
|
|
408
|
-
post: sinon.stub(),
|
|
409
|
-
};
|
|
410
|
-
axiosStub.returns(mockAxios);
|
|
411
|
-
const api = configure("https://example.com/api");
|
|
383
|
+
fetchStub.resolves(mockResponse(mockResponseData));
|
|
384
|
+
const api = configure("https://example.com/api/");
|
|
412
385
|
const result = yield api.editDevice(expectedToken, "AA:BB:CC:DD:EE:FF", "Updated Name", "Basement");
|
|
413
|
-
assert.
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
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);
|
|
424
400
|
}));
|
|
425
401
|
it("should use empty strings as defaults for name and room", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
get: sinon.stub(),
|
|
429
|
-
post: sinon.stub(),
|
|
430
|
-
};
|
|
431
|
-
axiosStub.returns(mockAxios);
|
|
432
|
-
const api = configure("https://example.com/api");
|
|
402
|
+
fetchStub.resolves(mockResponse({}));
|
|
403
|
+
const api = configure("https://example.com/api/");
|
|
433
404
|
yield api.editDevice(expectedToken, "AABBCCDDEEFF");
|
|
434
|
-
|
|
435
|
-
assert.equal(
|
|
405
|
+
const body = JSON.parse(fetchStub.firstCall.args[1].body);
|
|
406
|
+
assert.equal(body.deviceName, "");
|
|
407
|
+
assert.equal(body.deviceRoom, "");
|
|
436
408
|
}));
|
|
437
409
|
});
|
|
438
410
|
describe("deviceInfo with compressed responses", () => {
|
|
@@ -441,7 +413,7 @@ describe("library", () => {
|
|
|
441
413
|
commands: { power: true },
|
|
442
414
|
temperatures: { enviroment: 19, board: 25 },
|
|
443
415
|
};
|
|
444
|
-
const
|
|
416
|
+
const mockResponseData = {
|
|
445
417
|
status: createGzippedBuffer(statusData),
|
|
446
418
|
nvm: {
|
|
447
419
|
user_parameters: {
|
|
@@ -449,11 +421,8 @@ describe("library", () => {
|
|
|
449
421
|
},
|
|
450
422
|
},
|
|
451
423
|
};
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
};
|
|
455
|
-
axiosStub.returns(mockAxios);
|
|
456
|
-
const api = configure("https://example.com/api");
|
|
424
|
+
fetchStub.resolves(mockResponse(mockResponseData));
|
|
425
|
+
const api = configure("https://example.com/api/");
|
|
457
426
|
const result = yield api.deviceInfo(expectedToken, "mockMacAddress");
|
|
458
427
|
assert.deepEqual(result.status, statusData);
|
|
459
428
|
}));
|
|
@@ -467,18 +436,15 @@ describe("library", () => {
|
|
|
467
436
|
is_sound_active: true,
|
|
468
437
|
},
|
|
469
438
|
};
|
|
470
|
-
const
|
|
439
|
+
const mockResponseData = {
|
|
471
440
|
status: {
|
|
472
441
|
commands: { power: true },
|
|
473
442
|
temperatures: { enviroment: 19 },
|
|
474
443
|
},
|
|
475
444
|
nvm: createGzippedBuffer(nvmData),
|
|
476
445
|
};
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
};
|
|
480
|
-
axiosStub.returns(mockAxios);
|
|
481
|
-
const api = configure("https://example.com/api");
|
|
446
|
+
fetchStub.resolves(mockResponse(mockResponseData));
|
|
447
|
+
const api = configure("https://example.com/api/");
|
|
482
448
|
const result = yield api.deviceInfo(expectedToken, "mockMacAddress");
|
|
483
449
|
assert.deepEqual(result.nvm, nvmData);
|
|
484
450
|
}));
|
|
@@ -496,15 +462,12 @@ describe("library", () => {
|
|
|
496
462
|
is_sound_active: false,
|
|
497
463
|
},
|
|
498
464
|
};
|
|
499
|
-
const
|
|
465
|
+
const mockResponseData = {
|
|
500
466
|
status: createGzippedBuffer(statusData),
|
|
501
467
|
nvm: createGzippedBuffer(nvmData),
|
|
502
468
|
};
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
};
|
|
506
|
-
axiosStub.returns(mockAxios);
|
|
507
|
-
const api = configure("https://example.com/api");
|
|
469
|
+
fetchStub.resolves(mockResponse(mockResponseData));
|
|
470
|
+
const api = configure("https://example.com/api/");
|
|
508
471
|
const result = yield api.deviceInfo(expectedToken, "mockMacAddress");
|
|
509
472
|
assert.deepEqual(result.status, statusData);
|
|
510
473
|
assert.deepEqual(result.nvm, nvmData);
|
|
@@ -514,15 +477,12 @@ describe("library", () => {
|
|
|
514
477
|
commands: { power: true },
|
|
515
478
|
temperatures: { enviroment: 19 },
|
|
516
479
|
};
|
|
517
|
-
const
|
|
480
|
+
const mockResponseData = {
|
|
518
481
|
status: createGzippedBuffer(statusData),
|
|
519
482
|
nvm: { user_parameters: { enviroment_1_temperature: 22 } },
|
|
520
483
|
};
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
};
|
|
524
|
-
axiosStub.returns(mockAxios);
|
|
525
|
-
const api = configure("https://example.com/api");
|
|
484
|
+
fetchStub.resolves(mockResponse(mockResponseData));
|
|
485
|
+
const api = configure("https://example.com/api/");
|
|
526
486
|
const result = yield api.getPower(expectedToken, "mockMacAddress");
|
|
527
487
|
assert.equal(result, true);
|
|
528
488
|
}));
|
|
@@ -531,15 +491,12 @@ describe("library", () => {
|
|
|
531
491
|
commands: { power: true },
|
|
532
492
|
temperatures: { enviroment: 19, board: 25 },
|
|
533
493
|
};
|
|
534
|
-
const
|
|
494
|
+
const mockResponseData = {
|
|
535
495
|
status: createGzippedBuffer(statusData),
|
|
536
496
|
nvm: { user_parameters: { enviroment_1_temperature: 22 } },
|
|
537
497
|
};
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
};
|
|
541
|
-
axiosStub.returns(mockAxios);
|
|
542
|
-
const api = configure("https://example.com/api");
|
|
498
|
+
fetchStub.resolves(mockResponse(mockResponseData));
|
|
499
|
+
const api = configure("https://example.com/api/");
|
|
543
500
|
const result = yield api.getEnvironmentTemperature(expectedToken, "mockMacAddress");
|
|
544
501
|
assert.equal(result, 19);
|
|
545
502
|
}));
|
|
@@ -549,17 +506,37 @@ describe("library", () => {
|
|
|
549
506
|
enviroment_1_temperature: 22,
|
|
550
507
|
},
|
|
551
508
|
};
|
|
552
|
-
const
|
|
509
|
+
const mockResponseData = {
|
|
553
510
|
status: { commands: { power: true }, temperatures: { enviroment: 19 } },
|
|
554
511
|
nvm: createGzippedBuffer(nvmData),
|
|
555
512
|
};
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
};
|
|
559
|
-
axiosStub.returns(mockAxios);
|
|
560
|
-
const api = configure("https://example.com/api");
|
|
513
|
+
fetchStub.resolves(mockResponse(mockResponseData));
|
|
514
|
+
const api = configure("https://example.com/api/");
|
|
561
515
|
const result = yield api.getTargetTemperature(expectedToken, "mockMacAddress");
|
|
562
516
|
assert.equal(result, 22);
|
|
563
517
|
}));
|
|
564
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
|
+
});
|
|
565
542
|
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a raw serial number string to hex-encoded format.
|
|
3
|
+
* This is useful when serial numbers contain non-printable characters.
|
|
4
|
+
*
|
|
5
|
+
* @param serial - The raw serial number string
|
|
6
|
+
* @returns Hex-encoded string representation
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* serialNumberToHex("EDK123") // returns "45444b313233"
|
|
10
|
+
*/
|
|
11
|
+
declare const serialNumberToHex: (serial: string) => string;
|
|
12
|
+
/**
|
|
13
|
+
* Converts a hex-encoded serial number back to raw string format.
|
|
14
|
+
*
|
|
15
|
+
* @param hex - The hex-encoded serial number
|
|
16
|
+
* @returns Raw serial number string
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* serialNumberFromHex("45444b313233") // returns "EDK123"
|
|
20
|
+
*/
|
|
21
|
+
declare const serialNumberFromHex: (hex: string) => string;
|
|
22
|
+
/**
|
|
23
|
+
* Produces a display-friendly version of a serial number by removing
|
|
24
|
+
* non-printable characters and collapsing whitespace.
|
|
25
|
+
*
|
|
26
|
+
* @param serial - The raw serial number string
|
|
27
|
+
* @returns Display-friendly serial number
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* serialNumberDisplay("EDK\x00123\x1F") // returns "EDK123"
|
|
31
|
+
*/
|
|
32
|
+
declare const serialNumberDisplay: (serial: string) => string;
|
|
33
|
+
export { serialNumberDisplay, serialNumberFromHex, serialNumberToHex };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a Node.js Buffer object serialized to JSON.
|
|
3
|
+
* This format is used by the Edilkamin API for gzip-compressed fields.
|
|
4
|
+
*/
|
|
5
|
+
interface BufferEncodedType {
|
|
6
|
+
type: "Buffer";
|
|
7
|
+
data: number[];
|
|
8
|
+
}
|
|
9
|
+
interface CommandsType {
|
|
10
|
+
power: boolean;
|
|
11
|
+
}
|
|
12
|
+
interface TemperaturesType {
|
|
13
|
+
board: number;
|
|
14
|
+
enviroment: number;
|
|
15
|
+
}
|
|
16
|
+
interface StatusType {
|
|
17
|
+
commands: CommandsType;
|
|
18
|
+
temperatures: TemperaturesType;
|
|
19
|
+
}
|
|
20
|
+
interface UserParametersType {
|
|
21
|
+
enviroment_1_temperature: number;
|
|
22
|
+
enviroment_2_temperature: number;
|
|
23
|
+
enviroment_3_temperature: number;
|
|
24
|
+
is_auto: boolean;
|
|
25
|
+
is_sound_active: boolean;
|
|
26
|
+
}
|
|
27
|
+
interface DeviceInfoType {
|
|
28
|
+
status: StatusType;
|
|
29
|
+
nvm: {
|
|
30
|
+
user_parameters: UserParametersType;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Raw device info response that may contain Buffer-encoded compressed fields.
|
|
35
|
+
* Used internally before processing; external callers receive DeviceInfoType.
|
|
36
|
+
*/
|
|
37
|
+
interface DeviceInfoRawType {
|
|
38
|
+
status: StatusType | BufferEncodedType;
|
|
39
|
+
nvm: {
|
|
40
|
+
user_parameters: UserParametersType;
|
|
41
|
+
} | BufferEncodedType;
|
|
42
|
+
component_info?: BufferEncodedType | Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Request body for registering a device with a user account.
|
|
46
|
+
* All fields are required by the API.
|
|
47
|
+
*/
|
|
48
|
+
interface DeviceAssociationBody {
|
|
49
|
+
macAddress: string;
|
|
50
|
+
deviceName: string;
|
|
51
|
+
deviceRoom: string;
|
|
52
|
+
serialNumber: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Request body for editing a device's name and room.
|
|
56
|
+
* MAC address is specified in the URL path, not the body.
|
|
57
|
+
* Serial number cannot be changed after registration.
|
|
58
|
+
*/
|
|
59
|
+
interface EditDeviceAssociationBody {
|
|
60
|
+
deviceName: string;
|
|
61
|
+
deviceRoom: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Response from device registration endpoint.
|
|
65
|
+
* Structure based on Android app behavior - may need adjustment after testing.
|
|
66
|
+
*/
|
|
67
|
+
interface DeviceAssociationResponse {
|
|
68
|
+
macAddress: string;
|
|
69
|
+
deviceName: string;
|
|
70
|
+
deviceRoom: string;
|
|
71
|
+
serialNumber: string;
|
|
72
|
+
}
|
|
73
|
+
export type { BufferEncodedType, CommandsType, DeviceAssociationBody, DeviceAssociationResponse, DeviceInfoRawType, DeviceInfoType, EditDeviceAssociationBody, StatusType, TemperaturesType, UserParametersType, };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|