edilkamin 1.3.2 → 1.4.1

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,10 +8,13 @@ jobs:
8
8
  tests:
9
9
  runs-on: ubuntu-latest
10
10
  timeout-minutes: 5
11
+ strategy:
12
+ matrix:
13
+ node-version: [20.x, 22.x]
11
14
  steps:
12
15
  - uses: actions/checkout@v4
13
16
  - uses: actions/setup-node@v4
14
17
  with:
15
- node-version: "20.x"
18
+ node-version: ${{ matrix.node-version }}
16
19
  - run: yarn install --no-ignore-optional
17
20
  - run: yarn cli --help
@@ -2,17 +2,17 @@ name: Documentation
2
2
 
3
3
  on:
4
4
  push:
5
- branches:
6
- - main
5
+ pull_request:
7
6
 
8
7
  jobs:
9
8
  deploy:
10
9
  runs-on: ubuntu-latest
10
+ timeout-minutes: 5
11
11
  steps:
12
12
  - uses: actions/checkout@v4
13
13
  - uses: actions/setup-node@v4
14
14
  with:
15
- node-version: "20.x"
15
+ node-version: "22.x"
16
16
  - name: git config
17
17
  run: |
18
18
  git config user.name documentation-deploy-action
@@ -20,7 +20,7 @@ jobs:
20
20
  git remote set-url origin https://${{github.actor}}:${{github.token}}@github.com/${{github.repository}}.git
21
21
  - run: yarn install
22
22
  - run: yarn typedoc src/index.ts --out /tmp/docs
23
- - name: deploy documentation
23
+ - name: commit documentation
24
24
  run: |
25
25
  git ls-remote --exit-code . origin/gh-pages \
26
26
  && git checkout -b gh-pages \
@@ -30,5 +30,8 @@ jobs:
30
30
  cp --recursive /tmp/docs/. .
31
31
  echo /node_modules > .gitignore
32
32
  git add --all
33
- git commit --all --message ":memo: docs: Update generated documentation"
33
+ git commit --all --message ":memo: docs: Update generated documentation" || echo "No changes to commit"
34
+ - name: push documentation
35
+ if: github.ref_name == 'main'
36
+ run: |
34
37
  git push origin gh-pages
@@ -2,20 +2,22 @@ name: Publish
2
2
 
3
3
  on:
4
4
  push:
5
- tags:
6
- - "*"
5
+ pull_request:
7
6
 
8
7
  jobs:
9
8
  build:
10
9
  runs-on: ubuntu-latest
10
+ timeout-minutes: 5
11
11
  steps:
12
12
  - uses: actions/checkout@v4
13
13
  - uses: actions/setup-node@v4
14
14
  with:
15
- node-version: "20.x"
15
+ node-version: "22.x"
16
16
  registry-url: "https://registry.npmjs.org"
17
17
  - run: yarn install
18
18
  - run: yarn build
19
+ - run: npm publish --dry-run
19
20
  - run: npm publish
21
+ if: startsWith(github.ref, 'refs/tags/')
20
22
  env:
21
23
  NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
@@ -5,14 +5,25 @@ on:
5
5
  pull_request:
6
6
 
7
7
  jobs:
8
- build:
8
+ tests:
9
9
  runs-on: ubuntu-latest
10
+ timeout-minutes: 5
11
+ strategy:
12
+ matrix:
13
+ node-version: [20.x, 22.x]
10
14
  steps:
11
15
  - uses: actions/checkout@v4
12
16
  - uses: actions/setup-node@v4
13
17
  with:
14
- node-version: "20.x"
18
+ node-version: ${{ matrix.node-version }}
15
19
  - run: yarn install
16
20
  - run: yarn lint
17
21
  - run: yarn build
