edilkamin 1.7.3 → 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/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/cjs/src/index.js +22 -0
- 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.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/{browser-bundle.test.js → src/browser-bundle.test.js} +1 -1
- 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/constants.d.ts +4 -0
- package/dist/esm/src/index.d.ts +6 -0
- package/dist/esm/src/library.d.ts +55 -0
- package/dist/esm/src/library.test.d.ts +1 -0
- 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 +10 -10
- package/src/browser-bundle.test.ts +1 -1
- package/tsconfig.cjs.json +2 -2
- package/tsconfig.json +2 -3
- /package/dist/{esm → cjs/src}/browser-bundle.test.d.ts +0 -0
- /package/dist/{esm → cjs/src}/buffer-utils.d.ts +0 -0
- /package/dist/{esm → cjs/src}/buffer-utils.test.d.ts +0 -0
- /package/dist/{esm → cjs/src}/cli.d.ts +0 -0
- /package/dist/{esm → cjs/src}/configureAmplify.test.d.ts +0 -0
- /package/dist/{esm → cjs/src}/constants.d.ts +0 -0
- /package/dist/{esm → cjs/src}/index.d.ts +0 -0
- /package/dist/{esm → cjs/src}/library.d.ts +0 -0
- /package/dist/{esm → cjs/src}/library.test.d.ts +0 -0
- /package/dist/{esm → cjs/src}/serial-utils.d.ts +0 -0
- /package/dist/{esm → cjs/src}/serial-utils.test.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/{types.js → src/browser-bundle.test.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/{configureAmplify.test.js → src/configureAmplify.test.js} +0 -0
- /package/dist/esm/{constants.js → src/constants.js} +0 -0
- /package/dist/esm/{index.js → src/index.js} +0 -0
- /package/dist/esm/{library.js → src/library.js} +0 -0
- /package/dist/esm/{library.test.js → src/library.test.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
|
@@ -18,3 +18,9 @@ jobs:
|
|
|
18
18
|
node-version: ${{ matrix.node-version }}
|
|
19
19
|
- run: yarn install --no-ignore-optional
|
|
20
20
|
- run: yarn cli --help
|
|
21
|
+
- run: yarn build
|
|
22
|
+
- run: node dist/cjs/src/cli.js --help
|
|
23
|
+
- name: Verify CLI binary
|
|
24
|
+
run: |
|
|
25
|
+
test -f dist/cjs/src/cli.js
|
|
26
|
+
grep -q "#!/usr/bin/env node" dist/cjs/src/cli.js
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "edilkamin",
|
|
3
|
+
"version": "1.7.4",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/cjs/src/index.js",
|
|
6
|
+
"module": "dist/esm/src/index.js",
|
|
7
|
+
"types": "dist/esm/src/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/esm/src/index.d.ts",
|
|
12
|
+
"default": "./dist/esm/src/index.js"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/cjs/src/index.d.ts",
|
|
16
|
+
"default": "./dist/cjs/src/index.js"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"cli": "ts-node src/cli.ts",
|
|
22
|
+
"cli:debug": "node --inspect --require ts-node/register/transpile-only src/cli.ts",
|
|
23
|
+
"test": "nyc mocha --require ts-node/register src/*.test.ts",
|
|
24
|
+
"test:debug": "nyc mocha --require ts-node/register/transpile-only --inspect src/*.test.ts",
|
|
25
|
+
"lint:prettier": "prettier --check src docs .github *.json *.md *.mjs",
|
|
26
|
+
"format:prettier": "prettier --write src docs .github *.json *.md *.mjs",
|
|
27
|
+
"lint:eslint": "eslint src",
|
|
28
|
+
"format:eslint": "eslint --fix src",
|
|
29
|
+
"lint": "yarn lint:prettier && yarn lint:eslint",
|
|
30
|
+
"format": "yarn format:prettier && yarn format:eslint",
|
|
31
|
+
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
32
|
+
"build:esm": "tsc -p tsconfig.esm.json",
|
|
33
|
+
"build": "npm run build:cjs && npm run build:esm"
|
|
34
|
+
},
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/AndreMiras/edilkamin.js.git"
|
|
38
|
+
},
|
|
39
|
+
"author": "Andre Miras",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/AndreMiras/edilkamin.js/issues"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://github.com/AndreMiras/edilkamin.js#readme",
|
|
45
|
+
"bin": {
|
|
46
|
+
"edilkamin": "dist/cjs/src/cli.js"
|
|
47
|
+
},
|
|
48
|
+
"nyc": {
|
|
49
|
+
"reporter": [
|
|
50
|
+
"html",
|
|
51
|
+
"lcov",
|
|
52
|
+
"text"
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"aws-amplify": "^6.10.0",
|
|
57
|
+
"pako": "^2.1.0"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@eslint/eslintrc": "^3.2.0",
|
|
61
|
+
"@eslint/js": "^9.16.0",
|
|
62
|
+
"@types/mocha": "^10.0.10",
|
|
63
|
+
"@types/node": "^25.0.2",
|
|
64
|
+
"@types/pako": "^2.0.4",
|
|
65
|
+
"@types/sinon": "^17.0.3",
|
|
66
|
+
"@typescript-eslint/eslint-plugin": "^8.17.0",
|
|
67
|
+
"@typescript-eslint/parser": "^8.17.0",
|
|
68
|
+
"esbuild": "^0.27.1",
|
|
69
|
+
"eslint": "^9.16.0",
|
|
70
|
+
"eslint-config-prettier": "^10.1.8",
|
|
71
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
72
|
+
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
73
|
+
"mocha": "^11.7.5",
|
|
74
|
+
"nyc": "^17.1.0",
|
|
75
|
+
"prettier": "^3.7.4",
|
|
76
|
+
"sinon": "^19.0.2",
|
|
77
|
+
"ts-node": "^10.9.1",
|
|
78
|
+
"typedoc": "^0.28.15",
|
|
79
|
+
"typescript": "^5.7.2"
|
|
80
|
+
},
|
|
81
|
+
"optionalDependencies": {
|
|
82
|
+
"commander": "^12.1.0"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
const assert_1 = require("assert");
|
|
46
|
+
const esbuild = __importStar(require("esbuild"));
|
|
47
|
+
describe("browser-bundle", () => {
|
|
48
|
+
it("should bundle for browser without Node.js built-ins", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
49
|
+
// This test verifies that the library can be bundled for browser environments
|
|
50
|
+
// without requiring Node.js built-in modules (fs, os, path).
|
|
51
|
+
// If this test fails, it means Node.js-only code has leaked into the main exports.
|
|
52
|
+
const result = yield esbuild.build({
|
|
53
|
+
entryPoints: ["dist/esm/src/index.js"],
|
|
54
|
+
platform: "browser",
|
|
55
|
+
bundle: true,
|
|
56
|
+
write: false,
|
|
57
|
+
// External dependencies that are expected (real deps + assert which is used for validation)
|
|
58
|
+
external: ["aws-amplify", "aws-amplify/*", "pako", "assert"],
|
|
59
|
+
logLevel: "silent",
|
|
60
|
+
});
|
|
61
|
+
// If we get here without error, the bundle succeeded
|
|
62
|
+
assert_1.strict.ok(result.outputFiles.length > 0, "Bundle should produce output");
|
|
63
|
+
}));
|
|
64
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.processResponse = exports.isBuffer = exports.decompressBuffer = void 0;
|
|
7
|
+
const pako_1 = __importDefault(require("pako"));
|
|
8
|
+
/**
|
|
9
|
+
* Type guard to check if a value is a serialized Node.js Buffer.
|
|
10
|
+
* Node.js Buffers serialize to JSON as: {type: "Buffer", data: [...]}
|
|
11
|
+
*
|
|
12
|
+
* @param value - The value to check
|
|
13
|
+
* @returns True if the value is a Buffer-encoded object
|
|
14
|
+
*/
|
|
15
|
+
const isBuffer = (value) => {
|
|
16
|
+
return (typeof value === "object" &&
|
|
17
|
+
value !== null &&
|
|
18
|
+
"type" in value &&
|
|
19
|
+
value.type === "Buffer" &&
|
|
20
|
+
"data" in value &&
|
|
21
|
+
Array.isArray(value.data));
|
|
22
|
+
};
|
|
23
|
+
exports.isBuffer = isBuffer;
|
|
24
|
+
/**
|
|
25
|
+
* Decompresses a Buffer-encoded gzip object and parses the resulting JSON.
|
|
26
|
+
*
|
|
27
|
+
* @param bufferObj - A serialized Buffer object containing gzip data
|
|
28
|
+
* @returns The decompressed and parsed JSON data, or the original object on failure
|
|
29
|
+
*/
|
|
30
|
+
const decompressBuffer = (bufferObj) => {
|
|
31
|
+
try {
|
|
32
|
+
// Convert data array to Uint8Array for pako
|
|
33
|
+
const compressed = new Uint8Array(bufferObj.data);
|
|
34
|
+
// Decompress with gzip
|
|
35
|
+
const decompressed = pako_1.default.ungzip(compressed, { to: "string" });
|
|
36
|
+
// Parse JSON
|
|
37
|
+
return JSON.parse(decompressed);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
// Log warning but return original to maintain backward compatibility
|
|
41
|
+
console.warn("Failed to decompress buffer:", error);
|
|
42
|
+
return bufferObj;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
exports.decompressBuffer = decompressBuffer;
|
|
46
|
+
/**
|
|
47
|
+
* Recursively processes an API response to decompress any Buffer-encoded fields.
|
|
48
|
+
* Handles nested objects and arrays, preserving structure while decompressing.
|
|
49
|
+
*
|
|
50
|
+
* @param data - The API response data to process
|
|
51
|
+
* @returns The processed data with all Buffer fields decompressed
|
|
52
|
+
*/
|
|
53
|
+
const processResponse = (data) => {
|
|
54
|
+
if (data === null || data === undefined) {
|
|
55
|
+
return data;
|
|
56
|
+
}
|
|
57
|
+
// Check if this is a Buffer object
|
|
58
|
+
if (isBuffer(data)) {
|
|
59
|
+
const decompressed = decompressBuffer(data);
|
|
60
|
+
// Recursively process the decompressed result (may contain nested buffers)
|
|
61
|
+
return processResponse(decompressed);
|
|
62
|
+
}
|
|
63
|
+
// Recursively process arrays
|
|
64
|
+
if (Array.isArray(data)) {
|
|
65
|
+
return data.map((item) => processResponse(item));
|
|
66
|
+
}
|
|
67
|
+
// Recursively process objects
|
|
68
|
+
if (typeof data === "object") {
|
|
69
|
+
const processed = {};
|
|
70
|
+
for (const [key, value] of Object.entries(data)) {
|
|
71
|
+
processed[key] = processResponse(value);
|
|
72
|
+
}
|
|
73
|
+
return processed;
|
|
74
|
+
}
|
|
75
|
+
// Primitive value, return as-is
|
|
76
|
+
return data;
|
|
77
|
+
};
|
|
78
|
+
exports.processResponse = processResponse;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const assert_1 = require("assert");
|
|
7
|
+
const pako_1 = __importDefault(require("pako"));
|
|
8
|
+
const sinon_1 = __importDefault(require("sinon"));
|
|
9
|
+
const buffer_utils_1 = require("./buffer-utils");
|
|
10
|
+
/**
|
|
11
|
+
* Helper to create a gzip-compressed Buffer object for testing.
|
|
12
|
+
*/
|
|
13
|
+
const createGzippedBuffer = (data) => {
|
|
14
|
+
const json = JSON.stringify(data);
|
|
15
|
+
const compressed = pako_1.default.gzip(json);
|
|
16
|
+
return {
|
|
17
|
+
type: "Buffer",
|
|
18
|
+
data: Array.from(compressed),
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
describe("buffer-utils", () => {
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
sinon_1.default.restore();
|
|
24
|
+
});
|
|
25
|
+
describe("isBuffer", () => {
|
|
26
|
+
it("should detect valid Buffer objects", () => {
|
|
27
|
+
const buffer = { type: "Buffer", data: [31, 139, 8, 0] };
|
|
28
|
+
assert_1.strict.ok((0, buffer_utils_1.isBuffer)(buffer));
|
|
29
|
+
});
|
|
30
|
+
it("should detect empty Buffer objects", () => {
|
|
31
|
+
const buffer = { type: "Buffer", data: [] };
|
|
32
|
+
assert_1.strict.ok((0, buffer_utils_1.isBuffer)(buffer));
|
|
33
|
+
});
|
|
34
|
+
it("should reject non-Buffer objects with wrong type", () => {
|
|
35
|
+
assert_1.strict.ok(!(0, buffer_utils_1.isBuffer)({ type: "NotBuffer", data: [] }));
|
|
36
|
+
});
|
|
37
|
+
it("should reject objects without type field", () => {
|
|
38
|
+
assert_1.strict.ok(!(0, buffer_utils_1.isBuffer)({ data: [1, 2, 3] }));
|
|
39
|
+
});
|
|
40
|
+
it("should reject objects without data field", () => {
|
|
41
|
+
assert_1.strict.ok(!(0, buffer_utils_1.isBuffer)({ type: "Buffer" }));
|
|
42
|
+
});
|
|
43
|
+
it("should reject objects with non-array data", () => {
|
|
44
|
+
assert_1.strict.ok(!(0, buffer_utils_1.isBuffer)({ type: "Buffer", data: "not an array" }));
|
|
45
|
+
});
|
|
46
|
+
it("should reject null", () => {
|
|
47
|
+
assert_1.strict.ok(!(0, buffer_utils_1.isBuffer)(null));
|
|
48
|
+
});
|
|
49
|
+
it("should reject undefined", () => {
|
|
50
|
+
assert_1.strict.ok(!(0, buffer_utils_1.isBuffer)(undefined));
|
|
51
|
+
});
|
|
52
|
+
it("should reject primitives", () => {
|
|
53
|
+
assert_1.strict.ok(!(0, buffer_utils_1.isBuffer)("string"));
|
|
54
|
+
assert_1.strict.ok(!(0, buffer_utils_1.isBuffer)(123));
|
|
55
|
+
assert_1.strict.ok(!(0, buffer_utils_1.isBuffer)(true));
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
describe("decompressBuffer", () => {
|
|
59
|
+
it("should decompress gzipped JSON buffer", () => {
|
|
60
|
+
const originalData = { test: "value", nested: { key: 123 } };
|
|
61
|
+
const bufferObj = createGzippedBuffer(originalData);
|
|
62
|
+
const result = (0, buffer_utils_1.decompressBuffer)(bufferObj);
|
|
63
|
+
assert_1.strict.deepEqual(result, originalData);
|
|
64
|
+
});
|
|
65
|
+
it("should handle gzipped arrays", () => {
|
|
66
|
+
const originalData = [1, 2, 3, "test"];
|
|
67
|
+
const bufferObj = createGzippedBuffer(originalData);
|
|
68
|
+
const result = (0, buffer_utils_1.decompressBuffer)(bufferObj);
|
|
69
|
+
assert_1.strict.deepEqual(result, originalData);
|
|
70
|
+
});
|
|
71
|
+
it("should handle gzipped strings", () => {
|
|
72
|
+
const originalData = "test string";
|
|
73
|
+
const bufferObj = createGzippedBuffer(originalData);
|
|
74
|
+
const result = (0, buffer_utils_1.decompressBuffer)(bufferObj);
|
|
75
|
+
assert_1.strict.equal(result, originalData);
|
|
76
|
+
});
|
|
77
|
+
it("should return original value if decompression fails", () => {
|
|
78
|
+
const consoleWarnStub = sinon_1.default.stub(console, "warn");
|
|
79
|
+
const invalidBuffer = { type: "Buffer", data: [1, 2, 3] };
|
|
80
|
+
const result = (0, buffer_utils_1.decompressBuffer)(invalidBuffer);
|
|
81
|
+
assert_1.strict.deepEqual(result, invalidBuffer);
|
|
82
|
+
assert_1.strict.ok(consoleWarnStub.calledOnce);
|
|
83
|
+
});
|
|
84
|
+
it("should return original value if JSON parsing fails", () => {
|
|
85
|
+
const consoleWarnStub = sinon_1.default.stub(console, "warn");
|
|
86
|
+
// Create valid gzip but invalid JSON
|
|
87
|
+
const invalidJson = "not valid json {";
|
|
88
|
+
const compressed = pako_1.default.gzip(invalidJson);
|
|
89
|
+
const bufferObj = {
|
|
90
|
+
type: "Buffer",
|
|
91
|
+
data: Array.from(compressed),
|
|
92
|
+
};
|
|
93
|
+
const result = (0, buffer_utils_1.decompressBuffer)(bufferObj);
|
|
94
|
+
assert_1.strict.deepEqual(result, bufferObj);
|
|
95
|
+
assert_1.strict.ok(consoleWarnStub.calledOnce);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe("processResponse", () => {
|
|
99
|
+
it("should pass through null", () => {
|
|
100
|
+
assert_1.strict.equal((0, buffer_utils_1.processResponse)(null), null);
|
|
101
|
+
});
|
|
102
|
+
it("should pass through undefined", () => {
|
|
103
|
+
assert_1.strict.equal((0, buffer_utils_1.processResponse)(undefined), undefined);
|
|
104
|
+
});
|
|
105
|
+
it("should pass through primitives", () => {
|
|
106
|
+
assert_1.strict.equal((0, buffer_utils_1.processResponse)("string"), "string");
|
|
107
|
+
assert_1.strict.equal((0, buffer_utils_1.processResponse)(123), 123);
|
|
108
|
+
assert_1.strict.equal((0, buffer_utils_1.processResponse)(true), true);
|
|
109
|
+
});
|
|
110
|
+
it("should pass through plain objects", () => {
|
|
111
|
+
const obj = { key: "value", nested: { num: 42 } };
|
|
112
|
+
assert_1.strict.deepEqual((0, buffer_utils_1.processResponse)(obj), obj);
|
|
113
|
+
});
|
|
114
|
+
it("should pass through plain arrays", () => {
|
|
115
|
+
const arr = [1, "two", { three: 3 }];
|
|
116
|
+
assert_1.strict.deepEqual((0, buffer_utils_1.processResponse)(arr), arr);
|
|
117
|
+
});
|
|
118
|
+
it("should decompress Buffer at root level", () => {
|
|
119
|
+
const originalData = { decompressed: true };
|
|
120
|
+
const buffer = createGzippedBuffer(originalData);
|
|
121
|
+
const result = (0, buffer_utils_1.processResponse)(buffer);
|
|
122
|
+
assert_1.strict.deepEqual(result, originalData);
|
|
123
|
+
});
|
|
124
|
+
it("should decompress nested Buffer fields", () => {
|
|
125
|
+
const statusData = { commands: { power: true } };
|
|
126
|
+
const response = {
|
|
127
|
+
plain: "data",
|
|
128
|
+
status: createGzippedBuffer(statusData),
|
|
129
|
+
};
|
|
130
|
+
const result = (0, buffer_utils_1.processResponse)(response);
|
|
131
|
+
assert_1.strict.equal(result.plain, "data");
|
|
132
|
+
assert_1.strict.deepEqual(result.status, statusData);
|
|
133
|
+
});
|
|
134
|
+
it("should recursively decompress deeply nested Buffers", () => {
|
|
135
|
+
const innerData = { value: 42 };
|
|
136
|
+
const middleData = { inner: createGzippedBuffer(innerData) };
|
|
137
|
+
const response = {
|
|
138
|
+
outer: createGzippedBuffer(middleData),
|
|
139
|
+
};
|
|
140
|
+
const result = (0, buffer_utils_1.processResponse)(response);
|
|
141
|
+
assert_1.strict.deepEqual(result, { outer: { inner: { value: 42 } } });
|
|
142
|
+
});
|
|
143
|
+
it("should handle arrays containing Buffers", () => {
|
|
144
|
+
const itemData = { id: 1 };
|
|
145
|
+
const response = {
|
|
146
|
+
items: [createGzippedBuffer(itemData), { id: 2 }],
|
|
147
|
+
};
|
|
148
|
+
const result = (0, buffer_utils_1.processResponse)(response);
|
|
149
|
+
assert_1.strict.deepEqual(result.items, [{ id: 1 }, { id: 2 }]);
|
|
150
|
+
});
|
|
151
|
+
it("should handle mixed compressed and uncompressed fields", () => {
|
|
152
|
+
const compressedStatus = { commands: { power: true } };
|
|
153
|
+
const response = {
|
|
154
|
+
status: createGzippedBuffer(compressedStatus),
|
|
155
|
+
nvm: { user_parameters: { temperature: 22 } },
|
|
156
|
+
plain_field: "unchanged",
|
|
157
|
+
};
|
|
158
|
+
const result = (0, buffer_utils_1.processResponse)(response);
|
|
159
|
+
assert_1.strict.deepEqual(result.status, compressedStatus);
|
|
160
|
+
assert_1.strict.deepEqual(result.nvm, { user_parameters: { temperature: 22 } });
|
|
161
|
+
assert_1.strict.equal(result.plain_field, "unchanged");
|
|
162
|
+
});
|
|
163
|
+
it("should handle real-world DeviceInfo structure with compressed status", () => {
|
|
164
|
+
const statusData = {
|
|
165
|
+
commands: { power: true },
|
|
166
|
+
temperatures: { board: 25, enviroment: 20 },
|
|
167
|
+
};
|
|
168
|
+
const nvmData = {
|
|
169
|
+
user_parameters: {
|
|
170
|
+
enviroment_1_temperature: 22,
|
|
171
|
+
enviroment_2_temperature: 0,
|
|
172
|
+
enviroment_3_temperature: 0,
|
|
173
|
+
is_auto: false,
|
|
174
|
+
is_sound_active: true,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
const response = {
|
|
178
|
+
status: createGzippedBuffer(statusData),
|
|
179
|
+
nvm: createGzippedBuffer(nvmData),
|
|
180
|
+
};
|
|
181
|
+
const result = (0, buffer_utils_1.processResponse)(response);
|
|
182
|
+
assert_1.strict.deepEqual(result.status, statusData);
|
|
183
|
+
assert_1.strict.deepEqual(result.nvm, nvmData);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
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 commander_1 = require("commander");
|
|
18
|
+
const readline_1 = __importDefault(require("readline"));
|
|
19
|
+
const package_json_1 = require("../package.json");
|
|
20
|
+
const constants_1 = require("./constants");
|
|
21
|
+
const library_1 = require("./library");
|
|
22
|
+
const token_storage_1 = require("./token-storage");
|
|
23
|
+
const promptPassword = () => {
|
|
24
|
+
const rl = readline_1.default.createInterface({
|
|
25
|
+
input: process.stdin,
|
|
26
|
+
output: process.stdout,
|
|
27
|
+
terminal: true,
|
|
28
|
+
});
|
|
29
|
+
return new Promise((resolve) => {
|
|
30
|
+
rl.question("Enter password: ", (password) => {
|
|
31
|
+
// Hide the password input
|
|
32
|
+
readline_1.default.moveCursor(process.stdout, 0, -1);
|
|
33
|
+
readline_1.default.clearLine(process.stdout, 0);
|
|
34
|
+
rl.close();
|
|
35
|
+
resolve(password);
|
|
36
|
+
});
|
|
37
|
+
// Disable input echoing for password
|
|
38
|
+
process.stdin.on("data", (char) => {
|
|
39
|
+
if (char.toString("hex") === "0d0a")
|
|
40
|
+
return; // Enter key
|
|
41
|
+
process.stdout.write("*");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Adds common options (username and password) to a command.
|
|
47
|
+
* Username is optional if a session already exists.
|
|
48
|
+
* @param command The command to which options should be added.
|
|
49
|
+
* @returns The command with options added.
|
|
50
|
+
*/
|
|
51
|
+
const addAuthOptions = (command) => command
|
|
52
|
+
.option("-u, --username <username>", "Username (optional if session exists)")
|
|
53
|
+
.option("-p, --password <password>", "Password");
|
|
54
|
+
/**
|
|
55
|
+
* Adds MAC address option to a command.
|
|
56
|
+
* @param command The command to which the MAC address option should be added.
|
|
57
|
+
* @returns The command with the MAC address option added.
|
|
58
|
+
*/
|
|
59
|
+
const addMacOption = (command) => command.requiredOption("-m, --mac <macAddress>", "MAC address of the device");
|
|
60
|
+
/**
|
|
61
|
+
* Adds legacy API option to a command.
|
|
62
|
+
* @param command The command to which the legacy option should be added.
|
|
63
|
+
* @returns The command with the legacy option added.
|
|
64
|
+
*/
|
|
65
|
+
const addLegacyOption = (command) => command.option("--legacy", "Use legacy API endpoint (old AWS Gateway)");
|
|
66
|
+
/**
|
|
67
|
+
* Handles common authentication and API initialization logic.
|
|
68
|
+
* Tries to use existing session first, falls back to sign-in if needed.
|
|
69
|
+
* @param options The options passed from the CLI command.
|
|
70
|
+
* @returns An object containing the normalized MAC, JWT token, and configured API instance.
|
|
71
|
+
*/
|
|
72
|
+
const initializeCommand = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
73
|
+
const { username, password, mac, legacy = false } = options;
|
|
74
|
+
const normalizedMac = mac.replace(/:/g, "");
|
|
75
|
+
// Initialize file storage for session persistence
|
|
76
|
+
const storage = (0, token_storage_1.createFileStorage)();
|
|
77
|
+
(0, library_1.configureAmplify)(storage);
|
|
78
|
+
let jwtToken;
|
|
79
|
+
try {
|
|
80
|
+
// Try to get existing session first
|
|
81
|
+
jwtToken = yield (0, library_1.getSession)(false, legacy);
|
|
82
|
+
}
|
|
83
|
+
catch (_a) {
|
|
84
|
+
// No session, need to sign in
|
|
85
|
+
if (!username) {
|
|
86
|
+
throw new Error("No session found. Please provide --username to sign in.");
|
|
87
|
+
}
|
|
88
|
+
const pwd = password || (yield promptPassword());
|
|
89
|
+
jwtToken = yield (0, library_1.signIn)(username, pwd, legacy);
|
|
90
|
+
}
|
|
91
|
+
const apiUrl = legacy ? constants_1.OLD_API_URL : constants_1.NEW_API_URL;
|
|
92
|
+
const api = (0, library_1.configure)(apiUrl);
|
|
93
|
+
return { normalizedMac, jwtToken, api };
|
|
94
|
+
});
|
|
95
|
+
/**
|
|
96
|
+
* Executes a getter command by handling common steps (authentication, API initialization).
|
|
97
|
+
* @param options The options passed from the CLI command.
|
|
98
|
+
* @param getter A function to call on the configured API object.
|
|
99
|
+
*/
|
|
100
|
+
const executeGetter = (options, getter) => __awaiter(void 0, void 0, void 0, function* () {
|
|
101
|
+
const { normalizedMac, jwtToken, api } = yield initializeCommand(options);
|
|
102
|
+
const result = yield getter(api, jwtToken, normalizedMac);
|
|
103
|
+
console.log(result);
|
|
104
|
+
});
|
|
105
|
+
/**
|
|
106
|
+
* Executes a setter command by handling common steps (authentication, API initialization).
|
|
107
|
+
* @param options The options passed from the CLI command.
|
|
108
|
+
* @param setter A function to call on the configured API object.
|
|
109
|
+
*/
|
|
110
|
+
const executeSetter = (options, setter) => __awaiter(void 0, void 0, void 0, function* () {
|
|
111
|
+
const { normalizedMac, jwtToken, api } = yield initializeCommand(options);
|
|
112
|
+
const result = yield setter(api, jwtToken, normalizedMac, options.value);
|
|
113
|
+
console.log(result);
|
|
114
|
+
});
|
|
115
|
+
const createProgram = () => {
|
|
116
|
+
const program = new commander_1.Command();
|
|
117
|
+
program
|
|
118
|
+
.name("edilkamin-cli")
|
|
119
|
+
.description("CLI tool for interacting with the Edilkamin API")
|
|
120
|
+
.version(package_json_1.version);
|
|
121
|
+
// Command: signIn
|
|
122
|
+
program
|
|
123
|
+
.command("signIn")
|
|
124
|
+
.description("Sign in and retrieve a JWT token")
|
|
125
|
+
.requiredOption("-u, --username <username>", "Username")
|
|
126
|
+
.option("-p, --password <password>", "Password")
|
|
127
|
+
.action((options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
128
|
+
const { username, password } = options;
|
|
129
|
+
// Initialize file storage for session persistence
|
|
130
|
+
const storage = (0, token_storage_1.createFileStorage)();
|
|
131
|
+
(0, library_1.configureAmplify)(storage);
|
|
132
|
+
const pwd = password || (yield promptPassword());
|
|
133
|
+
const jwtToken = yield (0, library_1.signIn)(username, pwd);
|
|
134
|
+
console.log("JWT Token:", jwtToken);
|
|
135
|
+
}));
|
|
136
|
+
// Command: logout
|
|
137
|
+
program
|
|
138
|
+
.command("logout")
|
|
139
|
+
.description("Clear stored session")
|
|
140
|
+
.action(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
141
|
+
yield (0, token_storage_1.clearSession)();
|
|
142
|
+
console.log("Session cleared successfully");
|
|
143
|
+
}));
|
|
144
|
+
// Generic getter commands
|
|
145
|
+
[
|
|
146
|
+
{
|
|
147
|
+
commandName: "deviceInfo",
|
|
148
|
+
description: "Retrieve device info for a specific MAC address",
|
|
149
|
+
getter: (api, jwtToken, mac) => api.deviceInfo(jwtToken, mac),
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
commandName: "getPower",
|
|
153
|
+
description: "Retrieve device power status",
|
|
154
|
+
getter: (api, jwtToken, mac) => api.getPower(jwtToken, mac),
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
commandName: "getEnvironmentTemperature",
|
|
158
|
+
description: "Retrieve environment temperature",
|
|
159
|
+
getter: (api, jwtToken, mac) => api.getEnvironmentTemperature(jwtToken, mac),
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
commandName: "getTargetTemperature",
|
|
163
|
+
description: "Retrieve target temperature",
|
|
164
|
+
getter: (api, jwtToken, mac) => api.getTargetTemperature(jwtToken, mac),
|
|
165
|
+
},
|
|
166
|
+
].forEach(({ commandName, description, getter }) => {
|
|
167
|
+
addLegacyOption(addMacOption(addAuthOptions(program.command(commandName).description(description)))).action((options) => executeGetter(options, getter));
|
|
168
|
+
});
|
|
169
|
+
// Generic setter commands
|
|
170
|
+
[
|
|
171
|
+
{
|
|
172
|
+
commandName: "setPower",
|
|
173
|
+
description: "Set the power state of the device (1 for ON, 0 for OFF)",
|
|
174
|
+
setter: (api, jwtToken, mac, value) => api.setPower(jwtToken, mac, value),
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
commandName: "setTargetTemperature",
|
|
178
|
+
description: "Set the target temperature (degree celsius) for a device",
|
|
179
|
+
setter: (api, jwtToken, mac, value) => api.setTargetTemperature(jwtToken, mac, value),
|
|
180
|
+
},
|
|
181
|
+
].forEach(({ commandName, description, setter }) => {
|
|
182
|
+
addLegacyOption(addMacOption(addAuthOptions(program.command(commandName).description(description)).requiredOption("-v, --value <number>", "Value to set", parseFloat))).action((options) => executeSetter(options, setter));
|
|
183
|
+
});
|
|
184
|
+
// Command: register
|
|
185
|
+
addLegacyOption(addAuthOptions(program
|
|
186
|
+
.command("register")
|
|
187
|
+
.description("Register a device with your account")))
|
|
188
|
+
.requiredOption("-m, --mac <macAddress>", "MAC address of the device")
|
|
189
|
+
.requiredOption("-s, --serial <serialNumber>", "Device serial number")
|
|
190
|
+
.requiredOption("-n, --name <deviceName>", "Device name")
|
|
191
|
+
.requiredOption("-r, --room <deviceRoom>", "Room name")
|
|
192
|
+
.action((options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
193
|
+
const { username, password, mac, serial, name, room, legacy = false, } = options;
|
|
194
|
+
const normalizedMac = mac.replace(/:/g, "");
|
|
195
|
+
// Initialize file storage for session persistence
|
|
196
|
+
const storage = (0, token_storage_1.createFileStorage)();
|
|
197
|
+
(0, library_1.configureAmplify)(storage);
|
|
198
|
+
let jwtToken;
|
|
199
|
+
try {
|
|
200
|
+
jwtToken = yield (0, library_1.getSession)(false, legacy);
|
|
201
|
+
}
|
|
202
|
+
catch (_a) {
|
|
203
|
+
if (!username) {
|
|
204
|
+
throw new Error("No session found. Please provide --username to sign in.");
|
|
205
|
+
}
|
|
206
|
+
const pwd = password || (yield promptPassword());
|
|
207
|
+
jwtToken = yield (0, library_1.signIn)(username, pwd, legacy);
|
|
208
|
+
}
|
|
209
|
+
const apiUrl = legacy ? constants_1.OLD_API_URL : constants_1.NEW_API_URL;
|
|
210
|
+
const api = (0, library_1.configure)(apiUrl);
|
|
211
|
+
const result = yield api.registerDevice(jwtToken, normalizedMac, serial, name, room);
|
|
212
|
+
console.log("Device registered successfully:");
|
|
213
|
+
console.log(JSON.stringify(result, null, 2));
|
|
214
|
+
}));
|
|
215
|
+
// Command: editDevice
|
|
216
|
+
addLegacyOption(addMacOption(addAuthOptions(program
|
|
217
|
+
.command("editDevice")
|
|
218
|
+
.description("Update device name and room"))))
|
|
219
|
+
.requiredOption("-n, --name <deviceName>", "Device name")
|
|
220
|
+
.requiredOption("-r, --room <deviceRoom>", "Room name")
|
|
221
|
+
.action((options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
222
|
+
const { username, password, mac, name, room, legacy = false } = options;
|
|
223
|
+
const normalizedMac = mac.replace(/:/g, "");
|
|
224
|
+
// Initialize file storage for session persistence
|
|
225
|
+
const storage = (0, token_storage_1.createFileStorage)();
|
|
226
|
+
(0, library_1.configureAmplify)(storage);
|
|
227
|
+
let jwtToken;
|
|
228
|
+
try {
|
|
229
|
+
jwtToken = yield (0, library_1.getSession)(false, legacy);
|
|
230
|
+
}
|
|
231
|
+
catch (_a) {
|
|
232
|
+
if (!username) {
|
|
233
|
+
throw new Error("No session found. Please provide --username to sign in.");
|
|
234
|
+
}
|
|
235
|
+
const pwd = password || (yield promptPassword());
|
|
236
|
+
jwtToken = yield (0, library_1.signIn)(username, pwd, legacy);
|
|
237
|
+
}
|
|
238
|
+
const apiUrl = legacy ? constants_1.OLD_API_URL : constants_1.NEW_API_URL;
|
|
239
|
+
const api = (0, library_1.configure)(apiUrl);
|
|
240
|
+
const result = yield api.editDevice(jwtToken, normalizedMac, name, room);
|
|
241
|
+
console.log("Device updated successfully:");
|
|
242
|
+
console.log(JSON.stringify(result, null, 2));
|
|
243
|
+
}));
|
|
244
|
+
return program;
|
|
245
|
+
};
|
|
246
|
+
const main = () => {
|
|
247
|
+
const program = createProgram();
|
|
248
|
+
program.parse(process.argv);
|
|
249
|
+
};
|
|
250
|
+
exports.main = main;
|
|
251
|
+
if (require.main === module) {
|
|
252
|
+
main();
|
|
253
|
+
}
|