genlayer 0.8.0 → 0.9.0
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/.env.example +9 -0
- package/CHANGELOG.md +7 -0
- package/dist/index.js +26288 -13163
- package/docker-compose.yml +7 -0
- package/esbuild.config.dev +1 -1
- package/esbuild.config.prod +1 -1
- package/package.json +3 -1
- package/src/commands/contracts/deploy.ts +69 -0
- package/src/commands/contracts/index.ts +18 -0
- package/src/commands/general/index.ts +1 -2
- package/src/index.ts +2 -0
- package/src/lib/accounts/getPrivateKey.ts +21 -0
- package/tests/actions/deploy.test.ts +137 -0
- package/tests/commands/deploy.test.ts +69 -0
- package/tests/index.test.ts +4 -0
- package/tests/libs/getPrivateKey.test.ts +96 -0
- package/tsconfig.json +1 -1
package/docker-compose.yml
CHANGED
package/esbuild.config.dev
CHANGED
|
@@ -5,7 +5,7 @@ module.exports = {
|
|
|
5
5
|
bundle: true, // Bundle all dependencies
|
|
6
6
|
outfile: "dist/index.js", // Output file
|
|
7
7
|
platform: "node",
|
|
8
|
-
target: "
|
|
8
|
+
target: "es2020",
|
|
9
9
|
define: { 'import.meta.url': '_importMetaUrl' },
|
|
10
10
|
banner: {
|
|
11
11
|
js: "const _importMetaUrl=require('url').pathToFileURL(__filename)",
|
package/esbuild.config.prod
CHANGED
|
@@ -5,7 +5,7 @@ module.exports = {
|
|
|
5
5
|
bundle: true, // Bundle all dependencies
|
|
6
6
|
outfile: "dist/index.js", // Output file
|
|
7
7
|
platform: "node",
|
|
8
|
-
target: "
|
|
8
|
+
target: "es2020",
|
|
9
9
|
define: { 'import.meta.url': '_importMetaUrl' },
|
|
10
10
|
banner: {
|
|
11
11
|
js: "const _importMetaUrl=require('url').pathToFileURL(__filename)",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genlayer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "GenLayer Command Line Tool",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"bin": {
|
|
@@ -60,11 +60,13 @@
|
|
|
60
60
|
"dockerode": "^4.0.2",
|
|
61
61
|
"dotenv": "^16.4.5",
|
|
62
62
|
"ethers": "^6.13.4",
|
|
63
|
+
"genlayer-js": "^0.4.7",
|
|
63
64
|
"inquirer": "^9.2.19",
|
|
64
65
|
"node-fetch": "^2.7.0",
|
|
65
66
|
"open": "^10.1.0",
|
|
66
67
|
"update-check": "^1.5.4",
|
|
67
68
|
"uuid": "^9.0.1",
|
|
69
|
+
"viem": "^2.21.54",
|
|
68
70
|
"vitest": "^2.1.4"
|
|
69
71
|
}
|
|
70
72
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { createClient, createAccount } from "genlayer-js";
|
|
3
|
+
import { simulator } from "genlayer-js/chains";
|
|
4
|
+
import type { GenLayerClient } from "genlayer-js/types";
|
|
5
|
+
import { getPrivateKey } from "../../lib/accounts/getPrivateKey";
|
|
6
|
+
|
|
7
|
+
export interface DeployOptions {
|
|
8
|
+
contract?: string;
|
|
9
|
+
// network: string;
|
|
10
|
+
args?: any[];
|
|
11
|
+
kwargs?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class DeployAction {
|
|
15
|
+
private genlayerClient: GenLayerClient<typeof simulator>;
|
|
16
|
+
|
|
17
|
+
constructor() {
|
|
18
|
+
this.genlayerClient = createClient({
|
|
19
|
+
chain: simulator,
|
|
20
|
+
endpoint: process.env.VITE_JSON_RPC_SERVER_URL,
|
|
21
|
+
account: createAccount(getPrivateKey() as any),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private readContractCode(contractPath: string): string {
|
|
26
|
+
if (!fs.existsSync(contractPath)) {
|
|
27
|
+
throw new Error(`Contract file not found: ${contractPath}`);
|
|
28
|
+
}
|
|
29
|
+
return fs.readFileSync(contractPath, "utf-8");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async deploy(options: DeployOptions): Promise<void> {
|
|
33
|
+
|
|
34
|
+
const argsUsed = options.args && options.args.length > 0;
|
|
35
|
+
const kwargsUsed = options.kwargs && options.kwargs.trim() !== "";
|
|
36
|
+
|
|
37
|
+
if (argsUsed && kwargsUsed) {
|
|
38
|
+
throw new Error("Invalid usage: Please specify either `args` or `kwargs`, but not both.");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!options.contract) {
|
|
42
|
+
console.error("No contract specified for deployment.");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const contractCode = this.readContractCode(options.contract);
|
|
47
|
+
|
|
48
|
+
if (!contractCode) {
|
|
49
|
+
console.error("Contract code is empty.");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const leaderOnly = false;
|
|
54
|
+
let deployParams: any = { code: contractCode, args: options.args, leaderOnly };
|
|
55
|
+
|
|
56
|
+
console.log("Starting contract deployment...");
|
|
57
|
+
console.log("Deployment Parameters:", deployParams);
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const result = await this.genlayerClient.deployContract(deployParams);
|
|
61
|
+
|
|
62
|
+
console.log("Contract deployed successfully.");
|
|
63
|
+
console.log("Transaction Hash:", result);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error("Error deploying contract:", error);
|
|
66
|
+
throw new Error("Contract deployment failed.");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { DeployAction, DeployOptions } from "../contracts/deploy";
|
|
3
|
+
|
|
4
|
+
export function initializeContractsCommands(program: Command) {
|
|
5
|
+
|
|
6
|
+
program
|
|
7
|
+
.command("deploy")
|
|
8
|
+
.description("Deploy intelligent contracts")
|
|
9
|
+
.option("--contract <contractPath>", "Path to the smart contract to deploy")
|
|
10
|
+
// .option("--network <networkName>", "Specify the network (e.g., testnet)", "localnet")
|
|
11
|
+
.option("--args <args...>", "Positional arguments for the contract (space-separated, use quotes for multi-word arguments)", [])
|
|
12
|
+
.action(async (options: DeployOptions) => {
|
|
13
|
+
const deployer = new DeployAction();
|
|
14
|
+
await deployer.deploy(options);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return program;
|
|
18
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
|
|
3
2
|
import simulatorService from "../../lib/services/simulator";
|
|
4
3
|
import { initAction, InitActionOptions } from "./init";
|
|
5
4
|
import { startAction, StartActionOptions } from "./start";
|
|
@@ -11,7 +10,7 @@ export function initializeGeneralCommands(program: Command) {
|
|
|
11
10
|
.option("--numValidators <numValidators>", "Number of validators", "5")
|
|
12
11
|
.option("--headless", "Headless mode", false)
|
|
13
12
|
.option("--reset-db", "Reset Database", false)
|
|
14
|
-
.option("--localnet-version <localnetVersion>", "Select a specific localnet version",
|
|
13
|
+
.option("--localnet-version <localnetVersion>", "Select a specific localnet version", "latest")
|
|
15
14
|
.action((options: InitActionOptions) => initAction(options, simulatorService));
|
|
16
15
|
|
|
17
16
|
program
|
package/src/index.ts
CHANGED
|
@@ -4,12 +4,14 @@ import {version} from "../package.json";
|
|
|
4
4
|
import {CLI_DESCRIPTION} from "../src/lib/config/text";
|
|
5
5
|
import { initializeGeneralCommands } from "../src/commands/general";
|
|
6
6
|
import { initializeKeygenCommands } from "../src/commands/keygen";
|
|
7
|
+
import { initializeContractsCommands } from "../src/commands/contracts";
|
|
7
8
|
import { initializeConfigCommands } from "../src/commands/config";
|
|
8
9
|
|
|
9
10
|
export function initializeCLI() {
|
|
10
11
|
program.version(version).description(CLI_DESCRIPTION);
|
|
11
12
|
initializeGeneralCommands(program);
|
|
12
13
|
initializeKeygenCommands(program);
|
|
14
|
+
initializeContractsCommands(program);
|
|
13
15
|
initializeConfigCommands(program);
|
|
14
16
|
program.parse(process.argv);
|
|
15
17
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { ConfigFileManager } from "../config/ConfigFileManager";
|
|
3
|
+
|
|
4
|
+
export function getPrivateKey(): string {
|
|
5
|
+
const configFileManager: ConfigFileManager = new ConfigFileManager();
|
|
6
|
+
const keypairPath = configFileManager.getConfigByKey("keyPairPath");
|
|
7
|
+
|
|
8
|
+
if (!keypairPath || !fs.existsSync(keypairPath)) {
|
|
9
|
+
console.error("Keypair file not found. Please generate or specify a valid keypair path.");
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const keypairData = JSON.parse(fs.readFileSync(keypairPath, "utf-8"));
|
|
14
|
+
|
|
15
|
+
if (!keypairData.privateKey) {
|
|
16
|
+
console.error("Invalid keypair file. Private key is missing.");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return keypairData.privateKey;
|
|
21
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { describe, test, vi, beforeEach, afterEach, expect } from "vitest";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { createClient, createAccount } from "genlayer-js";
|
|
4
|
+
import { DeployAction, DeployOptions } from "../../src/commands/contracts/deploy";
|
|
5
|
+
import { getPrivateKey } from "../../src/lib/accounts/getPrivateKey";
|
|
6
|
+
|
|
7
|
+
vi.mock("fs");
|
|
8
|
+
vi.mock("genlayer-js");
|
|
9
|
+
vi.mock("../../src/lib/accounts/getPrivateKey");
|
|
10
|
+
|
|
11
|
+
describe("Deploy Action", () => {
|
|
12
|
+
let deployer: DeployAction;
|
|
13
|
+
const mockClient = {
|
|
14
|
+
deployContract: vi.fn(),
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const mockPrivateKey = "mocked_private_key";
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
vi.clearAllMocks();
|
|
21
|
+
vi.mocked(createClient).mockReturnValue(mockClient as any);
|
|
22
|
+
vi.mocked(createAccount).mockReturnValue({ privateKey: mockPrivateKey } as any);
|
|
23
|
+
vi.mocked(getPrivateKey).mockReturnValue(mockPrivateKey);
|
|
24
|
+
deployer = new DeployAction();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
vi.restoreAllMocks();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("reads contract code successfully", () => {
|
|
32
|
+
const contractPath = "/mocked/contract/path";
|
|
33
|
+
const contractContent = "contract code";
|
|
34
|
+
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
35
|
+
vi.mocked(fs.readFileSync).mockReturnValue(contractContent);
|
|
36
|
+
|
|
37
|
+
const result = deployer["readContractCode"](contractPath);
|
|
38
|
+
|
|
39
|
+
expect(fs.existsSync).toHaveBeenCalledWith(contractPath);
|
|
40
|
+
expect(fs.readFileSync).toHaveBeenCalledWith(contractPath, "utf-8");
|
|
41
|
+
expect(result).toBe(contractContent);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("throws error if contract file is missing", () => {
|
|
45
|
+
const contractPath = "/mocked/contract/path";
|
|
46
|
+
vi.mocked(fs.existsSync).mockReturnValue(false);
|
|
47
|
+
|
|
48
|
+
expect(() => deployer["readContractCode"](contractPath)).toThrowError(
|
|
49
|
+
`Contract file not found: ${contractPath}`
|
|
50
|
+
);
|
|
51
|
+
expect(fs.existsSync).toHaveBeenCalledWith(contractPath);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
test("deploys contract with args", async () => {
|
|
56
|
+
const options: DeployOptions = {
|
|
57
|
+
contract: "/mocked/contract/path",
|
|
58
|
+
args: [1, 2, 3],
|
|
59
|
+
};
|
|
60
|
+
const contractContent = "contract code";
|
|
61
|
+
|
|
62
|
+
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
63
|
+
vi.mocked(fs.readFileSync).mockReturnValue(contractContent);
|
|
64
|
+
vi.mocked(mockClient.deployContract).mockResolvedValue("mocked_tx_hash");
|
|
65
|
+
|
|
66
|
+
await deployer.deploy(options);
|
|
67
|
+
|
|
68
|
+
expect(fs.readFileSync).toHaveBeenCalledWith(options.contract, "utf-8");
|
|
69
|
+
expect(mockClient.deployContract).toHaveBeenCalledWith({
|
|
70
|
+
code: contractContent,
|
|
71
|
+
args: [1, 2, 3],
|
|
72
|
+
leaderOnly: false,
|
|
73
|
+
});
|
|
74
|
+
expect(mockClient.deployContract).toHaveResolvedWith("mocked_tx_hash");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("throws error for both args and kwargs", async () => {
|
|
78
|
+
const options: DeployOptions = {
|
|
79
|
+
contract: "/mocked/contract/path",
|
|
80
|
+
args: [1, 2, 3],
|
|
81
|
+
kwargs: "key1=value1,key2=42",
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
await expect(deployer.deploy(options)).rejects.toThrowError(
|
|
85
|
+
"Invalid usage: Please specify either `args` or `kwargs`, but not both."
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
expect(fs.readFileSync).not.toHaveBeenCalled();
|
|
89
|
+
expect(mockClient.deployContract).not.toHaveBeenCalled();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("throws error for missing contract", async () => {
|
|
93
|
+
const options: DeployOptions = {
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
await deployer.deploy(options);
|
|
97
|
+
|
|
98
|
+
expect(fs.readFileSync).not.toHaveBeenCalled();
|
|
99
|
+
expect(mockClient.deployContract).not.toHaveBeenCalled();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("handles deployment errors", async () => {
|
|
103
|
+
const options: DeployOptions = {
|
|
104
|
+
contract: "/mocked/contract/path",
|
|
105
|
+
args: [1, 2, 3],
|
|
106
|
+
};
|
|
107
|
+
const contractContent = "contract code";
|
|
108
|
+
|
|
109
|
+
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
110
|
+
vi.mocked(fs.readFileSync).mockReturnValue(contractContent);
|
|
111
|
+
vi.mocked(mockClient.deployContract).mockRejectedValue(
|
|
112
|
+
new Error("Mocked deployment error")
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
await expect(deployer.deploy(options)).rejects.toThrowError(
|
|
116
|
+
"Contract deployment failed."
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
expect(fs.readFileSync).toHaveBeenCalledWith(options.contract, "utf-8");
|
|
120
|
+
expect(mockClient.deployContract).toHaveBeenCalled();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("throws error if contract code is empty", async () => {
|
|
124
|
+
const options: DeployOptions = {
|
|
125
|
+
contract: "/mocked/contract/path",
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
129
|
+
vi.mocked(fs.readFileSync).mockReturnValue("");
|
|
130
|
+
|
|
131
|
+
await deployer.deploy(options);
|
|
132
|
+
|
|
133
|
+
expect(fs.existsSync).toHaveBeenCalledWith(options.contract);
|
|
134
|
+
expect(fs.readFileSync).toHaveBeenCalledWith(options.contract, "utf-8");
|
|
135
|
+
expect(mockClient.deployContract).not.toHaveBeenCalled();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { vi, describe, beforeEach, afterEach, test, expect } from "vitest";
|
|
3
|
+
import { initializeContractsCommands } from "../../src/commands/contracts";
|
|
4
|
+
import { DeployAction } from "../../src/commands/contracts/deploy";
|
|
5
|
+
|
|
6
|
+
vi.mock("../../src/commands/contracts/deploy");
|
|
7
|
+
|
|
8
|
+
describe("deploy command", () => {
|
|
9
|
+
let program: Command;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
program = new Command();
|
|
13
|
+
initializeContractsCommands(program);
|
|
14
|
+
vi.clearAllMocks();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
vi.restoreAllMocks();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("DeployAction.deploy is called with default options", async () => {
|
|
22
|
+
program.parse(["node", "test", "deploy", "--contract", "./path/to/contract"]);
|
|
23
|
+
expect(DeployAction).toHaveBeenCalledTimes(1);
|
|
24
|
+
expect(DeployAction.prototype.deploy).toHaveBeenCalledWith({
|
|
25
|
+
contract: "./path/to/contract",
|
|
26
|
+
args: [],
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("DeployAction.deploy is called with positional arguments", async () => {
|
|
31
|
+
program.parse([
|
|
32
|
+
"node",
|
|
33
|
+
"test",
|
|
34
|
+
"deploy",
|
|
35
|
+
"--contract",
|
|
36
|
+
"./path/to/contract",
|
|
37
|
+
"--args",
|
|
38
|
+
"1",
|
|
39
|
+
"2",
|
|
40
|
+
"3",
|
|
41
|
+
]);
|
|
42
|
+
expect(DeployAction).toHaveBeenCalledTimes(1);
|
|
43
|
+
expect(DeployAction.prototype.deploy).toHaveBeenCalledWith({
|
|
44
|
+
contract: "./path/to/contract",
|
|
45
|
+
args: ["1", "2", "3"]
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("DeployAction is instantiated when the deploy command is executed", async () => {
|
|
50
|
+
program.parse(["node", "test", "deploy", "--contract", "./path/to/contract"]);
|
|
51
|
+
expect(DeployAction).toHaveBeenCalledTimes(1);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("throws error for unrecognized options", async () => {
|
|
55
|
+
const deployCommand = program.commands.find((cmd) => cmd.name() === "deploy");
|
|
56
|
+
deployCommand?.exitOverride();
|
|
57
|
+
expect(() => program.parse(["node", "test", "deploy", "--unknown"])).toThrowError(
|
|
58
|
+
"error: unknown option '--unknown'"
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("DeployAction.deploy is called without throwing errors for valid options", async () => {
|
|
63
|
+
program.parse(["node", "test", "deploy", "--contract", "./path/to/contract"]);
|
|
64
|
+
vi.mocked(DeployAction.prototype.deploy).mockResolvedValueOnce(undefined);
|
|
65
|
+
expect(() =>
|
|
66
|
+
program.parse(["node", "test", "deploy", "--contract", "./path/to/contract"])
|
|
67
|
+
).not.toThrow();
|
|
68
|
+
});
|
|
69
|
+
});
|
package/tests/index.test.ts
CHANGED
|
@@ -17,6 +17,10 @@ vi.mock("../src/commands/keygen", () => ({
|
|
|
17
17
|
initializeKeygenCommands: vi.fn(),
|
|
18
18
|
}));
|
|
19
19
|
|
|
20
|
+
vi.mock("../src/commands/contracts", () => ({
|
|
21
|
+
initializeContractsCommands: vi.fn(),
|
|
22
|
+
}));
|
|
23
|
+
|
|
20
24
|
vi.mock("../src/commands/config", () => ({
|
|
21
25
|
initializeConfigCommands: vi.fn(),
|
|
22
26
|
}));
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { describe, test, vi, beforeEach, afterEach, expect } from "vitest";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { getPrivateKey } from "../../src/lib/accounts/getPrivateKey";
|
|
4
|
+
import { ConfigFileManager } from "../../src/lib/config/ConfigFileManager";
|
|
5
|
+
|
|
6
|
+
vi.mock("fs");
|
|
7
|
+
vi.mock("../../src/lib/config/ConfigFileManager");
|
|
8
|
+
|
|
9
|
+
describe("getPrivateKey", () => {
|
|
10
|
+
new ConfigFileManager();
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
vi.restoreAllMocks();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("returns the private key if the file exists and is valid", () => {
|
|
21
|
+
const mockPath = "/mocked/path/keypair.json";
|
|
22
|
+
const mockPrivateKey = "0xMockedPrivateKey";
|
|
23
|
+
const mockKeypairData = { privateKey: mockPrivateKey };
|
|
24
|
+
|
|
25
|
+
vi.mocked(ConfigFileManager.prototype.getConfigByKey).mockReturnValue(mockPath);
|
|
26
|
+
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
27
|
+
vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify(mockKeypairData));
|
|
28
|
+
|
|
29
|
+
const privateKey = getPrivateKey();
|
|
30
|
+
|
|
31
|
+
expect(ConfigFileManager.prototype.getConfigByKey).toHaveBeenCalledWith("keyPairPath");
|
|
32
|
+
expect(fs.existsSync).toHaveBeenCalledWith(mockPath);
|
|
33
|
+
expect(fs.readFileSync).toHaveBeenCalledWith(mockPath, "utf-8");
|
|
34
|
+
expect(privateKey).toBe(mockPrivateKey);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("exits if the keypair path is missing in the config", () => {
|
|
38
|
+
const consoleErrorSpy = vi.spyOn(console, "error");
|
|
39
|
+
const processExitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
40
|
+
throw new Error("process.exit");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
vi.mocked(ConfigFileManager.prototype.getConfigByKey).mockReturnValue(null);
|
|
44
|
+
|
|
45
|
+
expect(() => getPrivateKey()).toThrowError("process.exit");
|
|
46
|
+
|
|
47
|
+
expect(ConfigFileManager.prototype.getConfigByKey).toHaveBeenCalledWith("keyPairPath");
|
|
48
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
49
|
+
"Keypair file not found. Please generate or specify a valid keypair path."
|
|
50
|
+
);
|
|
51
|
+
expect(processExitSpy).toHaveBeenCalledWith(1);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("exits if the keypair file does not exist", () => {
|
|
55
|
+
const consoleErrorSpy = vi.spyOn(console, "error");
|
|
56
|
+
const processExitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
57
|
+
throw new Error("process.exit");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const mockPath = "/mocked/path/keypair.json";
|
|
61
|
+
|
|
62
|
+
vi.mocked(ConfigFileManager.prototype.getConfigByKey).mockReturnValue(mockPath);
|
|
63
|
+
vi.mocked(fs.existsSync).mockReturnValue(false);
|
|
64
|
+
|
|
65
|
+
expect(() => getPrivateKey()).toThrowError("process.exit");
|
|
66
|
+
|
|
67
|
+
expect(ConfigFileManager.prototype.getConfigByKey).toHaveBeenCalledWith("keyPairPath");
|
|
68
|
+
expect(fs.existsSync).toHaveBeenCalledWith(mockPath);
|
|
69
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
70
|
+
"Keypair file not found. Please generate or specify a valid keypair path."
|
|
71
|
+
);
|
|
72
|
+
expect(processExitSpy).toHaveBeenCalledWith(1);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("exits if the private key is missing in the keypair file", () => {
|
|
76
|
+
const consoleErrorSpy = vi.spyOn(console, "error");
|
|
77
|
+
const processExitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
78
|
+
throw new Error("process.exit");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const mockPath = "/mocked/path/keypair.json";
|
|
82
|
+
const mockKeypairData = { notPrivateKey: "SomeOtherData" }; // Invalid keypair data
|
|
83
|
+
|
|
84
|
+
vi.mocked(ConfigFileManager.prototype.getConfigByKey).mockReturnValue(mockPath);
|
|
85
|
+
vi.mocked(fs.existsSync).mockReturnValue(true);
|
|
86
|
+
vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify(mockKeypairData));
|
|
87
|
+
|
|
88
|
+
expect(() => getPrivateKey()).toThrowError("process.exit");
|
|
89
|
+
|
|
90
|
+
expect(ConfigFileManager.prototype.getConfigByKey).toHaveBeenCalledWith("keyPairPath");
|
|
91
|
+
expect(fs.existsSync).toHaveBeenCalledWith(mockPath);
|
|
92
|
+
expect(fs.readFileSync).toHaveBeenCalledWith(mockPath, "utf-8");
|
|
93
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith("Invalid keypair file. Private key is missing.");
|
|
94
|
+
expect(processExitSpy).toHaveBeenCalledWith(1);
|
|
95
|
+
});
|
|
96
|
+
});
|
package/tsconfig.json
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
/* Modules */
|
|
28
28
|
"module": "ES2022" /* Specify what module code is generated. */,
|
|
29
29
|
// "rootDir": /* Specify the root folder within your source files. */,
|
|
30
|
-
"moduleResolution": "
|
|
30
|
+
"moduleResolution": "bundler" /* Specify how TypeScript looks up a file from a given module specifier. */,
|
|
31
31
|
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
|
32
32
|
"paths": {
|
|
33
33
|
"@/*": ["./src/*"],
|