18
- - run: npm publish --dry-run
22
+ - run: yarn test
23
+ - uses: codecov/codecov-action@v5
24
+ with:
25
+ files: ./coverage/lcov.info
26
+ token: ${{ secrets.CODECOV_TOKEN }}
27
+ fail_ci_if_error: true
28
+ env:
29
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
package/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![Tests](https://github.com/AndreMiras/edilkamin.js/workflows/Tests/badge.svg)](https://github.com/AndreMiras/edilkamin.js/actions/workflows/tests.yml)
4
4
  [![CLI Tests](https://github.com/AndreMiras/edilkamin.js/actions/workflows/cli-tests.yml/badge.svg)](https://github.com/AndreMiras/edilkamin.js/actions/workflows/cli-tests.yml)
5
+ [![codecov](https://codecov.io/gh/AndreMiras/edilkamin.js/graph/badge.svg?token=YG3LKXNZWU)](https://app.codecov.io/gh/AndreMiras/edilkamin.js/tree/main)
5
6
  [![Documentation](https://github.com/AndreMiras/edilkamin.js/workflows/Documentation/badge.svg)](https://github.com/AndreMiras/edilkamin.js/actions/workflows/documentation.yml)
6
7
  [![npm version](https://badge.fury.io/js/edilkamin.svg)](https://badge.fury.io/js/edilkamin)
7
8
 
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
2
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
3
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
4
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -9,17 +8,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
10
9
  });
11
10
  };
12
- var __importDefault = (this && this.__importDefault) || function (mod) {
13
- return (mod && mod.__esModule) ? mod : { "default": mod };
14
- };
15
- Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.main = void 0;
17
- const library_1 = require("./library");
18
- const commander_1 = require("commander");
19
- const readline_1 = __importDefault(require("readline"));
20
- const package_json_1 = require("../package.json");
11
+ import { Command } from "commander";
12
+ import readline from "readline";
13
+ import { version } from "../package.json";
14
+ import { configure, signIn } from "./library";
21
15
  const promptPassword = () => {
22
- const rl = readline_1.default.createInterface({
16
+ const rl = readline.createInterface({
23
17
  input: process.stdin,
24
18
  output: process.stdout,
25
19
  terminal: true,
@@ -27,8 +21,8 @@ const promptPassword = () => {
27
21
  return new Promise((resolve) => {
28
22
  rl.question("Enter password: ", (password) => {
29
23
  // Hide the password input
30
- readline_1.default.moveCursor(process.stdout, 0, -1);
31
- readline_1.default.clearLine(process.stdout, 0);
24
+ readline.moveCursor(process.stdout, 0, -1);
25
+ readline.clearLine(process.stdout, 0);
32
26
  rl.close();
33
27
  resolve(password);
34
28
  });
@@ -49,16 +43,16 @@ const addCommonOptions = (command) => command
49
43
  .requiredOption("-u, --username <username>", "Username")
50
44
  .option("-p, --password <password>", "Password");
51
45
  const createProgram = () => {
52
- const program = new commander_1.Command();
46
+ const program = new Command();
53
47
  program
54
48
  .name("edilkamin-cli")
55
49
  .description("CLI tool for interacting with the Edilkamin API")
56
- .version(package_json_1.version);
50
+ .version(version);
57
51
  // Command: signIn
58
52
  addCommonOptions(program.command("signIn").description("Sign in and retrieve a JWT token")).action((options) => __awaiter(void 0, void 0, void 0, function* () {
59
53
  const { username, password } = options;
60
54
  const pwd = password || (yield promptPassword());
61
- const jwtToken = yield (0, library_1.signIn)(username, pwd);
55
+ const jwtToken = yield signIn(username, pwd);
62
56
  console.log("JWT Token:", jwtToken);
63
57
  }));
64
58
  // Command: deviceInfo
@@ -67,10 +61,11 @@ const createProgram = () => {
67
61
  .description("Retrieve device info for a specific MAC address")
68
62
  .requiredOption("-m, --mac <macAddress>", "MAC address of the device")).action((options) => __awaiter(void 0, void 0, void 0, function* () {
69
63
  const { username, password, mac } = options;
64
+ const normalizedMac = mac.replace(/:/g, "");
70
65
  const pwd = password || (yield promptPassword());
71
- const jwtToken = yield (0, library_1.signIn)(username, pwd);
72
- const api = (0, library_1.configure)(); // Use the default API configuration
73
- const deviceInfo = yield api.deviceInfo(jwtToken, mac);
66
+ const jwtToken = yield signIn(username, pwd);
67
+ const api = configure(); // Use the default API configuration
68
+ const deviceInfo = yield api.deviceInfo(jwtToken, normalizedMac);
74
69
  console.log("Device Info:", deviceInfo.data);
75
70
  }));
76
71
  return program;
@@ -79,7 +74,7 @@ const main = () => {
79
74
  const program = createProgram();
80
75
  program.parse(process.argv);
81
76
  };
82
- exports.main = main;
83
77
  if (require.main === module) {
84
78
  main();
85
79
  }
80
+ export { main };
@@ -0,0 +1,2 @@
1
+ const API_URL = "https://fxtj7xkgc6.execute-api.eu-central-1.amazonaws.com/prod/";
2
+ export { API_URL };
@@ -1,4 +1,4 @@
1
1
  export { API_URL } from "./constants";
2
+ export { configure, signIn } from "./library";
2
3
  export { CommandsType, DeviceInfoType, StatusType, TemperaturesType, UserParametersType, } from "./types";
3
- export { signIn, configure } from "./library";
4
4
  export declare const deviceInfo: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<import("./types").DeviceInfoType, any>>, setPower: (jwtToken: string, macAddress: string, value: number) => Promise<import("axios").AxiosResponse<any, any>>, setPowerOff: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<any, any>>, setPowerOn: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<any, any>>;
@@ -0,0 +1,4 @@
1
+ import { configure } from "./library";
2
+ export { API_URL } from "./constants";
3
+ export { configure, signIn } from "./library";
4
+ export const { deviceInfo, setPower, setPowerOff, setPowerOn } = configure();
@@ -0,0 +1,26 @@
1
+ import * as amplifyAuth from "aws-amplify/auth";
2
+ import { DeviceInfoType } from "./types";
3
+ /**
4
+ * Generates headers with a JWT token for authenticated requests.
5
+ * @param {string} jwtToken - The JWT token for authorization.
6
+ * @returns {object} - The headers object with the Authorization field.
7
+ */
8
+ declare const headers: (jwtToken: string) => {
9
+ Authorization: string;
10
+ };
11
+ /**
12
+ * Creates an authentication service with sign-in functionality.
13
+ * @param {typeof amplifyAuth} auth - The authentication module to use.
14
+ * @returns {object} - An object containing authentication-related methods.
15
+ */
16
+ declare const createAuthService: (auth: typeof amplifyAuth) => {
17
+ signIn: (username: string, password: string) => Promise<string>;
18
+ };
19
+ declare const signIn: (username: string, password: string) => Promise<string>;
20
+ declare const configure: (baseURL?: string) => {
21
+ deviceInfo: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<DeviceInfoType, any>>;
22
+ setPower: (jwtToken: string, macAddress: string, value: number) => Promise<import("axios").AxiosResponse<any, any>>;
23
+ setPowerOff: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<any, any>>;
24
+ setPowerOn: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<any, any>>;
25
+ };
26
+ export { configure, createAuthService, headers, signIn };
@@ -0,0 +1,84 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { strict as assert } from "assert";
11
+ import { Amplify } from "aws-amplify";
12
+ import * as amplifyAuth from "aws-amplify/auth";
13
+ import axios from "axios";
14
+ import { API_URL } from "./constants";
15
+ const amplifyconfiguration = {
16
+ aws_project_region: "eu-central-1",
17
+ aws_user_pools_id: "eu-central-1_BYmQ2VBlo",
18
+ aws_user_pools_web_client_id: "7sc1qltkqobo3ddqsk4542dg2h",
19
+ };
20
+ /**
21
+ * Generates headers with a JWT token for authenticated requests.
22
+ * @param {string} jwtToken - The JWT token for authorization.
23
+ * @returns {object} - The headers object with the Authorization field.
24
+ */
25
+ const headers = (jwtToken) => ({ Authorization: `Bearer ${jwtToken}` });
26
+ /**
27
+ * Configures Amplify if not already configured.
28
+ * Ensures the configuration is only applied once.
29
+ */
30
+ const configureAmplify = () => {
31
+ const currentConfig = Amplify.getConfig();
32
+ if (Object.keys(currentConfig).length !== 0)
33
+ return;
34
+ Amplify.configure(amplifyconfiguration);
35
+ };
36
+ /**
37
+ * Creates an authentication service with sign-in functionality.
38
+ * @param {typeof amplifyAuth} auth - The authentication module to use.
39
+ * @returns {object} - An object containing authentication-related methods.
40
+ */
41
+ const createAuthService = (auth) => {
42
+ /**
43
+ * Signs in a user with the provided credentials.
44
+ * @param {string} username - The username of the user.
45
+ * @param {string} password - The password of the user.
46
+ * @returns {Promise<string>} - The JWT token of the signed-in user.
47
+ * @throws {Error} - If sign-in fails or no tokens are retrieved.
48
+ */
49
+ const signIn = (username, password) => __awaiter(void 0, void 0, void 0, function* () {
50
+ configureAmplify();
51
+ yield auth.signOut(); // Ensure the user is signed out first
52
+ const { isSignedIn } = yield auth.signIn({ username, password });
53
+ assert.ok(isSignedIn, "Sign-in failed");
54
+ const { tokens } = yield auth.fetchAuthSession();
55
+ assert.ok(tokens, "No tokens found");
56
+ return tokens.accessToken.toString();
57
+ });
58
+ return { signIn };
59
+ };
60
+ // Create the default auth service using amplifyAuth
61
+ const { signIn } = createAuthService(amplifyAuth);
62
+ const deviceInfo = (axiosInstance) => (jwtToken, macAddress) => axiosInstance.get(`device/${macAddress}/info`, {
63
+ headers: headers(jwtToken),
64
+ });
65
+ const mqttCommand = (axiosInstance) =>
66
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
+ (jwtToken, macAddress, payload) => axiosInstance.put("mqtt/command", Object.assign({ mac_address: macAddress }, payload), { headers: headers(jwtToken) });
68
+ const setPower = (axiosInstance) => (jwtToken, macAddress, value) => mqttCommand(axiosInstance)(jwtToken, macAddress, { name: "power", value });
69
+ const setPowerOn = (axiosInstance) => (jwtToken, macAddress) => setPower(axiosInstance)(jwtToken, macAddress, 1);
70
+ const setPowerOff = (axiosInstance) => (jwtToken, macAddress) => setPower(axiosInstance)(jwtToken, macAddress, 0);
71
+ const configure = (baseURL = API_URL) => {
72
+ const axiosInstance = axios.create({ baseURL });
73
+ const deviceInfoInstance = deviceInfo(axiosInstance);
74
+ const setPowerInstance = setPower(axiosInstance);
75
+ const setPowerOffInstance = setPowerOff(axiosInstance);
76
+ const setPowerOnInstance = setPowerOn(axiosInstance);
77
+ return {
78
+ deviceInfo: deviceInfoInstance,
79
+ setPower: setPowerInstance,
80
+ setPowerOff: setPowerOffInstance,
81
+ setPowerOn: setPowerOnInstance,
82
+ };
83
+ };
84
+ export { configure, createAuthService, headers, signIn };
@@ -0,0 +1,168 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { strict as assert } from "assert";
11
+ import axios from "axios";
12
+ import sinon from "sinon";
13
+ import { configure, createAuthService } from "../src/library";
14
+ import { API_URL } from "./constants";
15
+ describe("library", () => {
16
+ let axiosStub;
17
+ beforeEach(() => {
18
+ axiosStub = sinon.stub(axios, "create").returns({
19
+ get: sinon.stub(),
20
+ put: sinon.stub(),
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+ });
23
+ });
24
+ afterEach(() => {
25
+ sinon.restore();
26
+ });
27
+ describe("signIn", () => {
28
+ it("should sign in and return the JWT token", () => __awaiter(void 0, void 0, void 0, function* () {
29
+ const expectedUsername = "testuser";
30
+ const expectedPassword = "testpassword";
31
+ const expectedToken = "mockJwtToken";
32
+ const signIn = sinon.stub().resolves({ isSignedIn: true });
33
+ const signOut = sinon.stub();
34
+ const fetchAuthSession = sinon.stub().resolves({
35
+ tokens: {
36
+ accessToken: { toString: () => expectedToken },
37
+ },
38
+ });
39
+ const authStub = {
40
+ signIn,
41
+ signOut,
42
+ fetchAuthSession,
43
+ };
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ const authService = createAuthService(authStub);
46
+ const token = yield authService.signIn(expectedUsername, expectedPassword);
47
+ assert.deepEqual(authStub.signOut.args, [[]]);
48
+ assert.deepEqual(signIn.args, [
49
+ [{ username: expectedUsername, password: expectedPassword }],
50
+ ]);
51
+ assert.equal(token, expectedToken);
52
+ }));
53
+ it("should throw an error if sign-in fails", () => __awaiter(void 0, void 0, void 0, function* () {
54
+ const expectedUsername = "testuser";
55
+ const expectedPassword = "testpassword";
56
+ const expectedToken = "mockJwtToken";
57
+ const signIn = sinon.stub().resolves({ isSignedIn: false });
58
+ const signOut = sinon.stub();
59
+ const fetchAuthSession = sinon.stub().resolves({
60
+ tokens: {
61
+ accessToken: { toString: () => expectedToken },
62
+ },
63
+ });
64
+ const authStub = {
65
+ signIn,
66
+ signOut,
67
+ fetchAuthSession,
68
+ };
69
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
70
+ const authService = createAuthService(authStub);
71
+ yield assert.rejects(() => __awaiter(void 0, void 0, void 0, function* () { return authService.signIn(expectedUsername, expectedPassword); }), {
72
+ name: "AssertionError",
73
+ message: "Sign-in failed",
74
+ });
75
+ }));
76
+ });
77
+ describe("configure", () => {
78
+ it("should create API methods with the correct baseURL", () => {
79
+ const baseURL = "https://example.com/api";
80
+ const api = configure(baseURL);
81
+ assert.deepEqual(axiosStub.args, [
82
+ [
83
+ {
84
+ baseURL,
85
+ },
86
+ ],
87
+ ]);
88
+ assert.deepEqual(Object.keys(api), [
89
+ "deviceInfo",
90
+ "setPower",
91
+ "setPowerOff",
92
+ "setPowerOn",
93
+ ]);
94
+ });
95
+ it("should create API methods with the default baseURL", () => {
96
+ const api = configure();
97
+ assert.deepEqual(axiosStub.args, [
98
+ [
99
+ {
100
+ baseURL: API_URL,
101
+ },
102
+ ],
103
+ ]);
104
+ assert.deepEqual(Object.keys(api), [
105
+ "deviceInfo",
106
+ "setPower",
107
+ "setPowerOff",
108
+ "setPowerOn",
109
+ ]);
110
+ });
111
+ });
112
+ describe("API Methods", () => {
113
+ it("should call axios for deviceInfo", () => __awaiter(void 0, void 0, void 0, function* () {
114
+ const expectedDevice = { id: "123", name: "Mock Device" };
115
+ const expectedToken = "mockToken";
116
+ const mockAxios = {
117
+ get: sinon.stub().resolves({ data: expectedDevice }),
118
+ };
119
+ axiosStub.returns(mockAxios);
120
+ const api = configure("https://example.com/api");
121
+ const result = yield api.deviceInfo(expectedToken, "mockMacAddress");
122
+ assert.deepEqual(mockAxios.get.args, [
123
+ [
124
+ "device/mockMacAddress/info",
125
+ { headers: { Authorization: `Bearer ${expectedToken}` } },
126
+ ],
127
+ ]);
128
+ assert.deepEqual(result.data, expectedDevice);
129
+ }));
130
+ // Tests for setPowerOn and setPowerOff
131
+ [
132
+ {
133
+ method: "setPowerOn",
134
+ call: (api) => api.setPowerOn("mockToken", "mockMacAddress"),
135
+ expectedValue: 1,
136
+ },
137
+ {
138
+ method: "setPowerOff",
139
+ call: (api) => api.setPowerOff("mockToken", "mockMacAddress"),
140
+ expectedValue: 0,
141
+ },
142
+ ].forEach(({ method, call, expectedValue }) => {
143
+ it(`should call axios for ${method}`, () => __awaiter(void 0, void 0, void 0, function* () {
144
+ const mockAxios = {
145
+ put: sinon.stub().resolves({ status: 200 }),
146
+ };
147
+ axiosStub.returns(mockAxios);
148
+ const api = configure("https://example.com/api");
149
+ // Invoke the method using the mapped call function
150
+ const result = yield call(api);
151
+ assert.deepEqual(mockAxios.put.args, [
152
+ [
153
+ "mqtt/command",
154
+ {
155
+ mac_address: "mockMacAddress",
156
+ name: "power",
157
+ value: expectedValue,
158
+ },
159
+ {
160
+ headers: { Authorization: "Bearer mockToken" },
161
+ },
162
+ ],
163
+ ]);
164
+ assert.equal(result.status, 200);
165
+ }));
166
+ });
167
+ });
168
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
1
+ import typescriptEslint from "@typescript-eslint/eslint-plugin";
2
+ import simpleImportSort from "eslint-plugin-simple-import-sort";
3
+ import globals from "globals";
4
+ import tsParser from "@typescript-eslint/parser";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import js from "@eslint/js";
8
+ import { FlatCompat } from "@eslint/eslintrc";
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ const compat = new FlatCompat({
14
+ baseDirectory: __dirname,
15
+ recommendedConfig: js.configs.recommended,
16
+ allConfig: js.configs.all,
17
+ });
18
+
19
+ export default [
20
+ ...compat.extends(
21
+ "eslint:recommended",
22
+ "plugin:@typescript-eslint/recommended"
23
+ ),
24
+ {
25
+ plugins: {
26
+ "@typescript-eslint": typescriptEslint,
27
+ "simple-import-sort": simpleImportSort,
28
+ },
29
+ rules: {
30
+ // Sorting imports and exports
31
+ "simple-import-sort/imports": "error",
32
+ "simple-import-sort/exports": "error",
33
+ },
34
+ },
35
+ ];
package/package.json CHANGED
@@ -1,17 +1,24 @@
1
1
  {
2
2
  "name": "edilkamin",
3
- "version": "1.3.2",
3
+ "version": "1.4.1",
4
4
  "description": "",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
5
+ "main": "dist/cjs/index.js",
6
+ "module": "dist/esm/index.js",
7
+ "types": "dist/esm/index.d.ts",
7
8
  "scripts": {
8
9
  "cli": "ts-node src/cli.ts",
9
10
  "cli:debug": "node --inspect --require ts-node/register/transpile-only src/cli.ts",
10
- "test": "mocha --require ts-node/register src/*.test.ts",
11
- "test:debug": "mocha --require ts-node/register/transpile-only --inspect src/*.test.ts",
12
- "lint": "prettier --check src docs .github *.md",
13
- "format": "prettier --write src docs .github *.md",
14
- "build": "tsc"
11
+ "test": "nyc mocha --require ts-node/register src/*.test.ts",
12
+ "test:debug": "nyc mocha --require ts-node/register/transpile-only --inspect src/*.test.ts",
13
+ "lint:prettier": "prettier --check src docs .github *.json *.md *.mjs",
14
+ "format:prettier": "prettier --write src docs .github *.json *.md *.mjs",
15
+ "lint:eslint": "eslint src",
16
+ "format:eslint": "eslint --fix src",
17
+ "lint": "yarn lint:prettier && yarn lint:eslint",
18
+ "format": "yarn format:prettier && yarn format:eslint",
19
+ "build:cjs": "tsc -p tsconfig.cjs.json",
20
+ "build:esm": "tsc -p tsconfig.esm.json",
21
+ "build": "npm run build:cjs && npm run build:esm"
15
22
  },
16
23
  "repository": {
17
24
  "type": "git",
@@ -24,7 +31,14 @@
24
31
  },
25
32
  "homepage": "https://github.com/AndreMiras/edilkamin.js#readme",
26
33
  "bin": {
27
- "edilkamin": "dist/cli.js"
34
+ "edilkamin": "dist/cjs/cli.js"
35
+ },
36
+ "nyc": {
37
+ "reporter": [
38
+ "html",
39
+ "lcov",
40
+ "text"
41
+ ]
28
42
  },
29
43
  "dependencies": {
30
44
  "aws-amplify": "^6.10.0",
@@ -32,9 +46,18 @@
32
46
  },
33
47
  "devDependencies": {
34
48
  "@aws-amplify/cli": "^7.6.21",
49
+ "@eslint/eslintrc": "^3.2.0",
50
+ "@eslint/js": "^9.16.0",
35
51
  "@types/mocha": "^10.0.10",
36
52
  "@types/sinon": "^17.0.3",
53
+ "@typescript-eslint/eslint-plugin": "^8.17.0",
54
+ "@typescript-eslint/parser": "^8.17.0",
55
+ "eslint": "^9.16.0",
56
+ "eslint-config-prettier": "^9.1.0",
57
+ "eslint-plugin-prettier": "^5.2.1",
58
+ "eslint-plugin-simple-import-sort": "^12.1.1",
37
59
  "mocha": "^10.8.2",
60
+ "nyc": "^17.1.0",
38
61
  "prettier": "^2.5.1",
39
62
  "sinon": "^19.0.2",
40
63
  "ts-node": "^10.9.1",
package/src/cli.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { signIn, configure } from "./library";
3
2
  import { Command } from "commander";
4
3
  import readline from "readline";
4
+
5
5
  import { version } from "../package.json";
6
+ import { configure, signIn } from "./library";
6
7
 
7
8
  const promptPassword = (): Promise<string> => {
8
9
  const rl = readline.createInterface({
@@ -59,10 +60,11 @@ const createProgram = (): Command => {
59
60
  .requiredOption("-m, --mac <macAddress>", "MAC address of the device")
60
61
  ).action(async (options) => {
61
62
  const { username, password, mac } = options;
63
+ const normalizedMac = mac.replace(/:/g, "");
62
64
  const pwd = password || (await promptPassword());
63
65
  const jwtToken = await signIn(username, pwd);
64
66
  const api = configure(); // Use the default API configuration
65
- const deviceInfo = await api.deviceInfo(jwtToken, mac);
67
+ const deviceInfo = await api.deviceInfo(jwtToken, normalizedMac);
66
68
  console.log("Device Info:", deviceInfo.data);
67
69
  });
68
70
  return program;
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { configure } from "./library";
2
2
 
3
3
  export { API_URL } from "./constants";
4
-
4
+ export { configure, signIn } from "./library";
5
5
  export {
6
6
  CommandsType,
7
7
  DeviceInfoType,
@@ -10,6 +10,4 @@ export {
10
10
  UserParametersType,
11
11
  } from "./types";
12
12
 
13
- export { signIn, configure } from "./library";
14
-
15
13
  export const { deviceInfo, setPower, setPowerOff, setPowerOn } = configure();
@@ -1,8 +1,9 @@
1
1
  import { strict as assert } from "assert";
2
- import sinon from "sinon";
3
- import { Amplify } from "aws-amplify";
4
2
  import axios from "axios";
5
- import { signIn, configure } from "../src/library";
3
+ import sinon from "sinon";
4
+
5
+ import { configure, createAuthService } from "../src/library";
6
+ import { API_URL } from "./constants";
6
7
 
7
8
  describe("library", () => {
8
9
  let axiosStub: sinon.SinonStub;
@@ -11,6 +12,7 @@ describe("library", () => {
11
12
  axiosStub = sinon.stub(axios, "create").returns({
12
13
  get: sinon.stub(),
13
14
  put: sinon.stub(),
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
16
  } as any);
15
17
  });
16
18
 
@@ -18,12 +20,91 @@ describe("library", () => {
18
20
  sinon.restore();
19
21
  });
20
22
 
23
+ describe("signIn", () => {
24
+ it("should sign in and return the JWT token", async () => {
25
+ const expectedUsername = "testuser";
26
+ const expectedPassword = "testpassword";
27
+ const expectedToken = "mockJwtToken";
28
+ const signIn = sinon.stub().resolves({ isSignedIn: true });
29
+ const signOut = sinon.stub();
30
+ const fetchAuthSession = sinon.stub().resolves({
31
+ tokens: {
32
+ accessToken: { toString: () => expectedToken },
33
+ },
34
+ });
35
+ const authStub = {
36
+ signIn,
37
+ signOut,
38
+ fetchAuthSession,
39
+ };
40
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
+ const authService = createAuthService(authStub as any);
42
+ const token = await authService.signIn(
43
+ expectedUsername,
44
+ expectedPassword
45
+ );
46
+ assert.deepEqual(authStub.signOut.args, [[]]);
47
+ assert.deepEqual(signIn.args, [
48
+ [{ username: expectedUsername, password: expectedPassword }],
49
+ ]);
50
+ assert.equal(token, expectedToken);
51
+ });
52
+
53
+ it("should throw an error if sign-in fails", async () => {
54
+ const expectedUsername = "testuser";
55
+ const expectedPassword = "testpassword";
56
+ const expectedToken = "mockJwtToken";
57
+ const signIn = sinon.stub().resolves({ isSignedIn: false });
58
+ const signOut = sinon.stub();
59
+ const fetchAuthSession = sinon.stub().resolves({
60
+ tokens: {
61
+ accessToken: { toString: () => expectedToken },
62
+ },
63
+ });
64
+ const authStub = {
65
+ signIn,
66
+ signOut,
67
+ fetchAuthSession,
68
+ };
69
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
70
+ const authService = createAuthService(authStub as any);
71
+ await assert.rejects(
72
+ async () => authService.signIn(expectedUsername, expectedPassword),
73
+ {
74
+ name: "AssertionError",
75
+ message: "Sign-in failed",
76
+ }
77
+ );
78
+ });
79
+ });
80
+
21
81
  describe("configure", () => {
22
82
  it("should create API methods with the correct baseURL", () => {
23
83
  const baseURL = "https://example.com/api";
24
84
  const api = configure(baseURL);
25
- assert.ok(axiosStub.calledOnce);
26
- assert.deepEqual(axiosStub.firstCall.args[0], { baseURL });
85
+ assert.deepEqual(axiosStub.args, [
86
+ [
87
+ {
88
+ baseURL,
89
+ },
90
+ ],
91
+ ]);
92
+ assert.deepEqual(Object.keys(api), [
93
+ "deviceInfo",
94
+ "setPower",
95
+ "setPowerOff",
96
+ "setPowerOn",
97
+ ]);
98
+ });
99
+ it("should create API methods with the default baseURL", () => {
100
+ const api = configure();
101
+ assert.deepEqual(axiosStub.args, [
102
+ [
103
+ {
104
+ baseURL: API_URL,
105
+ },
106
+ ],
107
+ ]);
27
108
  assert.deepEqual(Object.keys(api), [
28
109
  "deviceInfo",
29
110
  "setPower",
@@ -35,43 +116,62 @@ describe("library", () => {
35
116
 
36
117
  describe("API Methods", () => {
37
118
  it("should call axios for deviceInfo", async () => {
119
+ const expectedDevice = { id: "123", name: "Mock Device" };
120
+ const expectedToken = "mockToken";
38
121
  const mockAxios = {
39
- get: sinon
40
- .stub()
41
- .resolves({ data: { id: "123", name: "Mock Device" } }),
122
+ get: sinon.stub().resolves({ data: expectedDevice }),
42
123
  };
43
- axiosStub.returns(mockAxios as any);
124
+ axiosStub.returns(mockAxios);
44
125
  const api = configure("https://example.com/api");
45
- const result = await api.deviceInfo("mockToken", "mockMacAddress");
46
- assert.ok(mockAxios.get.calledOnce);
47
- assert.equal(
48
- mockAxios.get.firstCall.args[0],
49
- "device/mockMacAddress/info"
50
- );
51
- assert.deepEqual(mockAxios.get.firstCall.args[1], {
52
- headers: { Authorization: "Bearer mockToken" },
53
- });
54
- assert.deepEqual(result.data, { id: "123", name: "Mock Device" });
126
+ const result = await api.deviceInfo(expectedToken, "mockMacAddress");
127
+ assert.deepEqual(mockAxios.get.args, [
128
+ [
129
+ "device/mockMacAddress/info",
130
+ { headers: { Authorization: `Bearer ${expectedToken}` } },
131
+ ],
132
+ ]);
133
+ assert.deepEqual(result.data, expectedDevice);
55
134
  });
56
135
 
57
- it("should call axios for setPowerOn", async () => {
58
- const mockAxios = {
59
- put: sinon.stub().resolves({ status: 200 }),
60
- };
61
- axiosStub.returns(mockAxios as any);
62
- const api = configure("https://example.com/api");
63
- const result = await api.setPowerOn("mockToken", "mockMacAddress");
64
- assert.ok(mockAxios.put.calledOnce);
65
- assert.equal(mockAxios.put.firstCall.args[0], "mqtt/command");
66
- assert.deepEqual(mockAxios.put.firstCall.args[1], {
67
- mac_address: "mockMacAddress",
68
- name: "power",
69
- value: 1,
70
- });
71
- assert.deepEqual(mockAxios.put.firstCall.args[2], {
72
- headers: { Authorization: "Bearer mockToken" },
136
+ // Tests for setPowerOn and setPowerOff
137
+ [
138
+ {
139
+ method: "setPowerOn",
140
+ call: (api: ReturnType<typeof configure>) =>
141
+ api.setPowerOn("mockToken", "mockMacAddress"),
142
+ expectedValue: 1,
143
+ },
144
+ {
145
+ method: "setPowerOff",
146
+ call: (api: ReturnType<typeof configure>) =>
147
+ api.setPowerOff("mockToken", "mockMacAddress"),
148
+ expectedValue: 0,
149
+ },
150
+ ].forEach(({ method, call, expectedValue }) => {
151
+ it(`should call axios for ${method}`, async () => {
152
+ const mockAxios = {
153
+ put: sinon.stub().resolves({ status: 200 }),
154
+ };
155
+ axiosStub.returns(mockAxios);
156
+ const api = configure("https://example.com/api");
157
+
158
+ // Invoke the method using the mapped call function
159
+ const result = await call(api);
160
+ assert.deepEqual(mockAxios.put.args, [
161
+ [
162
+ "mqtt/command",
163
+ {
164
+ mac_address: "mockMacAddress",
165
+ name: "power",
166
+ value: expectedValue,
167
+ },
168
+ {
169
+ headers: { Authorization: "Bearer mockToken" },
170
+ },
171
+ ],
172
+ ]);
173
+ assert.equal(result.status, 200);
73
174
  });
74
- assert.equal(result.status, 200);
75
175
  });
76
176
  });
77
177
  });
package/src/library.ts CHANGED
@@ -2,35 +2,64 @@ import { strict as assert } from "assert";
2
2
  import { Amplify } from "aws-amplify";
3
3
  import * as amplifyAuth from "aws-amplify/auth";
4
4
  import axios, { AxiosInstance } from "axios";
5
- import { DeviceInfoType } from "./types";
5
+
6
6
  import { API_URL } from "./constants";
7
+ import { DeviceInfoType } from "./types";
7
8
 
8
9
  const amplifyconfiguration = {
9
10
  aws_project_region: "eu-central-1",
10
11
  aws_user_pools_id: "eu-central-1_BYmQ2VBlo",
11
12
  aws_user_pools_web_client_id: "7sc1qltkqobo3ddqsk4542dg2h",
12
13
  };
13
- Amplify.configure(amplifyconfiguration);
14
14
 
15
+ /**
16
+ * Generates headers with a JWT token for authenticated requests.
17
+ * @param {string} jwtToken - The JWT token for authorization.
18
+ * @returns {object} - The headers object with the Authorization field.
19
+ */
15
20
  const headers = (jwtToken: string) => ({ Authorization: `Bearer ${jwtToken}` });
16
21
 
17
22
  /**
18
- * Sign in to return the JWT token.
23
+ * Configures Amplify if not already configured.
24
+ * Ensures the configuration is only applied once.
25
+ */
26
+ const configureAmplify = () => {
27
+ const currentConfig = Amplify.getConfig();
28
+ if (Object.keys(currentConfig).length !== 0) return;
29
+ Amplify.configure(amplifyconfiguration);
30
+ };
31
+
32
+ /**
33
+ * Creates an authentication service with sign-in functionality.
34
+ * @param {typeof amplifyAuth} auth - The authentication module to use.
35
+ * @returns {object} - An object containing authentication-related methods.
19
36
  */
20
- const signIn = async (username: string, password: string): Promise<string> => {
21
- // in case the user is already signed in, refs:
22
- // https://github.com/aws-amplify/amplify-js/issues/13813
23
- await amplifyAuth.signOut();
24
- const { isSignedIn, nextStep } = await amplifyAuth.signIn({
25
- username,
26
- password,
27
- });
28
- assert.ok(isSignedIn);
29
- const { tokens } = await amplifyAuth.fetchAuthSession();
30
- assert.ok(tokens);
31
- return tokens.accessToken.toString();
37
+ const createAuthService = (auth: typeof amplifyAuth) => {
38
+ /**
39
+ * Signs in a user with the provided credentials.
40
+ * @param {string} username - The username of the user.
41
+ * @param {string} password - The password of the user.
42
+ * @returns {Promise<string>} - The JWT token of the signed-in user.
43
+ * @throws {Error} - If sign-in fails or no tokens are retrieved.
44
+ */
45
+ const signIn = async (
46
+ username: string,
47
+ password: string
48
+ ): Promise<string> => {
49
+ configureAmplify();
50
+ await auth.signOut(); // Ensure the user is signed out first
51
+ const { isSignedIn } = await auth.signIn({ username, password });
52
+ assert.ok(isSignedIn, "Sign-in failed");
53
+ const { tokens } = await auth.fetchAuthSession();
54
+ assert.ok(tokens, "No tokens found");
55
+ return tokens.accessToken.toString();
56
+ };
57
+ return { signIn };
32
58
  };
33
59
 
60
+ // Create the default auth service using amplifyAuth
61
+ const { signIn } = createAuthService(amplifyAuth);
62
+
34
63
  const deviceInfo =
35
64
  (axiosInstance: AxiosInstance) => (jwtToken: string, macAddress: string) =>
36
65
  axiosInstance.get<DeviceInfoType>(`device/${macAddress}/info`, {
@@ -39,6 +68,7 @@ const deviceInfo =
39
68
 
40
69
  const mqttCommand =
41
70
  (axiosInstance: AxiosInstance) =>
71
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
72
  (jwtToken: string, macAddress: string, payload: any) =>
43
73
  axiosInstance.put(
44
74
  "mqtt/command",
@@ -72,6 +102,4 @@ const configure = (baseURL: string = API_URL) => {
72
102
  };
73
103
  };
74
104
 
75
- const defaultApi = configure();
76
-
77
- export { signIn, configure };
105
+ export { configure, createAuthService, headers, signIn };
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist/esm",
5
+ "module": "es6"
6
+ }
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist/esm",
5
+ "module": "es6"
6
+ }
7
+ }
package/tsconfig.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "module": "commonjs",
4
- "target": "es2015",
5
- "declaration": true,
6
- "outDir": "./dist",
3
+ "target": "es6",
4
+ "target": "es6",
5
+ "moduleResolution": "node",
6
+ "outDir": "dist",
7
7
  "rootDir": "src",
8
8
  "strict": true,
9
+ "declaration": true,
9
10
  "esModuleInterop": true,
10
11
  "resolveJsonModule": true,
12
+ "noUnusedLocals": true,
13
+ "noUnusedParameters": true,
11
14
  "preserveConstEnums": true
12
15
  },
13
- "include": [
14
- "src/**/*.ts"
15
- ]
16
+ "include": ["src/**/*.ts"]
16
17
  }
package/dist/constants.js DELETED
@@ -1,5 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.API_URL = void 0;
4
- const API_URL = "https://fxtj7xkgc6.execute-api.eu-central-1.amazonaws.com/prod/";
5
- exports.API_URL = API_URL;
package/dist/index.js DELETED
@@ -1,11 +0,0 @@
1
- "use strict";
2
- var _a;
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.setPowerOn = exports.setPowerOff = exports.setPower = exports.deviceInfo = exports.configure = exports.signIn = exports.API_URL = void 0;
5
- const library_1 = require("./library");
6
- var constants_1 = require("./constants");
7
- Object.defineProperty(exports, "API_URL", { enumerable: true, get: function () { return constants_1.API_URL; } });
8
- var library_2 = require("./library");
9
- Object.defineProperty(exports, "signIn", { enumerable: true, get: function () { return library_2.signIn; } });
10
- Object.defineProperty(exports, "configure", { enumerable: true, get: function () { return library_2.configure; } });
11
- _a = (0, library_1.configure)(), exports.deviceInfo = _a.deviceInfo, exports.setPower = _a.setPower, exports.setPowerOff = _a.setPowerOff, exports.setPowerOn = _a.setPowerOn;
package/dist/library.d.ts DELETED
@@ -1,12 +0,0 @@
1
- import { DeviceInfoType } from "./types";
2
- /**
3
- * Sign in to return the JWT token.
4
- */
5
- declare const signIn: (username: string, password: string) => Promise<string>;
6
- declare const configure: (baseURL?: string) => {
7
- deviceInfo: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<DeviceInfoType, any>>;
8
- setPower: (jwtToken: string, macAddress: string, value: number) => Promise<import("axios").AxiosResponse<any, any>>;
9
- setPowerOff: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<any, any>>;
10
- setPowerOn: (jwtToken: string, macAddress: string) => Promise<import("axios").AxiosResponse<any, any>>;
11
- };
12
- export { signIn, configure };
package/dist/library.js DELETED
@@ -1,99 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
- return new (P || (P = Promise))(function (resolve, reject) {
38
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
- step((generator = generator.apply(thisArg, _arguments || [])).next());
42
- });
43
- };
44
- var __importDefault = (this && this.__importDefault) || function (mod) {
45
- return (mod && mod.__esModule) ? mod : { "default": mod };
46
- };
47
- Object.defineProperty(exports, "__esModule", { value: true });
48
- exports.configure = exports.signIn = void 0;
49
- const assert_1 = require("assert");
50
- const aws_amplify_1 = require("aws-amplify");
51
- const amplifyAuth = __importStar(require("aws-amplify/auth"));
52
- const axios_1 = __importDefault(require("axios"));
53
- const constants_1 = require("./constants");
54
- const amplifyconfiguration = {
55
- aws_project_region: "eu-central-1",
56
- aws_user_pools_id: "eu-central-1_BYmQ2VBlo",
57
- aws_user_pools_web_client_id: "7sc1qltkqobo3ddqsk4542dg2h",
58
- };
59
- aws_amplify_1.Amplify.configure(amplifyconfiguration);
60
- const headers = (jwtToken) => ({ Authorization: `Bearer ${jwtToken}` });
61
- /**
62
- * Sign in to return the JWT token.
63
- */
64
- const signIn = (username, password) => __awaiter(void 0, void 0, void 0, function* () {
65
- // in case the user is already signed in, refs:
66
- // https://github.com/aws-amplify/amplify-js/issues/13813
67
- yield amplifyAuth.signOut();
68
- const { isSignedIn, nextStep } = yield amplifyAuth.signIn({
69
- username,
70
- password,
71
- });
72
- assert_1.strict.ok(isSignedIn);
73
- const { tokens } = yield amplifyAuth.fetchAuthSession();
74
- assert_1.strict.ok(tokens);
75
- return tokens.accessToken.toString();
76
- });
77
- exports.signIn = signIn;
78
- const deviceInfo = (axiosInstance) => (jwtToken, macAddress) => axiosInstance.get(`device/${macAddress}/info`, {
79
- headers: headers(jwtToken),
80
- });
81
- const mqttCommand = (axiosInstance) => (jwtToken, macAddress, payload) => axiosInstance.put("mqtt/command", Object.assign({ mac_address: macAddress }, payload), { headers: headers(jwtToken) });
82
- const setPower = (axiosInstance) => (jwtToken, macAddress, value) => mqttCommand(axiosInstance)(jwtToken, macAddress, { name: "power", value });
83
- const setPowerOn = (axiosInstance) => (jwtToken, macAddress) => setPower(axiosInstance)(jwtToken, macAddress, 1);
84
- const setPowerOff = (axiosInstance) => (jwtToken, macAddress) => setPower(axiosInstance)(jwtToken, macAddress, 0);
85
- const configure = (baseURL = constants_1.API_URL) => {
86
- const axiosInstance = axios_1.default.create({ baseURL });
87
- const deviceInfoInstance = deviceInfo(axiosInstance);
88
- const setPowerInstance = setPower(axiosInstance);
89
- const setPowerOffInstance = setPowerOff(axiosInstance);
90
- const setPowerOnInstance = setPowerOn(axiosInstance);
91
- return {
92
- deviceInfo: deviceInfoInstance,
93
- setPower: setPowerInstance,
94
- setPowerOff: setPowerOffInstance,
95
- setPowerOn: setPowerOnInstance,
96
- };
97
- };
98
- exports.configure = configure;
99
- const defaultApi = configure();
@@ -1,81 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- const assert_1 = require("assert");
16
- const sinon_1 = __importDefault(require("sinon"));
17
- const axios_1 = __importDefault(require("axios"));
18
- const library_1 = require("../src/library");
19
- describe("library", () => {
20
- let axiosStub;
21
- beforeEach(() => {
22
- axiosStub = sinon_1.default.stub(axios_1.default, "create").returns({
23
- get: sinon_1.default.stub(),
24
- put: sinon_1.default.stub(),
25
- });
26
- });
27
- afterEach(() => {
28
- sinon_1.default.restore();
29
- });
30
- describe("configure", () => {
31
- it("should create API methods with the correct baseURL", () => {
32
- const baseURL = "https://example.com/api";
33
- const api = (0, library_1.configure)(baseURL);
34
- assert_1.strict.ok(axiosStub.calledOnce);
35
- assert_1.strict.deepEqual(axiosStub.firstCall.args[0], { baseURL });
36
- assert_1.strict.deepEqual(Object.keys(api), [
37
- "deviceInfo",
38
- "setPower",
39
- "setPowerOff",
40
- "setPowerOn",
41
- ]);
42
- });
43
- });
44
- describe("API Methods", () => {
45
- it("should call axios for deviceInfo", () => __awaiter(void 0, void 0, void 0, function* () {
46
- const mockAxios = {
47
- get: sinon_1.default
48
- .stub()
49
- .resolves({ data: { id: "123", name: "Mock Device" } }),
50
- };
51
- axiosStub.returns(mockAxios);
52
- const api = (0, library_1.configure)("https://example.com/api");
53
- const result = yield api.deviceInfo("mockToken", "mockMacAddress");
54
- assert_1.strict.ok(mockAxios.get.calledOnce);
55
- assert_1.strict.equal(mockAxios.get.firstCall.args[0], "device/mockMacAddress/info");
56
- assert_1.strict.deepEqual(mockAxios.get.firstCall.args[1], {
57
- headers: { Authorization: "Bearer mockToken" },
58
- });
59
- assert_1.strict.deepEqual(result.data, { id: "123", name: "Mock Device" });
60
- }));
61
- it("should call axios for setPowerOn", () => __awaiter(void 0, void 0, void 0, function* () {
62
- const mockAxios = {
63
- put: sinon_1.default.stub().resolves({ status: 200 }),
64
- };
65
- axiosStub.returns(mockAxios);
66
- const api = (0, library_1.configure)("https://example.com/api");
67
- const result = yield api.setPowerOn("mockToken", "mockMacAddress");
68
- assert_1.strict.ok(mockAxios.put.calledOnce);
69
- assert_1.strict.equal(mockAxios.put.firstCall.args[0], "mqtt/command");
70
- assert_1.strict.deepEqual(mockAxios.put.firstCall.args[1], {
71
- mac_address: "mockMacAddress",
72
- name: "power",
73
- value: 1,
74
- });
75
- assert_1.strict.deepEqual(mockAxios.put.firstCall.args[2], {
76
- headers: { Authorization: "Bearer mockToken" },
77
- });
78
- assert_1.strict.equal(result.status, 200);
79
- }));
80
- });
81
- });
package/dist/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
File without changes
File without changes
File without changes