diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..8c10e4b
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,5 @@
+dist
+node_modules
+coverage
+**/*.js
+
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
new file mode 100644
index 0000000..d0973c9
--- /dev/null
+++ b/.eslintrc.cjs
@@ -0,0 +1,35 @@
+module.exports = {
+ root: true,
+ parser: '@typescript-eslint/parser',
+ plugins: ['@typescript-eslint'],
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ ],
+ env: {
+ node: true,
+ es2021: true,
+ jest: true,
+ },
+ parserOptions: {
+ ecmaVersion: 2021,
+ sourceType: 'module',
+ },
+ rules: {
+ '@typescript-eslint/no-explicit-any': 'warn',
+ '@typescript-eslint/explicit-function-return-type': 'off',
+ '@typescript-eslint/consistent-type-imports': 'warn',
+ 'no-console': 'off',
+ 'no-var': 'error',
+ preferConst: 'error',
+ },
+ overrides: [
+ {
+ files: ['**/*.js'],
+ rules: {
+ '@typescript-eslint/no-var-requires': 'off',
+ },
+ },
+ ],
+};
+
diff --git a/.gitignore b/.gitignore
index bd888cd..c43ae43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,8 @@
/node_modules
/.pnp
.pnp.js
-
+contracts/
+test.ts
# testing
/coverage
@@ -16,6 +17,7 @@
.env.development.local
.env.test.local
.env.production.local
+.npmrc
npm-debug.log*
yarn-debug.log*
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..ef722db
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 CredShields
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index 2cccd3d..4a6a2a9 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,151 @@
-# solidityscan-npm-package
\ No newline at end of file
+# SolidityScan
+
+Secure your Solidity smart contracts straight from your terminal or JavaScript code! **SolidityScan** is a lightweight CLI and Node.js library that connects to the [CredShields SolidityScan](https://solidityscan.com) API to identify vulnerabilities, gas optimisations, and other issues in your smart-contract projects.
+
+---
+
+## Table of Contents
+
+1. [Features](#features)
+2. [Installation](#installation)
+3. [Getting an API Key](#getting-an-api-key)
+4. [CLI Usage](#cli-usage)
+ * [Scan a local directory](#scan-a-local-directory)
+ * [Run a local file server](#run-a-local-file-server)
+5. [Programmatic Usage](#programmatic-usage)
+6. [Examples](#examples)
+7. [Contributing](#contributing)
+8. [License](#license)
+
+---
+
+## Features
+
+β’ π¦ **Local Directory Scanning** β Zip and upload your local Solidity source code and get instant feedback in the terminal.
+β’ β‘ **Real-time Progress** β Live WebSocket updates with an elegant spinner so you always know the scan status.
+β’ π **Readable Reports** β Vulnerabilities and severities are displayed in coloured, column-aligned tables, followed by a concise scan summary.
+β’ π **Local WebSocket File Server** β Spin up a file server for quick web-UI integrations and demos.
+
+---
+
+## Installation
+
+```bash
+# Install globally to use the `solidityscan` CLI
+yarn global add solidityscan # or npm install -g solidityscan
+
+# Add to a project for programmatic use
+npm install solidityscan --save # or yarn add solidityscan
+```
+
+> **Requirement**: Node.js >= 14
+
+---
+
+## Getting an API Key
+
+1. Sign up or log in at [solidityscan.com](https://solidityscan.com).
+2. Navigate to **API Keys** and generate a new key.
+3. Either export it as an environment variable:
+
+```bash
+export SOLIDITYSCAN_API_KEY="YOUR_API_KEY"
+```
+
+β¦or pass it as the last argument in each CLI command (see below).
+
+---
+
+## CLI Usage
+
+After installing globally you will have a `solidityscan` binary in your PATH.
+Run `solidityscan --help` to view the brief usage guide.
+
+---
+
+### Scan a Local Directory
+
+Analyse a local folder containing `.sol` files. The tool packages the Solidity source, uploads it, waits for the scan to finish and prints the results.
+
+If using with API key in terminal command.
+
+```bash
+solidityscan local /path/to/my/contracts [api-key] [project-name]
+```
+
+If using with API key in environment variable.
+
+```bash
+solidityscan local /path/to/my/contracts [project-name]
+```
+
+If no project name is provided, it will default to "LocalScan".
+
+---
+
+### Run a Local File Server
+
+Start a WebSocket file server to expose your local directory to the SolidityScan web-UI
+A unique **identifier** (\`--id\`) is mandatory β this becomes the sub-domain of the temporary public URL.
+
+```bash
+# Serve current directory on default port 9462 (or 9463-9466 if 9462 is busy)
+solidityscan -l --id
+
+# Serve a specific directory
+solidityscan -l -p /my/contracts --id
+
+# Bind to an explicit port instead of the automatic range
+solidityscan -l -p ./src --id --port 9000
+```
+
+Behaviour notes:
+
+* If **--port** is omitted the CLI tries to bind to 9462 and, if in use, increments the port up to 5 times (9462-9466).
+* The **identifier** should be exactly the string shown on SolidityScan's **Connect to Localhost** page β copy it from the web-UI and use it with `--id`.
+
+---
+
+## Programmatic Usage
+
+You can also integrate SolidityScan directly into your Node.js scripts or CI pipelines:
+
+```js
+const solidityscan = require("solidityscan");
+
+(async () => {
+ const apiToken = process.env.SOLIDITYSCAN_API_KEY;
+
+ // Scan a local directory (same behaviour as CLI `test`)
+ await solidityscan.runTests("./contracts", apiToken);
+})();
+```
+
+Available exported helpers:
+
+* `runTests(directoryPath, apiToken)`
+* `scan()` β executes the CLI with current `process.argv` (internally used by the binary).
+
+---
+
+## Examples
+
+You can find full working examples inside the [`examples/`](https://github.com/Credshields/solidityscan-npm-package/tree/main/examples) directory (coming soon).
+
+---
+
+## Contributing
+
+1. Fork the repo and create your feature branch: `git checkout -b feat/awesome-feature`.
+2. Install dependencies: `npm install`.
+3. Run the tests: `npm test`.
+4. Commit your changes and push: `git push origin feat/awesome-feature`.
+5. Open a pull request β we love to review!
+
+Please adhere to the existing code style and add unit tests for any new logic.
+
+---
+
+## License
+
+This project is licensed under the **ISC** license β see the [LICENSE](LICENSE) file for details.
\ No newline at end of file
diff --git a/bin/solidityscan.js b/bin/solidityscan.js
old mode 100644
new mode 100755
index 78251c3..6aa5fd9
--- a/bin/solidityscan.js
+++ b/bin/solidityscan.js
@@ -1,4 +1,4 @@
-#!/usr/bin/env node
-
-// Simple forwarder to the real CLI implementation
-require("../src/cli").scan();
\ No newline at end of file
+#!/usr/bin/env node
+
+// Forwarder to compiled CLI implementation
+require("../dist/src/cli").scan();
\ No newline at end of file
diff --git a/dist/index.d.ts b/dist/index.d.ts
new file mode 100644
index 0000000..0f5b5f5
--- /dev/null
+++ b/dist/index.d.ts
@@ -0,0 +1,10 @@
+import * as api from "./src/api";
+import * as cli from "./src/cli";
+export declare const projectScan: typeof api.projectScan;
+export declare const generateReport: typeof api.generateReport;
+export declare const quickScanProject: typeof api.quickScanProject;
+export declare const quickScanContract: typeof api.quickScanContract;
+export declare const contractScan: typeof api.contractScan;
+export declare const analyseProject: typeof api.analyzeProject;
+export declare const runTests: typeof api.runTests;
+export declare const scan: typeof cli.scan;
diff --git a/dist/index.js b/dist/index.js
new file mode 100644
index 0000000..1596a74
--- /dev/null
+++ b/dist/index.js
@@ -0,0 +1,47 @@
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || (function () {
+ var ownKeys = function(o) {
+ ownKeys = Object.getOwnPropertyNames || function (o) {
+ var ar = [];
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
+ return ar;
+ };
+ return ownKeys(o);
+ };
+ return function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
+ __setModuleDefault(result, mod);
+ return result;
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.scan = exports.runTests = exports.analyseProject = exports.contractScan = exports.quickScanContract = exports.quickScanProject = exports.generateReport = exports.projectScan = void 0;
+const api = __importStar(require("./src/api"));
+const cli = __importStar(require("./src/cli"));
+exports.projectScan = api.projectScan;
+exports.generateReport = api.generateReport;
+exports.quickScanProject = api.quickScanProject;
+exports.quickScanContract = api.quickScanContract;
+exports.contractScan = api.contractScan;
+exports.analyseProject = api.analyzeProject;
+exports.runTests = api.runTests;
+exports.scan = cli.scan;
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/dist/index.js.map b/dist/index.js.map
new file mode 100644
index 0000000..90f441b
--- /dev/null
+++ b/dist/index.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AACjC,+CAAiC;AAEpB,QAAA,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;AAC9B,QAAA,cAAc,GAAG,GAAG,CAAC,cAAc,CAAC;AACpC,QAAA,gBAAgB,GAAG,GAAG,CAAC,gBAAgB,CAAC;AACxC,QAAA,iBAAiB,GAAG,GAAG,CAAC,iBAAiB,CAAC;AAC1C,QAAA,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC;AAChC,QAAA,cAAc,GAAG,GAAG,CAAC,cAAc,CAAC;AACpC,QAAA,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;AACxB,QAAA,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC"}
\ No newline at end of file
diff --git a/dist/src/api.d.ts b/dist/src/api.d.ts
new file mode 100644
index 0000000..cdcef1b
--- /dev/null
+++ b/dist/src/api.d.ts
@@ -0,0 +1,31 @@
+export interface ProjectScanPayload {
+ provider: string;
+ project_url: string;
+ project_name: string;
+ project_branch: string;
+ recur_scans?: boolean;
+ skip_file_paths?: string[];
+}
+export interface ContractScanPayload {
+ contract_address: string;
+ contract_platform: string;
+ contract_chain: string;
+}
+export interface GenerateReportPayload {
+ project_id: string;
+ scan_id: string;
+ scan_type: string;
+}
+declare function projectScan(projectPayload: ProjectScanPayload, apiToken?: string, spinner?: boolean): Promise;
+declare function quickScanProject(projectPayload: ProjectScanPayload, apiToken?: string, spinner?: boolean): Promise;
+declare function quickScanContract(contractPayload: ContractScanPayload, apiToken?: string, spinner?: boolean): Promise;
+declare function generateReport(generateReportPayload: GenerateReportPayload, apiToken?: string, spinner?: boolean): Promise;
+declare function contractScan(contractPayload: ContractScanPayload, apiToken?: string, spinner?: boolean): Promise;
+declare function analyzeProject(projectDirectory: string, apiToken: string | undefined, projectName: string, isRunningTest?: boolean): Promise;
+type RunTestsReturn = {
+ metadata: unknown;
+ scanDetails: unknown;
+ resultFile: string;
+};
+declare function runTests(projectDirectory: string, apiToken: string | undefined, projectName: string): Promise;
+export { projectScan, generateReport, contractScan, analyzeProject, runTests, quickScanProject, quickScanContract, };
diff --git a/dist/src/api.js b/dist/src/api.js
new file mode 100644
index 0000000..3f26b45
--- /dev/null
+++ b/dist/src/api.js
@@ -0,0 +1,166 @@
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || (function () {
+ var ownKeys = function(o) {
+ ownKeys = Object.getOwnPropertyNames || function (o) {
+ var ar = [];
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
+ return ar;
+ };
+ return ownKeys(o);
+ };
+ return function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
+ __setModuleDefault(result, mod);
+ return result;
+ };
+})();
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.projectScan = projectScan;
+exports.generateReport = generateReport;
+exports.contractScan = contractScan;
+exports.analyzeProject = analyzeProject;
+exports.runTests = runTests;
+exports.quickScanProject = quickScanProject;
+exports.quickScanContract = quickScanContract;
+const utils = __importStar(require("./utils"));
+const fs_1 = __importDefault(require("fs"));
+const cli_spinners_1 = __importDefault(require("cli-spinners"));
+const axios_1 = __importDefault(require("axios"));
+const https_1 = __importDefault(require("https"));
+const spinner = cli_spinners_1.default.dots;
+async function projectScan(projectPayload, apiToken, spinner = true) {
+ const request_payload = {
+ action: "message",
+ payload: {
+ type: "private_project_scan_initiate",
+ body: projectPayload,
+ },
+ };
+ return utils.initializeWebSocket(apiToken, request_payload, spinner);
+}
+async function quickScanProject(projectPayload, apiToken, spinner = true) {
+ const request_payload = {
+ action: "message",
+ payload: {
+ type: "private_quick_scan_initiate",
+ body: projectPayload,
+ },
+ };
+ return utils.initializeWebSocket(apiToken, request_payload, spinner);
+}
+async function quickScanContract(contractPayload, apiToken, spinner = true) {
+ const request_payload = {
+ action: "message",
+ payload: {
+ type: "private_quick_scan_initiate",
+ body: contractPayload,
+ },
+ };
+ return utils.initializeWebSocket(apiToken, request_payload, spinner);
+}
+async function generateReport(generateReportPayload, apiToken, spinner = true) {
+ const request_payload = {
+ action: "message",
+ payload: {
+ type: "generate_report",
+ body: generateReportPayload,
+ },
+ };
+ return utils.initializeWebSocket(apiToken, request_payload, spinner);
+}
+async function contractScan(contractPayload, apiToken, spinner = true) {
+ const request_payload = {
+ action: "message",
+ payload: {
+ type: "private_threat_scan_initiate",
+ body: contractPayload,
+ },
+ };
+ return utils.initializeWebSocket(apiToken, request_payload, spinner);
+}
+async function analyzeProject(projectDirectory, apiToken, projectName, isRunningTest = false) {
+ try {
+ const initializingSpinner = await utils.showSpinnerWithStatus("Initializing Scan", spinner.frames);
+ const projectZipPath = await utils.createProjectZip(projectDirectory);
+ const uploadUrl = await utils.getUploadPresignedUrl(projectZipPath, apiToken);
+ if (uploadUrl) {
+ const fileData = fs_1.default.readFileSync(projectZipPath);
+ const uploadSuccessful = await utils.uploadToS3(fileData, uploadUrl);
+ if (uploadSuccessful) {
+ utils.stopSpinner(initializingSpinner, "Initializing Scan");
+ const scanningSpinner = await utils.showSpinnerWithStatus("Scan in progress", spinner.frames);
+ const request_payload = {
+ type: "private_project_scan_initiate",
+ body: {
+ file_urls: [uploadUrl],
+ project_name: projectName,
+ project_visibility: "public",
+ project_type: "new",
+ },
+ };
+ const result = utils.initializeWebSocket(apiToken, request_payload);
+ return result;
+ }
+ }
+ else {
+ throw new Error(`Error analyzing project`);
+ }
+ }
+ catch (error) {
+ throw new Error(`Error analyzing project from directory: ${error.message}`);
+ }
+}
+async function runTests(projectDirectory, apiToken, projectName) {
+ try {
+ const results = await analyzeProject(projectDirectory, apiToken, projectName, true);
+ const maybeResults = results;
+ if (maybeResults && maybeResults.scan_details && maybeResults.scan_details.link) {
+ const response = await axios_1.default.get(maybeResults.scan_details.link, {
+ httpsAgent: new https_1.default.Agent({ rejectUnauthorized: false })
+ });
+ const scanData = response.data;
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
+ const filename = `scan-result-${maybeResults.scan_id}-${timestamp}.json`;
+ fs_1.default.writeFileSync(filename, JSON.stringify(scanData, null, 2));
+ console.log(`\nScan results saved to: ${filename}`);
+ return {
+ metadata: maybeResults,
+ scanDetails: scanData,
+ resultFile: filename
+ };
+ }
+ else {
+ console.error("Error: Scan results link not found in the response");
+ return results;
+ }
+ }
+ catch (error) {
+ console.error("Error during scan:", error?.message || error);
+ if (error?.response) {
+ console.error("API response error:", error.response.data);
+ }
+ throw error;
+ }
+}
+//# sourceMappingURL=api.js.map
\ No newline at end of file
diff --git a/dist/src/api.js.map b/dist/src/api.js.map
new file mode 100644
index 0000000..e466b55
--- /dev/null
+++ b/dist/src/api.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/dist/src/cli.d.ts b/dist/src/cli.d.ts
new file mode 100644
index 0000000..97e2d51
--- /dev/null
+++ b/dist/src/cli.d.ts
@@ -0,0 +1,2 @@
+declare function scan(): void;
+export { scan, };
diff --git a/dist/src/cli.js b/dist/src/cli.js
new file mode 100644
index 0000000..4a62b19
--- /dev/null
+++ b/dist/src/cli.js
@@ -0,0 +1,210 @@
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || (function () {
+ var ownKeys = function(o) {
+ ownKeys = Object.getOwnPropertyNames || function (o) {
+ var ar = [];
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
+ return ar;
+ };
+ return ownKeys(o);
+ };
+ return function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
+ __setModuleDefault(result, mod);
+ return result;
+ };
+})();
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.scan = scan;
+const axios_1 = __importDefault(require("axios"));
+const api_1 = require("./api");
+const utils = __importStar(require("./utils"));
+function scan() {
+ const [, , ...args] = process.argv;
+ if (args[0] === "scan") {
+ const scanType = args[1];
+ if (scanType === "project") {
+ const provider = args[2];
+ const projectUrl = args[3];
+ const projectBranch = args[4];
+ const projecName = args[5];
+ const recurScan = args[7] ? args[7] === 'true' : false;
+ const apiKey = process.env.SOLIDITYSCAN_API_KEY || args[6];
+ if (!provider || !projectUrl || !projectBranch || !projecName) {
+ console.error("Usage: solisityscan scan ");
+ process.exit(1);
+ }
+ const payload = {
+ provider: provider,
+ project_url: projectUrl,
+ project_name: projecName,
+ project_branch: projectBranch,
+ recur_scans: recurScan || false,
+ skip_file_paths: [],
+ };
+ (0, api_1.projectScan)(payload, apiKey)
+ .then((results) => {
+ console.log("Scan results:", results);
+ })
+ .catch((error) => {
+ console.error("Error during scan:", error);
+ });
+ }
+ else if (scanType === "contract") {
+ const contractAddress = args[2];
+ const contractChain = args[3];
+ const contractPlatform = args[4];
+ const cliProvidedToken = args[5]; // CLI provided token
+ if (!contractAddress || !contractChain || !contractPlatform) {
+ console.error("Usage: solisityscan scan contract [apiToken]");
+ process.exit(1);
+ }
+ try {
+ // Get API token from environment or command line
+ const apiToken = process.env.SOLIDITYSCAN_API_KEY || cliProvidedToken;
+ if (!apiToken) {
+ console.error("No API token provided. Please set SOLIDITYSCAN_API_KEY environment variable or provide token as argument.");
+ process.exit(1);
+ }
+ const payload = {
+ contract_address: contractAddress,
+ contract_platform: contractPlatform,
+ contract_chain: contractChain,
+ };
+ (0, api_1.contractScan)(payload, apiToken)
+ .then((results) => {
+ console.log("Scan results:", JSON.stringify(results, null, 2));
+ })
+ .catch((error) => {
+ console.error("\nError during scan:", error);
+ });
+ }
+ catch (error) {
+ console.error("\nError with API token:", error?.message || error);
+ process.exit(1);
+ }
+ }
+ }
+ else if (args[0] === "local") {
+ const projectPath = args[1];
+ const apiKeyFromArgs = args[2] && !process.env.SOLIDITYSCAN_API_KEY;
+ const apiKey = process.env.SOLIDITYSCAN_API_KEY || args[2];
+ let projectName = apiKeyFromArgs ? args[3] : args[2];
+ if (!projectName) {
+ projectName = "LocalScan";
+ }
+ if (!projectPath) {
+ console.error("Usage: solisityscan run-tests ");
+ process.exit(1);
+ }
+ (0, api_1.analyzeProject)(projectPath, apiKey, projectName)
+ .then((results) => {
+ const r = results;
+ if (r?.scan_details?.link) {
+ axios_1.default.get(r.scan_details.link)
+ .then((response) => {
+ utils.displayScanResults(response.data.scan_report);
+ })
+ .catch((error) => {
+ console.error("Error during scan:", error);
+ });
+ }
+ })
+ .catch((error) => {
+ console.error("Error during scan:", error);
+ });
+ }
+ else if (args.includes("-l")) {
+ const dirFlagIndex = args.indexOf("-p");
+ const serveDirectory = dirFlagIndex !== -1 && args[dirFlagIndex + 1]
+ ? args[dirFlagIndex + 1]
+ : process.cwd();
+ const portFlagIndex = args.indexOf("--port");
+ const userSpecifiedPort = portFlagIndex !== -1 && args[portFlagIndex + 1]
+ ? parseInt(args[portFlagIndex + 1], 10)
+ : null;
+ const idFlagIndex = args.indexOf("--id");
+ const tunnelId = idFlagIndex !== -1 && args[idFlagIndex + 1]
+ ? args[idFlagIndex + 1]
+ : null;
+ if (!tunnelId) {
+ console.error("Missing --id argument");
+ process.exit(1);
+ }
+ let portAttempts = 0;
+ let port = userSpecifiedPort || 9462;
+ let wss;
+ while (portAttempts < 5) {
+ try {
+ wss = utils.startLocalFileServer(serveDirectory, port);
+ break; // success
+ }
+ catch (err) {
+ if (userSpecifiedPort || err?.code !== "EADDRINUSE") {
+ console.error(err?.message || "Failed to start local server");
+ process.exit(1);
+ }
+ port += 1;
+ portAttempts += 1;
+ }
+ }
+ if (!wss) {
+ console.error("Could not bind to any port between 9462 and 9466");
+ process.exit(1);
+ }
+ (async () => {
+ try {
+ const localtunnel = require("localtunnel");
+ const tunnel = await localtunnel({ port, subdomain: tunnelId });
+ const clean = () => {
+ try {
+ tunnel.close();
+ }
+ catch (_) { }
+ try {
+ if (wss)
+ wss.close();
+ }
+ catch (_) { }
+ process.exit(0);
+ };
+ process.on("SIGINT", clean);
+ process.on("SIGTERM", clean);
+ }
+ catch (e) {
+ console.error("Error during tunnel:", e);
+ }
+ })();
+ return;
+ }
+ else {
+ console.error("Unknown command. Usage: solidityscan scan ");
+ process.exit(1);
+ }
+}
+if (require.main === module) {
+ // executed via `node src/cli.js ...` β run the CLI
+ scan();
+}
+//# sourceMappingURL=cli.js.map
\ No newline at end of file
diff --git a/dist/src/cli.js.map b/dist/src/cli.js.map
new file mode 100644
index 0000000..8f02677
--- /dev/null
+++ b/dist/src/cli.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/dist/src/utils.d.ts b/dist/src/utils.d.ts
new file mode 100644
index 0000000..07d0644
--- /dev/null
+++ b/dist/src/utils.d.ts
@@ -0,0 +1,10 @@
+declare const initializeWebSocket: (apiToken: string | undefined, payload: any, spinner?: boolean) => Promise;
+declare const createProjectZip: (projectDirectory: string) => Promise;
+declare const getUploadPresignedUrl: (fileName: string, apiToken?: string) => Promise;
+declare const uploadToS3: (fileData: Buffer | Uint8Array, uploadUrl: string) => Promise;
+declare const displayScanResults: (scan: any) => void;
+declare const displayScanSummary: (scan: any) => void;
+declare function showSpinnerWithStatus(statusMessage: string, spinnerFrames: string[]): Promise>;
+declare function stopSpinner(interval: ReturnType, statusMessage: string): void;
+declare function startLocalFileServer(rootDirectory: string, port?: number): any;
+export { initializeWebSocket, createProjectZip, getUploadPresignedUrl, uploadToS3, displayScanResults, displayScanSummary, showSpinnerWithStatus, stopSpinner, startLocalFileServer, };
diff --git a/dist/src/utils.js b/dist/src/utils.js
new file mode 100644
index 0000000..53df0c0
--- /dev/null
+++ b/dist/src/utils.js
@@ -0,0 +1,531 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.displayScanSummary = exports.displayScanResults = exports.uploadToS3 = exports.getUploadPresignedUrl = exports.createProjectZip = exports.initializeWebSocket = void 0;
+exports.showSpinnerWithStatus = showSpinnerWithStatus;
+exports.stopSpinner = stopSpinner;
+exports.startLocalFileServer = startLocalFileServer;
+const request_1 = __importDefault(require("request"));
+const ws_1 = __importDefault(require("ws"));
+const fs_1 = __importDefault(require("fs"));
+const path_1 = __importDefault(require("path"));
+const archiver_1 = __importDefault(require("archiver"));
+const axios_1 = __importDefault(require("axios"));
+const cli_table3_1 = __importDefault(require("cli-table3"));
+const cli_spinners_1 = __importDefault(require("cli-spinners"));
+const spinner = cli_spinners_1.default.dots;
+const getApi = (apiToken) => {
+ const apiBaseUrl = "https://api.solidityscan.com/";
+ if (apiToken) {
+ const instance = axios_1.default.create({
+ baseURL: apiBaseUrl,
+ headers: {
+ "Content-Type": "application/json",
+ "accept": "application/json, text/plain, */*",
+ "Authorization": `Bearer ${apiToken}`,
+ "cache-control": "no-cache",
+ }
+ });
+ return instance;
+ }
+ else {
+ const instance = axios_1.default.create({
+ baseURL: apiBaseUrl,
+ headers: {
+ "Content-Type": "application/json",
+ "CF-Access-Client-Secret": "",
+ "CF-Access-Client-Id": "",
+ }
+ });
+ return instance;
+ }
+};
+const initializeWebSocket = (apiToken, payload, spinner = true) => {
+ const wsUrl = 'wss://api-ws.solidityscan.com/';
+ const ws = new ws_1.default(wsUrl, {
+ rejectUnauthorized: false
+ });
+ const emitMessage = (messagePayload) => {
+ ws.send(JSON.stringify({
+ action: "message",
+ payload: messagePayload,
+ }));
+ };
+ return new Promise((resolve, reject) => {
+ const connectionTimeout = setTimeout(() => {
+ ws.close();
+ reject(new Error("WebSocket connection timed out waiting for scan results"));
+ }, 60000); // 60 second timeout
+ ws.on("open", () => {
+ if (apiToken) {
+ emitMessage({
+ type: "auth_token_register",
+ body: {
+ auth_token: apiToken,
+ },
+ });
+ }
+ else {
+ console.log("No authentication token provided, sending payload directly");
+ emitMessage(payload);
+ }
+ });
+ ws.on("message", (data) => {
+ try {
+ const receivedMessage = JSON.parse(data.toString());
+ clearTimeout(connectionTimeout);
+ if (receivedMessage.type === "auth_token_register") {
+ if (payload.payload) {
+ emitMessage(payload.payload);
+ }
+ else {
+ emitMessage(payload);
+ }
+ }
+ else if (receivedMessage.type === "scan_status") {
+ if (receivedMessage.payload?.scan_status === "scan_done") {
+ resolve(receivedMessage.payload);
+ ws.close();
+ }
+ }
+ else if (receivedMessage.type === "quick_scan_status") {
+ if (receivedMessage.payload?.scan_status === "scan_done") {
+ resolve(receivedMessage.payload);
+ ws.close();
+ }
+ else {
+ console.log(`\n[WebSocket] Waiting for scan to complete. Current status: ${receivedMessage.payload?.scan_status || receivedMessage.payload?.quick_scan_status || 'processing'}`);
+ }
+ }
+ else if (receivedMessage.type === "report_generation_status") {
+ if (receivedMessage.payload?.report_status === "report_generated") {
+ resolve(receivedMessage.payload);
+ ws.close();
+ }
+ else {
+ console.log(`\n[WebSocket] Report generation payload: ${receivedMessage.payload}`);
+ }
+ }
+ else if (receivedMessage.type === "quick_scan_result") {
+ if (receivedMessage.payload?.scan_details?.link) {
+ request_1.default.get(receivedMessage.payload.scan_details.link, (error, response, body) => {
+ if (error) {
+ resolve(error);
+ }
+ else if (response.statusCode !== 200) {
+ resolve(error);
+ }
+ else {
+ try {
+ const scan_result = JSON.parse(body);
+ resolve(scan_result.scan_report || scan_result);
+ }
+ catch (e) {
+ resolve(body);
+ }
+ }
+ ws.close();
+ });
+ }
+ }
+ else if (receivedMessage.type === "error") {
+ console.log("\n Error received from server:", receivedMessage.payload?.payload?.error_message || receivedMessage.payload?.error_message || "Unknown error");
+ ws.close();
+ reject(receivedMessage.payload?.payload?.error_message || receivedMessage.payload?.error_message || "Unknown error from server");
+ }
+ else {
+ if (spinner) {
+ process.stdout.write(".");
+ }
+ }
+ }
+ catch (error) {
+ console.error("\nError processing message:", error);
+ console.error("\nRaw message data:", data.toString());
+ }
+ });
+ ws.on("error", (error) => {
+ console.log(error);
+ reject(error);
+ });
+ ws.on("close", () => { });
+ });
+};
+exports.initializeWebSocket = initializeWebSocket;
+const createProjectZip = async (projectDirectory) => {
+ try {
+ const zipFileName = "project.zip";
+ const output = fs_1.default.createWriteStream(zipFileName);
+ const archive = (0, archiver_1.default)("zip", { zlib: { level: 9 } });
+ archive.pipe(output);
+ const gatherSolFiles = (directory) => {
+ const files = fs_1.default.readdirSync(directory);
+ files.forEach((file) => {
+ const filePath = path_1.default.join(directory, file);
+ if (fs_1.default.statSync(filePath).isDirectory() && file !== "node_modules") {
+ gatherSolFiles(filePath);
+ }
+ else if (path_1.default.extname(file) === ".sol") {
+ const relativePath = path_1.default.relative(projectDirectory, filePath);
+ const fileContent = fs_1.default.readFileSync(filePath);
+ archive.append(fileContent, { name: relativePath });
+ }
+ });
+ };
+ gatherSolFiles(projectDirectory);
+ await archive.finalize();
+ return zipFileName;
+ }
+ catch (error) {
+ throw new Error(`Error creating project ZIP: ${error.message}`);
+ }
+};
+exports.createProjectZip = createProjectZip;
+const getUploadPresignedUrl = async (fileName, apiToken) => {
+ try {
+ const apiUrl = `private/api-get-presigned-url/?file_name=${fileName}`;
+ const API = getApi(apiToken);
+ const response = await API.get(apiUrl);
+ if (response.status === 200 && response.data && response.data.result) {
+ return response.data.result.url;
+ }
+ else {
+ return null;
+ }
+ }
+ catch (error) {
+ throw new Error(`Failed to get presigned URL: ${error.message}`);
+ }
+};
+exports.getUploadPresignedUrl = getUploadPresignedUrl;
+const uploadToS3 = async (fileData, uploadUrl) => {
+ try {
+ const response = await axios_1.default.put(uploadUrl, fileData, {
+ headers: {
+ "Content-Type": "application/octet-stream",
+ }
+ });
+ if (response.status === 200 || response.status === 204) {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ catch (error) {
+ return false;
+ }
+};
+exports.uploadToS3 = uploadToS3;
+function capitalizeFirstLetter(str) {
+ return str.charAt(0).toUpperCase() + str.slice(1);
+}
+function formatHtmlForTerminal(htmlContent) {
+ if (!htmlContent)
+ return '';
+ let text = htmlContent.replace(/
/gi, '\n');
+ text = text.replace(/(.*?)<\/code>/gi, '`$1`');
+ text = text.replace(/<\/?[^>]+(>|$)/g, '');
+ text = text.replace(/\s+/g, ' ').trim();
+ return text;
+}
+const displayScanResults = (scan) => {
+ const table = new cli_table3_1.default({
+ head: ["#", "NAME", "SEVERITY", "CONFIDENCE", "DESCRIPTION", "REMEDIATION"],
+ chars: {
+ 'top': 'β', 'top-mid': 'β¬', 'top-left': 'β', 'top-right': 'β',
+ 'bottom': 'β', 'bottom-mid': 'β΄', 'bottom-left': 'β', 'bottom-right': 'β',
+ 'left': 'β', 'left-mid': 'β', 'mid': 'β', 'mid-mid': 'βΌ',
+ 'right': 'β', 'right-mid': 'β€', 'middle': 'β'
+ },
+ style: {
+ head: ['bold']
+ },
+ // Configure optimal column widths
+ colWidths: [5, 20, 12, 12, 35, 35],
+ wordWrap: true
+ });
+ let issueCount = 0;
+ scan.multi_file_scan_details.forEach((detail) => {
+ const { template_details } = detail;
+ if (detail.metric_wise_aggregated_findings) {
+ detail.metric_wise_aggregated_findings.forEach((bug) => {
+ issueCount++;
+ const filePath = bug.findings[0].file_path;
+ const location = `${filePath.replace("/project", "")}\nL${bug.findings[0].line_nos_start} - L${bug.findings[0].line_nos_end}`;
+ const description = formatHtmlForTerminal(template_details.issue_description);
+ const fullDescription = `${description}\n\nLocation:\n${location}`;
+ const row = [
+ `${issueCount}.`,
+ template_details.issue_name,
+ capitalizeFirstLetter(template_details.issue_severity),
+ template_details.issue_confidence,
+ fullDescription,
+ formatHtmlForTerminal(template_details.issue_remediation)
+ ];
+ table.push(row);
+ });
+ }
+ });
+ if (issueCount === 0) {
+ console.log('No security issues found!');
+ }
+ else {
+ console.log('SECURITY SCAN RESULTS:');
+ console.log(table.toString());
+ console.log(`Found ${issueCount} security ${issueCount === 1 ? 'issue' : 'issues'}.`);
+ }
+};
+exports.displayScanResults = displayScanResults;
+const displayScanSummary = (scan) => {
+ const table = new cli_table3_1.default();
+ const issues_count = scan.multi_file_scan_summary.issue_severity_distribution.critical +
+ scan.multi_file_scan_summary.issue_severity_distribution.high +
+ scan.multi_file_scan_summary.issue_severity_distribution.medium +
+ scan.multi_file_scan_summary.issue_severity_distribution.low +
+ scan.multi_file_scan_summary.issue_severity_distribution.informational +
+ scan.multi_file_scan_summary.issue_severity_distribution.gas;
+ table.push({
+ Critical: scan.multi_file_scan_summary.issue_severity_distribution.critical,
+ }, { High: scan.multi_file_scan_summary.issue_severity_distribution.high }, {
+ Medium: scan.multi_file_scan_summary.issue_severity_distribution.medium,
+ }, { Low: scan.multi_file_scan_summary.issue_severity_distribution.low }, {
+ Informational: scan.multi_file_scan_summary.issue_severity_distribution.informational,
+ }, { Gas: scan.multi_file_scan_summary.issue_severity_distribution.gas }, { "Security Score": `${scan.multi_file_scan_summary.score_v2} / 100` });
+ console.log(table.toString());
+ console.log(`Scan successful! ${issues_count} issues found. To view detailed results and generate a report navigate to solidityscan.com.`);
+};
+exports.displayScanSummary = displayScanSummary;
+// Function to display a spinner with dynamic status
+async function showSpinnerWithStatus(statusMessage, spinnerFrames) {
+ process.stdout.write(`${statusMessage}... `);
+ let frameIndex = 0;
+ const interval = setInterval(() => {
+ process.stdout.write(spinnerFrames[frameIndex]);
+ process.stdout.write("\b");
+ frameIndex = (frameIndex + 1) % spinnerFrames.length;
+ }, 100);
+ return interval;
+}
+// Function to stop the spinner
+function stopSpinner(interval, statusMessage) {
+ clearInterval(interval);
+ process.stdout.write("\r");
+ console.log(`${statusMessage}... Done`);
+}
+// New helper to serve local directory over WebSocket
+function startLocalFileServer(rootDirectory, port = 8080) {
+ if (!fs_1.default.existsSync(rootDirectory)) {
+ throw new Error(`Directory not found: ${rootDirectory}`);
+ }
+ const absoluteRoot = path_1.default.resolve(rootDirectory);
+ const wss = new ws_1.default.Server({ port, verifyClient: (info, done) => {
+ if (!originIsAllowed(info.origin)) {
+ done(false);
+ console.log(`Connection from origin ${info.origin} is not allowed`);
+ return;
+ }
+ done(true);
+ } });
+ console.log(`SolidityScan local file server started\nServing directory: ${absoluteRoot}`);
+ wss.on("connection", (socket) => {
+ socket.on("message", async (raw) => {
+ let message;
+ try {
+ message = JSON.parse(raw);
+ }
+ catch (err) {
+ socket.send(JSON.stringify({ type: "error", error: "Invalid JSON message" }));
+ return;
+ }
+ const { action, payload } = message;
+ if (action === "listFiles") {
+ // Return hierarchical folder tree with metadata
+ const buildTree = (dir, relPath = "") => {
+ const name = path_1.default.basename(dir);
+ const stat = fs_1.default.statSync(dir);
+ if (stat.isDirectory()) {
+ const dirs = [];
+ const files = [];
+ fs_1.default.readdirSync(dir).forEach((entry) => {
+ if (entry === "node_modules")
+ return;
+ const abs = path_1.default.join(dir, entry);
+ const rootName = path_1.default.basename(absoluteRoot);
+ // Build a raw relative path using native separators
+ let childRelRaw;
+ if (relPath === "") {
+ childRelRaw = path_1.default.join(rootName, entry);
+ }
+ else {
+ childRelRaw = path_1.default.join(relPath, entry);
+ }
+ // Convert to POSIX style with a single "/" separator for JSON responses
+ const childRel = childRelRaw
+ .split(path_1.default.sep)
+ .join("/")
+ .replace(/\/+/g, "/");
+ if (fs_1.default.statSync(abs).isDirectory()) {
+ // Recurse with the raw path to preserve correct joining behaviour
+ dirs.push(buildTree(abs, childRelRaw + path_1.default.sep));
+ }
+ else {
+ const fStat = fs_1.default.statSync(abs);
+ files.push({
+ path: childRel,
+ name: entry,
+ size: fStat.size,
+ mtimeMs: fStat.mtimeMs,
+ checked: entry.endsWith(".sol"),
+ });
+ }
+ });
+ // Determine checked / isChildCheck flags
+ const numSol = files.filter((f) => f.checked).length;
+ const numNonSol = files.length - numSol;
+ let checkedDir = false;
+ let isChildCheck = false;
+ if (numSol === 0) {
+ checkedDir = false;
+ isChildCheck = false;
+ }
+ else if (numNonSol === 0) {
+ checkedDir = true;
+ isChildCheck = true;
+ }
+ else {
+ checkedDir = false;
+ isChildCheck = true;
+ }
+ // Build directory path (raw) and then normalise to POSIX
+ let dirPathRaw;
+ if (dir === absoluteRoot) {
+ dirPathRaw = path_1.default.basename(absoluteRoot) + path_1.default.sep;
+ }
+ else {
+ dirPathRaw = relPath + (relPath && !relPath.endsWith(path_1.default.sep) ? path_1.default.sep : "");
+ }
+ let dirPath = dirPathRaw
+ .split(path_1.default.sep)
+ .join("/")
+ .replace(/\/+/g, "/");
+ // Ensure directory paths end with a single trailing slash
+ if (!dirPath.endsWith("/")) {
+ dirPath += "/";
+ }
+ return {
+ name,
+ path: dirPath,
+ tree: dirs,
+ isChildCheck,
+ checked: checkedDir,
+ blobs: files,
+ size: 0,
+ mtimeMs: stat.mtimeMs,
+ };
+ }
+ // Should not reach here for files as we handle in parent
+ return undefined;
+ };
+ const rootTreeInternal = buildTree(absoluteRoot, "");
+ const responseTree = {
+ name: "",
+ path: "",
+ tree: [rootTreeInternal],
+ isChildCheck: rootTreeInternal.isChildCheck,
+ checked: rootTreeInternal.checked,
+ blobs: [],
+ size: 0,
+ mtimeMs: rootTreeInternal.mtimeMs,
+ };
+ socket.send(JSON.stringify({ type: "folderStructure", tree: responseTree }));
+ }
+ else if (action === "zipAndSendFiles") {
+ const presignedUrl = payload.presigned_url;
+ if (!originIsAllowed(payload.origin)) {
+ socket.send(JSON.stringify({ type: "error", error: "origin not allowed" }));
+ return;
+ }
+ const skip = new Set(payload.skip_file_paths || []);
+ if (!presignedUrl) {
+ socket.send(JSON.stringify({ type: "error", error: "presigned_url missing" }));
+ return;
+ }
+ const archive = (0, archiver_1.default)("zip", { zlib: { level: 9 } });
+ const chunks = [];
+ archive.on("data", (chunk) => chunks.push(chunk));
+ archive.on("warning", (err) => {
+ if (err.code !== "ENOENT") {
+ socket.send(JSON.stringify({ type: "error", error: err.message }));
+ }
+ });
+ archive.on("error", (err) => {
+ socket.send(JSON.stringify({ type: "error", error: err.message }));
+ });
+ archive.on("end", async () => {
+ const buffer = Buffer.concat(chunks);
+ let success = false;
+ try {
+ if (presignedUrl.startsWith("memory://")) {
+ // test stub
+ success = true;
+ }
+ else {
+ success = await uploadToS3(buffer, presignedUrl);
+ }
+ }
+ catch (e) {
+ console.log("error uploading file", e);
+ success = false;
+ }
+ socket.send(JSON.stringify({
+ type: "uploadStatus",
+ success,
+ }));
+ });
+ // recursively walk and add files not skipped
+ const walkAdd = (dir, rel = "") => {
+ fs_1.default.readdirSync(dir).forEach((entry) => {
+ if (entry === "node_modules")
+ return;
+ const abs = path_1.default.join(dir, entry);
+ const relPath = path_1.default.join(rel, entry);
+ const relPathPosix = relPath
+ .split(path_1.default.sep)
+ .join("/")
+ .replace(/\/+/g, "/");
+ const stat = fs_1.default.statSync(abs);
+ if (stat.isDirectory()) {
+ walkAdd(abs, relPath);
+ }
+ else {
+ if (!skip.has(relPathPosix)) {
+ // Use POSIX-style path inside the archive to avoid platform-specific separators
+ archive.file(abs, { name: relPathPosix });
+ }
+ }
+ });
+ };
+ walkAdd(absoluteRoot, "");
+ archive.finalize();
+ }
+ else {
+ socket.send(JSON.stringify({ type: "error", error: "Unknown action" }));
+ }
+ });
+ });
+ return wss;
+}
+function getDomain(url) {
+ const domainMatch = url.match(/^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)/img);
+ return domainMatch ? domainMatch[0] : null;
+}
+function originIsAllowed(origin) {
+ return true;
+ const DOMAIN = getDomain(origin) || "";
+ const allowedOrigins = ["https://solidityscan.com", "https://develop.solidityscan.com", "https://credshields-prod.s3.amazonaws.com", "https://credshields-dev.s3.amazonaws.com/"];
+ return allowedOrigins.includes(DOMAIN);
+}
+//# sourceMappingURL=utils.js.map
\ No newline at end of file
diff --git a/dist/src/utils.js.map b/dist/src/utils.js.map
new file mode 100644
index 0000000..d24af64
--- /dev/null
+++ b/dist/src/utils.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/index.js b/index.js
deleted file mode 100755
index 5679590..0000000
--- a/index.js
+++ /dev/null
@@ -1,10 +0,0 @@
-const api = require("./src/api");
-const cli = require("./src/cli");
-
-module.exports = {
- projectScan: api.projectScan,
- contractScan: api.contractScan,
- analyseProject: api.analyzeProject,
- runTests: api.runTests,
- scan: cli.scan,
-};
diff --git a/index.ts b/index.ts
new file mode 100755
index 0000000..1abe7af
--- /dev/null
+++ b/index.ts
@@ -0,0 +1,11 @@
+import * as api from "./src/api";
+import * as cli from "./src/cli";
+
+export const projectScan = api.projectScan;
+export const generateReport = api.generateReport;
+export const quickScanProject = api.quickScanProject;
+export const quickScanContract = api.quickScanContract;
+export const contractScan = api.contractScan;
+export const analyseProject = api.analyzeProject;
+export const runTests = api.runTests;
+export const scan = cli.scan;
diff --git a/originalReadme.md b/originalReadme.md
new file mode 100644
index 0000000..85b488b
--- /dev/null
+++ b/originalReadme.md
@@ -0,0 +1,190 @@
+# SolidityScan
+
+Secure your Solidity smart contracts straight from your terminal or JavaScript code! **SolidityScan** is a lightweight CLI and Node.js library that connects to the [CredShields SolidityScan](https://solidityscan.com) API to identify vulnerabilities, gas optimisations, and other issues in your smart-contract projects.
+
+---
+
+## Table of Contents
+
+1. [Features](#features)
+2. [Installation](#installation)
+3. [Getting an API Key](#getting-an-api-key)
+4. [CLI Usage](#cli-usage)
+ * [Scan a remote project](#scan-a-remote-project)
+ * [Scan a contract address](#scan-a-contract-address)
+ * [Scan a local directory](#scan-a-local-directory)
+ * [Run a local file server](#run-a-local-file-server)
+5. [Programmatic Usage](#programmatic-usage)
+6. [Examples](#examples)
+7. [Contributing](#contributing)
+8. [License](#license)
+
+---
+
+## Features
+
+β’ π **Project & Contract Scanning** β Analyse entire Git repositories or individual contract addresses for known vulnerabilities.
+β’ π¦ **Local Directory Scanning** β Zip and upload your local Solidity source code and get instant feedback in the terminal.
+β’ β‘ **Real-time Progress** β Live WebSocket updates with an elegant spinner so you always know the scan status.
+β’ π **Readable Reports** β Vulnerabilities and severities are displayed in coloured, column-aligned tables, followed by a concise scan summary.
+β’ π **Local WebSocket File Server** β Spin up a file server for quick web-UI integrations and demos.
+
+---
+
+## Installation
+
+```bash
+# Install globally to use the `solidityscan` CLI
+yarn global add solidityscan # or npm install -g solidityscan
+
+# Add to a project for programmatic use
+npm install solidityscan --save # or yarn add solidityscan
+```
+
+> **Requirement**: Node.js >= 14
+
+---
+
+## Getting an API Key
+
+1. Sign up or log in at [solidityscan.com](https://solidityscan.com).
+2. Navigate to **API Keys** and generate a new key.
+3. Either export it as an environment variable:
+
+```bash
+export SOLIDITYSCAN_API_KEY="YOUR_API_KEY"
+```
+
+β¦or pass it as the last argument in each CLI command (see below).
+
+---
+
+## CLI Usage
+
+After installing globally you will have a `solidityscan` binary in your PATH.
+Run `solidityscan --help` to view the brief usage guide.
+
+### Scan a Remote Project
+
+```bash
+solidityscan scan project [recurScan]
+# Example
+solidityscan scan project github https://github.com/Credshields/solidityscan-npm-package main DemoProject $SOLIDITYSCAN_API_KEY
+```
+
+Arguments:
+
+1. `provider` β Currently supported: `github` (more coming soon).
+2. `repo-url` β HTTPS or SSH URL of the repository.
+3. `branch` β Branch to scan (e.g. `main`).
+4. `project-name` β Friendly name that will appear in the dashboard.
+5. `api-key` *(optional)* β Falls back to `SOLIDITYSCAN_API_KEY` env var.
+6. `recurScan` *(optional)* β `true` to enable recurring scans.
+
+---
+
+### Scan a Contract Address
+
+```bash
+solidityscan scan contract
+# Example
+solidityscan scan contract 0x1234... ethereum evm $SOLIDITYSCAN_API_KEY
+```
+
+* `address` β Deployed contract address.
+* `chain` β Network/chain identifier, e.g. `ethereum`, `polygon`.
+* `platform` β Platform indicator such as `evm`.
+
+---
+
+### Scan a Local Directory
+
+Analyse a local folder containing `.sol` files. The tool packages the Solidity source, uploads it, waits for the scan to finish and prints the results.
+
+```bash
+solidityscan test /path/to/my/contracts [api-key]
+```
+
+---
+
+### Run a Local File Server
+
+Start a WebSocket file server to expose your local directory to the SolidityScan web-UI (handy for visually picking files).
+
+```bash
+# Serve current directory on default port 8080
+solidityscan -l
+
+# Serve a custom directory on port 9090
+solidityscan -l -p /my/contracts --port 9090
+```
+
+---
+
+## Programmatic Usage
+
+You can also integrate SolidityScan directly into your Node.js scripts or CI pipelines:
+
+```js
+const solidityscan = require("solidityscan");
+
+(async () => {
+ const apiToken = process.env.SOLIDITYSCAN_API_KEY;
+
+ // 1. Scan a Git repository
+ const projectPayload = {
+ provider: "github",
+ project_url: "https://github.com/Credshields/awesome-contracts",
+ project_name: "AwesomeContracts",
+ project_branch: "main",
+ recur_scans: false,
+ skip_file_paths: [],
+ };
+ const repoScanResult = await solidityscan.projectScan(projectPayload, apiToken);
+ console.log(repoScanResult);
+
+ // 2. Scan a contract address
+ const contractPayload = {
+ contract_address: "0x1234...",
+ contract_chain: "ethereum",
+ contract_platform: "evm",
+ };
+ const contractScanResult = await solidityscan.contractScan(contractPayload, apiToken);
+ console.log(contractScanResult);
+
+ // 3. Scan a local directory (same behaviour as CLI `test`)
+ await solidityscan.runTests("./contracts", apiToken);
+})();
+```
+
+Available exported helpers:
+
+* `projectScan(payload, apiToken)`
+* `contractScan(payload, apiToken)`
+* `analyseProject(directoryPath, apiToken)`
+* `runTests(directoryPath, apiToken)`
+* `scan()` β executes the CLI with current `process.argv` (internally used by the binary).
+
+---
+
+## Examples
+
+You can find full working examples inside the [`examples/`](https://github.com/Credshields/solidityscan-npm-package/tree/main/examples) directory (coming soon).
+
+---
+
+## Contributing
+
+1. Fork the repo and create your feature branch: `git checkout -b feat/awesome-feature`.
+2. Install dependencies: `npm install`.
+3. Run the tests: `npm test`.
+4. Commit your changes and push: `git push origin feat/awesome-feature`.
+5. Open a pull request β we love to review!
+
+Please adhere to the existing code style and add unit tests for any new logic.
+
+---
+
+## License
+
+This project is licensed under the **ISC** license β see the [LICENSE](LICENSE) file for details.
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index c101082..970b4b1 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,25 +1,37 @@
{
- "name": "solidityscan-npm-test",
- "version": "1.0.0",
+ "name": "solidityscan",
+ "version": "0.1.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "solidityscan-npm-test",
- "version": "1.0.0",
+ "name": "solidityscan",
+ "version": "0.1.6",
"license": "ISC",
"dependencies": {
"archiver": "^6.0.1",
"axios": "^1.6.7",
"cli-spinners": "^2.9.2",
"cli-table3": "^0.6.3",
+ "dotenv": "^16.5.0",
"fs": "^0.0.1-security",
+ "localtunnel": "^2.0.2",
"path": "^0.12.7",
"request": "^2.88.2",
"ws": "^8.16.0"
},
+ "bin": {
+ "solidityscan": "dist/bin/solidityscan.js"
+ },
"devDependencies": {
- "jest": "^29.7.0"
+ "@types/jest": "^29.5.12",
+ "@types/node": "^20.14.11",
+ "@types/ws": "^8.5.10",
+ "@typescript-eslint/eslint-plugin": "^7.17.0",
+ "@typescript-eslint/parser": "^7.17.0",
+ "eslint": "^8.57.0",
+ "jest": "^29.7.0",
+ "typescript": "^5.5.4"
}
},
"node_modules/@ampproject/remapping": {
@@ -496,6 +508,204 @@
"node": ">=0.1.90"
}
},
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
+ "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.12.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+ "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.6.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "8.57.1",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
+ "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
+ "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
+ "deprecated": "Use @eslint/config-array instead",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^2.0.3",
+ "debug": "^4.3.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+ "deprecated": "Use @eslint/object-schema instead",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
"node_modules/@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -890,6 +1100,44 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/@sinclair/typebox": {
"version": "0.27.8",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
@@ -988,13 +1236,25 @@
"@types/istanbul-lib-report": "*"
}
},
+ "node_modules/@types/jest": {
+ "version": "29.5.14",
+ "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz",
+ "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "expect": "^29.0.0",
+ "pretty-format": "^29.0.0"
+ }
+ },
"node_modules/@types/node": {
- "version": "24.0.1",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.1.tgz",
- "integrity": "sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw==",
+ "version": "20.19.10",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.10.tgz",
+ "integrity": "sha512-iAFpG6DokED3roLSP0K+ybeDdIX6Bc0Vd3mLW5uDqThPWtNos3E+EqOM11mPQHKzfWHqEBuLjIlsBQQ8CsISmQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "undici-types": "~7.8.0"
+ "undici-types": "~6.21.0"
}
},
"node_modules/@types/stack-utils": {
@@ -1003,6 +1263,16 @@
"integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
"dev": true
},
+ "node_modules/@types/ws": {
+ "version": "8.18.1",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
+ "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/yargs": {
"version": "17.0.33",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz",
@@ -1018,114 +1288,375 @@
"integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
"dev": true
},
- "node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz",
+ "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
+ "@eslint-community/regexpp": "^4.10.0",
+ "@typescript-eslint/scope-manager": "7.18.0",
+ "@typescript-eslint/type-utils": "7.18.0",
+ "@typescript-eslint/utils": "7.18.0",
+ "@typescript-eslint/visitor-keys": "7.18.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.3.1",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^1.3.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
},
"funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^7.0.0",
+ "eslint": "^8.56.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
}
},
- "node_modules/ansi-escapes": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
- "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+ "node_modules/@typescript-eslint/parser": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz",
+ "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
- "type-fest": "^0.21.3"
+ "@typescript-eslint/scope-manager": "7.18.0",
+ "@typescript-eslint/types": "7.18.0",
+ "@typescript-eslint/typescript-estree": "7.18.0",
+ "@typescript-eslint/visitor-keys": "7.18.0",
+ "debug": "^4.3.4"
},
"engines": {
- "node": ">=8"
+ "node": "^18.18.0 || >=20.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "engines": {
- "node": ">=8"
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.56.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
}
},
- "node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz",
+ "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "color-convert": "^2.0.1"
+ "@typescript-eslint/types": "7.18.0",
+ "@typescript-eslint/visitor-keys": "7.18.0"
},
"engines": {
- "node": ">=8"
+ "node": "^18.18.0 || >=20.0.0"
},
"funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
}
},
- "node_modules/anymatch": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
- "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz",
+ "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
+ "@typescript-eslint/typescript-estree": "7.18.0",
+ "@typescript-eslint/utils": "7.18.0",
+ "debug": "^4.3.4",
+ "ts-api-utils": "^1.3.0"
},
"engines": {
- "node": ">= 8"
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.56.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
}
},
- "node_modules/archiver": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/archiver/-/archiver-6.0.1.tgz",
- "integrity": "sha512-CXGy4poOLBKptiZH//VlWdFuUC1RESbdZjGjILwBuZ73P7WkAUN0htfSfBq/7k6FRFlpu7bg4JOkj1vU9G6jcQ==",
- "dependencies": {
- "archiver-utils": "^4.0.1",
- "async": "^3.2.4",
- "buffer-crc32": "^0.2.1",
- "readable-stream": "^3.6.0",
- "readdir-glob": "^1.1.2",
- "tar-stream": "^3.0.0",
- "zip-stream": "^5.0.1"
- },
+ "node_modules/@typescript-eslint/types": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz",
+ "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==",
+ "dev": true,
+ "license": "MIT",
"engines": {
- "node": ">= 12.0.0"
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
}
},
- "node_modules/archiver-utils": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-4.0.1.tgz",
- "integrity": "sha512-Q4Q99idbvzmgCTEAAhi32BkOyq8iVI5EwdO0PmBDSGIzzjYNdcFn7Q7k3OzbLy4kLUPXfJtG6fO2RjftXbobBg==",
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz",
+ "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
- "glob": "^8.0.0",
- "graceful-fs": "^4.2.0",
- "lazystream": "^1.0.0",
- "lodash": "^4.17.15",
- "normalize-path": "^3.0.0",
- "readable-stream": "^3.6.0"
+ "@typescript-eslint/types": "7.18.0",
+ "@typescript-eslint/visitor-keys": "7.18.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "minimatch": "^9.0.4",
+ "semver": "^7.6.0",
+ "ts-api-utils": "^1.3.0"
},
"engines": {
- "node": ">= 12.0.0"
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
}
},
- "node_modules/argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz",
+ "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "@typescript-eslint/scope-manager": "7.18.0",
+ "@typescript-eslint/types": "7.18.0",
+ "@typescript-eslint/typescript-estree": "7.18.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.56.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz",
+ "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "7.18.0",
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
+ "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/acorn": {
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-escapes": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.21.3"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/archiver": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-6.0.1.tgz",
+ "integrity": "sha512-CXGy4poOLBKptiZH//VlWdFuUC1RESbdZjGjILwBuZ73P7WkAUN0htfSfBq/7k6FRFlpu7bg4JOkj1vU9G6jcQ==",
+ "dependencies": {
+ "archiver-utils": "^4.0.1",
+ "async": "^3.2.4",
+ "buffer-crc32": "^0.2.1",
+ "readable-stream": "^3.6.0",
+ "readdir-glob": "^1.1.2",
+ "tar-stream": "^3.0.0",
+ "zip-stream": "^5.0.1"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/archiver-utils": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-4.0.1.tgz",
+ "integrity": "sha512-Q4Q99idbvzmgCTEAAhi32BkOyq8iVI5EwdO0PmBDSGIzzjYNdcFn7Q7k3OzbLy4kLUPXfJtG6fO2RjftXbobBg==",
+ "dependencies": {
+ "glob": "^8.0.0",
+ "graceful-fs": "^4.2.0",
+ "lazystream": "^1.0.0",
+ "lodash": "^4.17.15",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/asn1": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
@@ -1539,7 +2070,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
@@ -1550,8 +2080,7 @@
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/combined-stream": {
"version": "1.0.8",
@@ -1695,6 +2224,13 @@
}
}
},
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
@@ -1730,6 +2266,44 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "16.5.0",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz",
+ "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
"node_modules/ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@@ -1775,7 +2349,6 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
- "dev": true,
"engines": {
"node": ">=6"
}
@@ -1789,6 +2362,246 @@
"node": ">=8"
}
},
+ "node_modules/eslint": {
+ "version": "8.57.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
+ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
+ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.6.1",
+ "@eslint/eslintrc": "^2.1.4",
+ "@eslint/js": "8.57.1",
+ "@humanwhocodes/config-array": "^0.13.0",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "@ungap/structured-clone": "^1.2.0",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3",
+ "strip-ansi": "^6.0.1",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint/node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/eslint/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/eslint/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/eslint/node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/eslint/node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/espree": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.9.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
"node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@@ -1802,6 +2615,52 @@
"node": ">=4"
}
},
+ "node_modules/esquery": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+ "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/execa": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
@@ -1873,11 +2732,58 @@
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
"integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="
},
+ "node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fastq": {
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
+ "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
"node_modules/fb-watchman": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
@@ -1887,6 +2793,19 @@
"bser": "2.1.1"
}
},
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -1912,6 +2831,28 @@
"node": ">=8"
}
},
+ "node_modules/flat-cache": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
+ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.3",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
+ "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/follow-redirects": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
@@ -1998,7 +2939,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true,
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
@@ -2050,6 +2990,19 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
"node_modules/globals": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
@@ -2059,11 +3012,39 @@
"node": ">=4"
}
},
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
},
+ "node_modules/graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@@ -2126,13 +3107,50 @@
"npm": ">=1.3.7"
}
},
- "node_modules/human-signals": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
- "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+ "node_modules/human-signals": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10.17.0"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/import-fresh/node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=10.17.0"
+ "node": ">=4"
}
},
"node_modules/import-local": {
@@ -2198,6 +3216,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@@ -2215,6 +3243,19 @@
"node": ">=6"
}
},
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -2224,6 +3265,16 @@
"node": ">=0.12.0"
}
},
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@@ -3024,6 +4075,13 @@
"node": ">=6"
}
},
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
@@ -3040,6 +4098,13 @@
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
@@ -3071,6 +4136,16 @@
"node": ">=0.6.0"
}
},
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
"node_modules/kleur": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
@@ -3127,12 +4202,114 @@
"node": ">=6"
}
},
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"dev": true
},
+ "node_modules/localtunnel": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-2.0.2.tgz",
+ "integrity": "sha512-n418Cn5ynvJd7m/N1d9WVJISLJF/ellZnfsLnx8WBWGzxv/ntNcFkJ1o6se5quUhCplfLGBNL5tYHiq5WF3Nug==",
+ "license": "MIT",
+ "dependencies": {
+ "axios": "0.21.4",
+ "debug": "4.3.2",
+ "openurl": "1.1.1",
+ "yargs": "17.1.1"
+ },
+ "bin": {
+ "lt": "bin/lt.js"
+ },
+ "engines": {
+ "node": ">=8.3.0"
+ }
+ },
+ "node_modules/localtunnel/node_modules/axios": {
+ "version": "0.21.4",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
+ "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
+ "license": "MIT",
+ "dependencies": {
+ "follow-redirects": "^1.14.0"
+ }
+ },
+ "node_modules/localtunnel/node_modules/cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "node_modules/localtunnel/node_modules/debug": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
+ "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/localtunnel/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "license": "MIT"
+ },
+ "node_modules/localtunnel/node_modules/yargs": {
+ "version": "17.1.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.1.1.tgz",
+ "integrity": "sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ==",
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/localtunnel/node_modules/yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -3150,6 +4327,13 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -3201,6 +4385,16 @@
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true
},
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
@@ -3328,6 +4522,30 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/openurl": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz",
+ "integrity": "sha512-d/gTkTb1i1GKz5k3XE3XFV/PxQ1k45zDqGP2OA7YhgsaLoqm6qRvARAZOFer1fcXritWlGBRCu/UgeS4HAnXAA==",
+ "license": "MIT"
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -3379,6 +4597,19 @@
"node": ">=6"
}
},
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/parse-json": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
@@ -3439,6 +4670,16 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@@ -3483,6 +4724,16 @@
"node": ">=8"
}
},
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
"node_modules/pretty-format": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
@@ -3577,6 +4828,27 @@
"node": ">=0.6"
}
},
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/queue-tick": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
@@ -3644,7 +4916,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -3699,6 +4970,104 @@
"node": ">=10"
}
},
+ "node_modules/reusify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rimraf/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/rimraf/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rimraf/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -4010,6 +5379,13 @@
"node": "*"
}
},
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/tmpl": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@@ -4040,6 +5416,19 @@
"node": ">=0.8"
}
},
+ "node_modules/ts-api-utils": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz",
+ "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.2.0"
+ }
+ },
"node_modules/tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@@ -4056,6 +5445,19 @@
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
},
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
"node_modules/type-detect": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
@@ -4077,11 +5479,26 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/typescript": {
+ "version": "5.9.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
+ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
"node_modules/undici-types": {
- "version": "7.8.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
- "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
- "dev": true
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/update-browserslist-db": {
"version": "1.1.3",
@@ -4199,11 +5616,20 @@
"node": ">= 8"
}
},
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
@@ -4258,7 +5684,6 @@
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true,
"engines": {
"node": ">=10"
}
diff --git a/package.json b/package.json
index 73eac82..b08839b 100755
--- a/package.json
+++ b/package.json
@@ -1,9 +1,14 @@
{
- "name": "solidityscan-npm-test",
- "version": "1.0.0",
- "description": "Test SolidityScan",
- "main": "index.js",
+ "name": "solidityscan",
+ "version": "0.2.3",
+ "description": "SolidityScan is a tool for scanning Solidity smart contracts for vulnerabilities.",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
"scripts": {
+ "build": "tsc -p tsconfig.json",
+ "typecheck": "tsc --noEmit -p tsconfig.json",
+ "lint": "eslint . --ext .ts",
+ "prepublishOnly": "npm run build",
"test": "jest"
},
"keywords": [
@@ -22,15 +27,32 @@
"axios": "^1.6.7",
"cli-spinners": "^2.9.2",
"cli-table3": "^0.6.3",
+ "dotenv": "^16.5.0",
"fs": "^0.0.1-security",
+ "localtunnel": "^2.0.2",
"path": "^0.12.7",
"request": "^2.88.2",
"ws": "^8.16.0"
},
"devDependencies": {
- "jest": "^29.7.0"
+ "@types/jest": "^29.5.12",
+ "@types/node": "^20.14.11",
+ "@types/ws": "^8.5.10",
+ "@typescript-eslint/eslint-plugin": "^7.17.0",
+ "@typescript-eslint/parser": "^7.17.0",
+ "eslint": "^8.57.0",
+ "jest": "^29.7.0",
+ "typescript": "^5.5.4"
},
"bin": {
"solidityscan": "bin/solidityscan.js"
- }
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/Credshields/solidityscan-npm-package.git"
+ },
+ "bugs": {
+ "url": "https://github.com/Credshields/solidityscan-npm-package/issues"
+ },
+ "homepage": "https://github.com/Credshields/solidityscan-npm-package#readme"
}
diff --git a/src/api.js b/src/api.js
deleted file mode 100755
index 4632338..0000000
--- a/src/api.js
+++ /dev/null
@@ -1,90 +0,0 @@
-const utils = require("./utils");
-const fs = require("fs");
-const cliSpinners = require("cli-spinners");
-const spinner = cliSpinners.dots;
-
-async function projectScan(projectPayload, apiToken) {
- const request_payload = {
- action: "message",
- payload: {
- type: "private_project_scan_initiate",
- body: projectPayload,
- },
- };
- return utils.initializeWebSocket(apiToken, request_payload);
-}
-
-async function contractScan(contractPayload, apiToken) {
- const request_payload = {
- action: "message",
- payload: {
- type: "private_block_scan_initiate",
- body: contractPayload,
- },
- };
- return utils.initializeWebSocket(apiToken, request_payload);
-}
-
-async function analyzeProject(projectDirectory, apiToken) {
- try {
- const initializingSpinner = await utils.showSpinnerWithStatus(
- "Initializing Scan",
- spinner.frames
- );
- const projectZipPath = await utils.createProjectZip(projectDirectory);
- const uploadUrl = await utils.getUploadPresignedUrl(
- projectZipPath,
- apiToken
- );
- if (uploadUrl) {
- const fileData = fs.readFileSync(projectZipPath);
- const uploadSuccessful = await utils.uploadToS3(fileData, uploadUrl);
- if (uploadSuccessful) {
- utils.stopSpinner(initializingSpinner, "Initializing Scan");
- const scanningSpinner = await utils.showSpinnerWithStatus(
- "Scan in progress",
- spinner.frames
- );
- const request_payload = {
- type: "private_project_scan_initiate",
- body: {
- file_urls: [uploadUrl],
- project_name: "fileName",
- project_visibility: "public",
- project_type: "new",
- },
- };
- const result = utils.initializeWebSocket(
- apiToken,
- request_payload,
- scanningSpinner
- );
- return result;
- }
- } else {
- throw new Error(`Error analyzing project`);
- }
- } catch (error) {
- throw new Error(`Error analyzing project from directory: ${error.message}`);
- }
-}
-
-async function runTests(projectDirectory, apiToken) {
- analyzeProject(projectDirectory, apiToken)
- .then((results) => {
- utils.displayScanResults(results);
- console.log("");
- console.log("Scan Summary");
- utils.displayScanSummary(results);
- })
- .catch((error) => {
- console.error("Error during scan:", error);
- });
-}
-
-module.exports = {
- projectScan,
- contractScan,
- analyzeProject,
- runTests,
-};
diff --git a/src/api.ts b/src/api.ts
new file mode 100755
index 0000000..192debe
--- /dev/null
+++ b/src/api.ts
@@ -0,0 +1,190 @@
+import * as utils from "./utils";
+import fs from "fs";
+import cliSpinners from "cli-spinners";
+import axios from "axios";
+import https from "https";
+const spinner = cliSpinners.dots;
+
+export interface ProjectScanPayload {
+ provider: string;
+ project_url: string;
+ project_name: string;
+ project_branch: string;
+ recur_scans?: boolean;
+ skip_file_paths?: string[];
+}
+
+export interface ContractScanPayload {
+ contract_address: string;
+ contract_platform: string;
+ contract_chain: string;
+}
+
+export interface GenerateReportPayload {
+ project_id: string;
+ scan_id: string;
+ scan_type: string;
+}
+
+async function projectScan(projectPayload: ProjectScanPayload, apiToken?: string, spinner: boolean = true) {
+ const request_payload = {
+ action: "message",
+ payload: {
+ type: "private_project_scan_initiate",
+ body: projectPayload,
+ },
+ };
+ return utils.initializeWebSocket(apiToken, request_payload, spinner);
+}
+
+async function quickScanProject(projectPayload: ProjectScanPayload, apiToken?: string, spinner: boolean = true) {
+ const request_payload = {
+ action: "message",
+ payload: {
+ type: "private_quick_scan_initiate",
+ body: projectPayload,
+ },
+ };
+ return utils.initializeWebSocket(apiToken, request_payload, spinner);
+}
+
+async function quickScanContract(contractPayload: ContractScanPayload, apiToken?: string, spinner: boolean = true) {
+ const request_payload = {
+ action: "message",
+ payload: {
+ type: "private_quick_scan_initiate",
+ body: contractPayload,
+ },
+ };
+ return utils.initializeWebSocket(apiToken, request_payload, spinner);
+}
+
+
+async function generateReport(
+ generateReportPayload: GenerateReportPayload,
+ apiToken?: string,
+ spinner: boolean = true
+) {
+ const request_payload = {
+ action: "message",
+ payload: {
+ type: "generate_report",
+ body: generateReportPayload,
+ },
+ };
+ return utils.initializeWebSocket(apiToken, request_payload, spinner);
+}
+
+async function contractScan(contractPayload: ContractScanPayload, apiToken?: string, spinner: boolean = true) {
+ const request_payload = {
+ action: "message",
+ payload: {
+ type: "private_threat_scan_initiate",
+ body: contractPayload,
+ },
+ };
+ return utils.initializeWebSocket(apiToken, request_payload, spinner);
+}
+
+async function analyzeProject(
+ projectDirectory: string,
+ apiToken: string | undefined,
+ projectName: string,
+ isRunningTest = false
+) {
+ try {
+ const initializingSpinner = await utils.showSpinnerWithStatus(
+ "Initializing Scan",
+ spinner.frames
+ );
+ const projectZipPath = await utils.createProjectZip(projectDirectory);
+ const uploadUrl = await utils.getUploadPresignedUrl(
+ projectZipPath,
+ apiToken
+ );
+ if (uploadUrl) {
+ const fileData = fs.readFileSync(projectZipPath);
+ const uploadSuccessful = await utils.uploadToS3(fileData, uploadUrl);
+ if (uploadSuccessful) {
+ utils.stopSpinner(initializingSpinner, "Initializing Scan");
+ const scanningSpinner = await utils.showSpinnerWithStatus(
+ "Scan in progress",
+ spinner.frames
+ );
+ const request_payload = {
+ type: "private_project_scan_initiate",
+ body: {
+ file_urls: [uploadUrl],
+ project_name: projectName,
+ project_visibility: "public",
+ project_type: "new",
+ },
+ };
+ const result = utils.initializeWebSocket(
+ apiToken,
+ request_payload
+ );
+ return result;
+ }
+ } else {
+ throw new Error(`Error analyzing project`);
+ }
+ } catch (error: any) {
+ throw new Error(`Error analyzing project from directory: ${error.message}`);
+ }
+}
+
+type RunTestsReturn = {
+ metadata: unknown;
+ scanDetails: unknown;
+ resultFile: string;
+};
+
+async function runTests(
+ projectDirectory: string,
+ apiToken: string | undefined,
+ projectName: string
+): Promise {
+ try {
+ const results = await analyzeProject(projectDirectory, apiToken, projectName, true);
+
+ const maybeResults: any = results as any;
+ if (maybeResults && maybeResults.scan_details && maybeResults.scan_details.link) {
+ const response = await axios.get(maybeResults.scan_details.link, {
+ httpsAgent: new https.Agent({ rejectUnauthorized: false })
+ });
+
+ const scanData = response.data;
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
+ const filename = `scan-result-${maybeResults.scan_id}-${timestamp}.json`;
+
+ fs.writeFileSync(filename, JSON.stringify(scanData, null, 2));
+ console.log(`\nScan results saved to: ${filename}`);
+
+ return {
+ metadata: maybeResults,
+ scanDetails: scanData,
+ resultFile: filename
+ };
+ } else {
+ console.error("Error: Scan results link not found in the response");
+ return results;
+ }
+ } catch (error: any) {
+ console.error("Error during scan:", error?.message || error);
+ if (error?.response) {
+ console.error("API response error:", error.response.data);
+ }
+ throw error;
+ }
+}
+
+export {
+ projectScan,
+ generateReport,
+ contractScan,
+ analyzeProject,
+ runTests,
+ quickScanProject,
+ quickScanContract,
+};
diff --git a/src/cli.js b/src/cli.js
deleted file mode 100755
index 62a83ef..0000000
--- a/src/cli.js
+++ /dev/null
@@ -1,119 +0,0 @@
-const { projectScan, contractScan, analyzeProject } = require("./api");
-const utils = require("./utils");
-
-function scan() {
- const [, , ...args] = process.argv;
-
- if (args[0] === "scan") {
- const scanType = args[1];
- if (scanType === "project") {
- const provider = args[2];
- const projectUrl = args[3];
- const projectBranch = args[4];
- const projecName = args[5];
- const recurScan = args[7];
- const apiKey = process.env.SOLIDITYSCAN_API_KEY || args[6];
-
- if (!provider || !projectUrl || !projectBranch || !projecName) {
- console.error("Usage: solisityscan scan ");
- process.exit(1);
- }
-
- const payload = {
- provider: provider,
- project_url: projectUrl,
- project_name: projecName,
- project_branch: projectBranch,
- recur_scans: recurScan || false,
- skip_file_paths: [],
- };
-
- projectScan(payload, apiKey)
- .then((results) => {
- console.log("Scan results:", results);
- })
- .catch((error) => {
- console.error("Error during scan:", error);
- });
- } else if (scanType === "contract") {
- const contractAddress = args[2];
- const contractChain = args[3];
- const contractPlatform = args[4];
- const apiKey = process.env.SOLIDITYSCAN_API_KEY || args[5];
-
- if (!contractAddress || !contractChain || !contractPlatform) {
- console.error("Usage: solisityscan scan ");
- process.exit(1);
- }
-
- const payload = {
- contract_address: contractAddress,
- contract_platform: contractPlatform,
- contract_chain: contractPlatform,
- };
-
- contractScan(payload, apiKey)
- .then((results) => {
- console.log("Scan results:", results);
- })
- .catch((error) => {
- console.error("Error during scan:", error);
- });
- }
- } else if (args[0] === "test") {
- const projectPath = args[1];
- const apiKey = process.env.SOLIDITYSCAN_API_KEY || args[2];
-
- if (!projectPath) {
- console.error("Usage: solisityscan run-tests ");
- process.exit(1);
- }
-
- analyzeProject(projectPath, apiKey)
- .then((results) => {
- utils.displayScanResults(results);
- console.log("");
- console.log("Scan Summary");
- utils.displayScanSummary(results);
- })
- .catch((error) => {
- console.error("Error during scan:", error);
- });
- } else if (args.includes("-l")) {
- // Start local WebSocket file server to expose file system
- const dirFlagIndex = args.indexOf("-p");
- const serveDirectory =
- dirFlagIndex !== -1 && args[dirFlagIndex + 1]
- ? args[dirFlagIndex + 1]
- : process.cwd();
-
- const portFlagIndex = args.indexOf("--port");
- const port =
- portFlagIndex !== -1 && args[portFlagIndex + 1]
- ? parseInt(args[portFlagIndex + 1], 10)
- : 8080;
-
- try {
- utils.startLocalFileServer(serveDirectory, port);
- } catch (error) {
- console.error(error.message);
- process.exit(1);
- }
- // keep the process alive when in local server mode
- return;
- } else {
- console.error(
- "Unknown command. Usage: solidityscan scan "
- );
- process.exit(1);
- }
-}
-
-if (require.main === module) {
- // executed via `node src/cli.js ...` β run the CLI
- scan();
-}
-
-module.exports = {
- scan,
-};
diff --git a/src/cli.ts b/src/cli.ts
new file mode 100755
index 0000000..a09ed39
--- /dev/null
+++ b/src/cli.ts
@@ -0,0 +1,193 @@
+import { default as axios } from "axios";
+import { projectScan, contractScan, analyzeProject, ProjectScanPayload, ContractScanPayload } from "./api";
+import * as utils from "./utils";
+
+function scan(): void {
+ const [, , ...args] = process.argv;
+
+ if (args[0] === "scan") {
+ const scanType = args[1];
+ if (scanType === "project") {
+ const provider = args[2];
+ const projectUrl = args[3];
+ const projectBranch = args[4];
+ const projecName = args[5];
+ const recurScan = args[7] ? args[7] === 'true' : false;
+ const apiKey = process.env.SOLIDITYSCAN_API_KEY || args[6];
+
+ if (!provider || !projectUrl || !projectBranch || !projecName) {
+ console.error("Usage: solisityscan scan ");
+ process.exit(1);
+ }
+
+ const payload: ProjectScanPayload = {
+ provider: provider,
+ project_url: projectUrl,
+ project_name: projecName,
+ project_branch: projectBranch,
+ recur_scans: recurScan || false,
+ skip_file_paths: [],
+ };
+
+ projectScan(payload, apiKey)
+ .then((results) => {
+ console.log("Scan results:", results);
+ })
+ .catch((error) => {
+ console.error("Error during scan:", error);
+ });
+ } else if (scanType === "contract") {
+ const contractAddress: string | undefined = args[2];
+ const contractChain: string | undefined = args[3];
+ const contractPlatform: string | undefined = args[4];
+ const cliProvidedToken = args[5]; // CLI provided token
+
+ if (!contractAddress || !contractChain || !contractPlatform) {
+ console.error("Usage: solisityscan scan contract [apiToken]");
+ process.exit(1);
+ }
+
+ try {
+ // Get API token from environment or command line
+ const apiToken = process.env.SOLIDITYSCAN_API_KEY || cliProvidedToken;
+ if (!apiToken) {
+ console.error("No API token provided. Please set SOLIDITYSCAN_API_KEY environment variable or provide token as argument.");
+ process.exit(1);
+ }
+
+ const payload: ContractScanPayload = {
+ contract_address: contractAddress,
+ contract_platform: contractPlatform,
+ contract_chain: contractChain,
+ };
+
+ contractScan(payload, apiToken)
+ .then((results) => {
+ console.log("Scan results:",JSON.stringify(results, null, 2));
+ })
+ .catch((error) => {
+ console.error("\nError during scan:", error);
+ });
+ } catch (error: any) {
+ console.error("\nError with API token:", error?.message || error);
+ process.exit(1);
+ }
+ }
+ } else if (args[0] === "local") {
+ const projectPath: string | undefined = args[1];
+ const apiKeyFromArgs = args[2] && !process.env.SOLIDITYSCAN_API_KEY;
+ const apiKey: string | undefined = process.env.SOLIDITYSCAN_API_KEY || args[2];
+ let projectName: string | undefined = apiKeyFromArgs ? args[3] : args[2];
+
+ if(!projectName){
+ projectName = "LocalScan";
+ }
+
+ if (!projectPath) {
+ console.error("Usage: solisityscan run-tests ");
+ process.exit(1);
+ }
+
+ analyzeProject(projectPath, apiKey, projectName)
+ .then((results) => {
+ const r: any = results as any;
+ if(r?.scan_details?.link){
+ axios.get(r.scan_details.link)
+ .then((response) => {
+ utils.displayScanResults(response.data.scan_report);
+ })
+ .catch((error) => {
+ console.error("Error during scan:", error);
+ });
+ }
+ })
+ .catch((error) => {
+ console.error("Error during scan:", error);
+ });
+ } else if (args.includes("-l")) {
+
+ const dirFlagIndex = args.indexOf("-p");
+ const serveDirectory =
+ dirFlagIndex !== -1 && args[dirFlagIndex + 1]
+ ? args[dirFlagIndex + 1]
+ : process.cwd();
+
+
+ const portFlagIndex = args.indexOf("--port");
+ const userSpecifiedPort =
+ portFlagIndex !== -1 && args[portFlagIndex + 1]
+ ? parseInt(args[portFlagIndex + 1], 10)
+ : null;
+
+ const idFlagIndex = args.indexOf("--id");
+ const tunnelId =
+ idFlagIndex !== -1 && args[idFlagIndex + 1]
+ ? args[idFlagIndex + 1]
+ : null;
+
+ if (!tunnelId) {
+ console.error("Missing --id argument");
+ process.exit(1);
+ }
+
+ let portAttempts = 0;
+ let port = userSpecifiedPort || 9462;
+ let wss;
+
+ while (portAttempts < 5) {
+ try {
+ wss = utils.startLocalFileServer(serveDirectory, port);
+ break; // success
+ } catch (err: any) {
+ if (userSpecifiedPort || err?.code !== "EADDRINUSE") {
+ console.error(err?.message || "Failed to start local server");
+ process.exit(1);
+ }
+ port += 1;
+ portAttempts += 1;
+ }
+ }
+
+ if (!wss) {
+ console.error("Could not bind to any port between 9462 and 9466");
+ process.exit(1);
+ }
+
+ (async () => {
+ try {
+ const localtunnel = require("localtunnel");
+ const tunnel = await localtunnel({ port, subdomain: tunnelId });
+
+ const clean = () => {
+ try {
+ tunnel.close();
+ } catch (_) {}
+ try {
+ if (wss) wss.close();
+ } catch (_) {}
+ process.exit(0);
+ };
+ process.on("SIGINT", clean);
+ process.on("SIGTERM", clean);
+ } catch (e) {
+ console.error("Error during tunnel:", e);
+ }
+ })();
+
+ return;
+ } else {
+ console.error(
+ "Unknown command. Usage: solidityscan scan "
+ );
+ process.exit(1);
+ }
+}
+
+if (require.main === module) {
+ // executed via `node src/cli.js ...` β run the CLI
+ scan();
+}
+
+export {
+ scan,
+};
diff --git a/src/utils.js b/src/utils.js
deleted file mode 100755
index 782fcb6..0000000
--- a/src/utils.js
+++ /dev/null
@@ -1,436 +0,0 @@
-const request = require("request");
-const WebSocket = require("ws");
-const fs = require("fs");
-const path = require("path");
-const archiver = require("archiver");
-const axios = require("axios");
-const Table = require("cli-table3");
-
-const cliSpinners = require("cli-spinners");
-const spinner = cliSpinners.dots;
-
-const getApi = (apiToken) => {
- if (apiToken) {
- return axios.create({
- baseURL: "https://api-develop.solidityscan.com/",
- headers: {
- "Content-Type": "application/json",
- Authorization: `Bearer ${apiToken}`,
- "CF-Access-Client-Secret": "",
- "CF-Access-Client-Id": "",
- },
- });
- } else {
- return axios.create({
- baseURL: "https://api-develop.solidityscan.com/",
- headers: {
- "Content-Type": "application/json",
- "CF-Access-Client-Secret": "",
- "CF-Access-Client-Id": "",
- },
- });
- }
-};
-
-const initializeWebSocket = (apiToken, payload, spinner) => {
- const wsUrl = `${"wss://api-ws-stage.solidityscan.com/stage"}${
- apiToken ? `?auth_token=${apiToken}` : ""
- }`;
- const ws = new WebSocket(wsUrl);
-
- return new Promise((resolve, reject) => {
- ws.on("open", () => {
- ws.send(
- JSON.stringify({
- action: "message",
- payload: payload,
- })
- );
- });
-
- ws.on("message", (data) => {
- const receivedMessage = JSON.parse(data);
- if (receivedMessage.type === "error") {
- ws.close();
- reject(receivedMessage.payload.payload.error_message);
- } else if (receivedMessage.type === "scan_status") {
- if (receivedMessage.payload.scan_status === "scan_done") {
- request.get(
- receivedMessage.payload.scan_details.link,
- (error, response, body) => {
- if (error) {
- resolve(error);
- } else if (response.statusCode !== 200) {
- resolve(error);
- } else {
- const scan_result = JSON.parse(body);
- resolve(scan_result.scan_report);
- }
- stopSpinner(spinner, "Scan in progress");
- ws.close();
- }
- );
- }
- }
- console.log(receivedMessage);
- });
-
- ws.on("error", (error) => {
- console.log(error);
- reject(error);
- });
-
- ws.on("close", () => {});
- });
-};
-
-const createProjectZip = async (projectDirectory) => {
- try {
- const zipFileName = "project.zip";
- const output = fs.createWriteStream(zipFileName);
- const archive = archiver("zip", { zlib: { level: 9 } });
-
- archive.pipe(output);
-
- const gatherSolFiles = (directory) => {
- const files = fs.readdirSync(directory);
-
- files.forEach((file) => {
- const filePath = path.join(directory, file);
-
- if (fs.statSync(filePath).isDirectory() && file !== "node_modules") {
- gatherSolFiles(filePath);
- } else if (path.extname(file) === ".sol") {
- const relativePath = path.relative(projectDirectory, filePath);
- const fileContent = fs.readFileSync(filePath);
- archive.append(fileContent, { name: relativePath });
- }
- });
- };
-
- gatherSolFiles(projectDirectory);
-
- await archive.finalize();
-
- return zipFileName;
- } catch (error) {
- throw new Error(`Error creating project ZIP: ${error.message}`);
- }
-};
-
-const getUploadPresignedUrl = async (fileName, apiToken) => {
- const apiUrl = `private/api-get-presigned-url/?file_name=${fileName}`;
- const API = getApi(apiToken);
- const response = await API.get(apiUrl);
- if (response.status === 200 && response.data && response.data.result) {
- return response.data.result.url;
- } else {
- return null;
- }
-};
-
-const uploadToS3 = async (fileData, uploadUrl) => {
- try {
- const response = await axios.put(uploadUrl, fileData, {
- headers: {
- "Content-Type": "application/octet-stream",
- },
- // httpsAgent: new https.Agent({
- // rejectUnauthorized: false // Only for local
- // })
- });
- if (response.status === 200) {
- return true;
- } else {
- return false;
- }
- } catch (error) {
- console.log("error uploading file>",error)
- return false;
- }
-};
-
-function capitalizeFirstLetter(str) {
- return str.charAt(0).toUpperCase() + str.slice(1);
-}
-
-const displayScanResults = (scan) => {
- const table = new Table({
- head: ["Issue Name", "Issue Severity", "File Path", "Line No."],
- });
-
- scan.multi_file_scan_details.forEach((detail) => {
- const { template_details } = detail;
- if (detail.metric_wise_aggregated_findings) {
- detail.metric_wise_aggregated_findings.forEach((bug) => {
- const filePath = bug.findings[0].file_path;
- const line = `L${bug.findings[0].line_nos_start} - L${bug.findings[0].line_nos_end}`;
- const row = [
- template_details.issue_name,
- capitalizeFirstLetter(template_details.issue_severity),
- filePath.replace("/project", ""),
- line,
- ];
- table.push(row);
- });
- }
- });
-
- console.log(table.toString());
-};
-
-const displayScanSummary = (scan) => {
- const table = new Table();
-
- const issues_count =
- scan.multi_file_scan_summary.issue_severity_distribution.critical +
- scan.multi_file_scan_summary.issue_severity_distribution.high +
- scan.multi_file_scan_summary.issue_severity_distribution.medium +
- scan.multi_file_scan_summary.issue_severity_distribution.low +
- scan.multi_file_scan_summary.issue_severity_distribution.informational +
- scan.multi_file_scan_summary.issue_severity_distribution.gas;
-
- table.push(
- {
- Critical:
- scan.multi_file_scan_summary.issue_severity_distribution.critical,
- },
- { High: scan.multi_file_scan_summary.issue_severity_distribution.high },
- {
- Medium: scan.multi_file_scan_summary.issue_severity_distribution.medium,
- },
- { Low: scan.multi_file_scan_summary.issue_severity_distribution.low },
- {
- Informational:
- scan.multi_file_scan_summary.issue_severity_distribution.informational,
- },
- { Gas: scan.multi_file_scan_summary.issue_severity_distribution.gas },
- { "Security Score": `${scan.multi_file_scan_summary.score_v2} / 100` }
- );
- console.log(table.toString());
- console.log(
- `Scan successful! ${issues_count} issues found. To view detailed results and generate a report navigate to solidityscan.com.`
- );
-};
-
-// Function to display a spinner with dynamic status
-async function showSpinnerWithStatus(statusMessage, spinnerFrames) {
- process.stdout.write(`${statusMessage}... `);
-
- let frameIndex = 0;
-
- const interval = setInterval(() => {
- process.stdout.write(spinnerFrames[frameIndex]);
- process.stdout.write("\b");
- frameIndex = (frameIndex + 1) % spinnerFrames.length;
- }, 100);
-
- return interval;
-}
-
-// Function to stop the spinner
-function stopSpinner(interval, statusMessage) {
- clearInterval(interval);
- process.stdout.write("\r");
- console.log(`${statusMessage}... Done`);
-}
-
-// New helper to serve local directory over WebSocket
-function startLocalFileServer(rootDirectory, port = 8080) {
- if (!fs.existsSync(rootDirectory)) {
- throw new Error(`Directory not found: ${rootDirectory}`);
- }
-
- const absoluteRoot = path.resolve(rootDirectory);
- const wss = new WebSocket.Server({ port });
-
- // eslint-disable-next-line no-console
- console.log(`SolidityScan local file server started on ws://localhost:${wss.options.port}\nServing directory: ${absoluteRoot}`);
-
- wss.on("connection", (socket) => {
- socket.on("message", async (raw) => {
- let message;
- try {
- message = JSON.parse(raw);
- } catch (err) {
- socket.send(
- JSON.stringify({ type: "error", error: "Invalid JSON message" })
- );
- return;
- }
-
- const { action, payload } = message;
-
- if (action === "listFiles") {
- // Return hierarchical folder tree with metadata
- const buildTree = (dir, relPath = "") => {
- const name = path.basename(dir);
- const stat = fs.statSync(dir);
- if (stat.isDirectory()) {
- const dirs = [];
- const files = [];
- fs.readdirSync(dir).forEach((entry) => {
- if (entry === "node_modules") return;
- const abs = path.join(dir, entry);
- const rootName = path.basename(absoluteRoot);
-
- let childRel;
- if (relPath === "") {
- childRel = path.join(rootName, entry);
- } else {
- childRel = path.join(relPath, entry);
- }
-
- if (fs.statSync(abs).isDirectory()) {
- dirs.push(buildTree(abs, childRel + path.sep));
- } else {
- const fStat = fs.statSync(abs);
- files.push({
- path: childRel,
- name: entry,
- size: fStat.size,
- mtimeMs: fStat.mtimeMs,
- checked: entry.endsWith(".sol"),
- });
- }
- });
-
- // Determine checked / isChildCheck flags
- const numSol = files.filter((f) => f.checked).length;
- const numNonSol = files.length - numSol;
- let checkedDir = false;
- let isChildCheck = false;
- if (numSol === 0) {
- checkedDir = false;
- isChildCheck = false;
- } else if (numNonSol === 0) {
- checkedDir = true;
- isChildCheck = true;
- } else {
- checkedDir = false;
- isChildCheck = true;
- }
-
- let dirPath;
- if (dir === absoluteRoot) {
- dirPath = path.basename(absoluteRoot) + "/";
- } else {
- dirPath = relPath + (relPath && !relPath.endsWith(path.sep) ? path.sep : "");
- }
-
- return {
- name,
- path: dirPath,
- tree: dirs,
- isChildCheck,
- checked: checkedDir,
- blobs: files,
- size: 0,
- mtimeMs: stat.mtimeMs,
- };
- }
- // Should not reach here for files as we handle in parent
- };
-
- const rootTreeInternal = buildTree(absoluteRoot, "");
- const responseTree = {
- name: "",
- path: "",
- tree: [rootTreeInternal],
- isChildCheck: rootTreeInternal.isChildCheck,
- checked: rootTreeInternal.checked,
- blobs: [],
- size: 0,
- mtimeMs: rootTreeInternal.mtimeMs,
- };
-
- socket.send(
- JSON.stringify({ type: "folderStructure", tree: responseTree })
- );
- } else if (action === "zipAndSendFiles") {
- const presignedUrl = payload.presigned_url;
- const skip = new Set(payload.skip_file_paths || []);
- if (!presignedUrl) {
- socket.send(
- JSON.stringify({ type: "error", error: "presigned_url missing" })
- );
- return;
- }
-
- const archive = archiver("zip", { zlib: { level: 9 } });
- const chunks = [];
-
- archive.on("data", (chunk) => chunks.push(chunk));
- archive.on("warning", (err) => {
- if (err.code !== "ENOENT") {
- socket.send(JSON.stringify({ type: "error", error: err.message }));
- }
- });
- archive.on("error", (err) => {
- socket.send(JSON.stringify({ type: "error", error: err.message }));
- });
- archive.on("end", async () => {
- const buffer = Buffer.concat(chunks);
-
- let success = false;
- try {
- if (presignedUrl.startsWith("memory://")) {
- // test stub
- success = true;
- } else {
- success = await uploadToS3(buffer, presignedUrl);
- }
- } catch (e) {
- console.log("error uploading file",e)
- success = false;
- }
-
- socket.send(
- JSON.stringify({
- type: "uploadStatus",
- success,
- })
- );
- });
-
- // recursively walk and add files not skipped
- const walkAdd = (dir, rel = "") => {
- fs.readdirSync(dir).forEach((entry) => {
- if (entry === "node_modules") return;
- const abs = path.join(dir, entry);
- const relPath = path.join(rel, entry);
- const relPathPosix = relPath.split(path.sep).join("/");
- const stat = fs.statSync(abs);
- if (stat.isDirectory()) {
- walkAdd(abs, relPath);
- } else {
- if (!skip.has(relPathPosix)) {
- archive.file(abs, { name: relPath });
- }
- }
- });
- };
- walkAdd(absoluteRoot, "");
- archive.finalize();
- } else {
- socket.send(
- JSON.stringify({ type: "error", error: "Unknown action" })
- );
- }
- });
- });
-
- return wss;
-}
-
-module.exports = {
- initializeWebSocket,
- createProjectZip,
- getUploadPresignedUrl,
- uploadToS3,
- displayScanResults,
- displayScanSummary,
- showSpinnerWithStatus,
- stopSpinner,
- startLocalFileServer,
-};
diff --git a/src/utils.ts b/src/utils.ts
new file mode 100755
index 0000000..a8b613e
--- /dev/null
+++ b/src/utils.ts
@@ -0,0 +1,585 @@
+import request from "request";
+import WebSocket from "ws";
+import fs from "fs";
+import path from "path";
+import archiver from "archiver";
+import axios, { type AxiosInstance } from "axios";
+import Table from "cli-table3";
+
+import cliSpinners from "cli-spinners";
+const spinner = cliSpinners.dots;
+
+const getApi = (apiToken?: string): AxiosInstance => {
+ const apiBaseUrl = "https://api.solidityscan.com/";
+ if (apiToken) {
+ const instance = axios.create({
+ baseURL: apiBaseUrl,
+ headers: {
+ "Content-Type": "application/json",
+ "accept": "application/json, text/plain, */*",
+ "Authorization": `Bearer ${apiToken}`,
+ "cache-control": "no-cache",
+ }
+ });
+ return instance;
+ } else {
+ const instance = axios.create({
+ baseURL: apiBaseUrl,
+ headers: {
+ "Content-Type": "application/json",
+ "CF-Access-Client-Secret": "",
+ "CF-Access-Client-Id": "",
+ }
+ });
+ return instance;
+ }
+};
+
+const initializeWebSocket = (apiToken: string | undefined, payload: any, spinner: boolean = true, ): Promise => {
+ const wsUrl = 'wss://api-ws.solidityscan.com/';
+ const ws = new WebSocket(wsUrl, {
+ rejectUnauthorized: false
+ });
+
+ const emitMessage = (messagePayload: any) => {
+ ws.send(
+ JSON.stringify({
+ action: "message",
+ payload: messagePayload,
+ })
+ );
+ };
+
+ return new Promise((resolve, reject) => {
+ const connectionTimeout: NodeJS.Timeout = setTimeout(() => {
+ ws.close();
+ reject(new Error("WebSocket connection timed out waiting for scan results"));
+ }, 60000); // 60 second timeout
+ ws.on("open", () => {
+ if (apiToken) {
+ emitMessage({
+ type: "auth_token_register",
+ body: {
+ auth_token: apiToken,
+ },
+ });
+ } else {
+ console.log("No authentication token provided, sending payload directly");
+ emitMessage(payload);
+ }
+ });
+
+ ws.on("message", (data: any) => {
+ try {
+ const receivedMessage = JSON.parse(data.toString());
+ clearTimeout(connectionTimeout);
+ if (receivedMessage.type === "auth_token_register") {
+
+ if (payload.payload) {
+ emitMessage(payload.payload);
+ } else {
+ emitMessage(payload);
+ }
+ }
+ else if (receivedMessage.type === "scan_status") {
+ if (receivedMessage.payload?.scan_status === "scan_done") {
+ resolve(receivedMessage.payload);
+ ws.close();
+ }
+ }
+ else if (receivedMessage.type === "quick_scan_status") {
+ if (receivedMessage.payload?.scan_status === "scan_done") {
+ resolve(receivedMessage.payload);
+ ws.close();
+ } else {
+ console.log(`\n[WebSocket] Waiting for scan to complete. Current status: ${receivedMessage.payload?.scan_status || receivedMessage.payload?.quick_scan_status || 'processing'}`);
+ }
+ }
+ else if (receivedMessage.type === "report_generation_status") {
+ if (receivedMessage.payload?.report_status === "report_generated") {
+ resolve(receivedMessage.payload);
+ ws.close();
+ } else {
+ console.log(`\n[WebSocket] Report generation payload: ${receivedMessage.payload}`);
+ }
+ }
+ else if (receivedMessage.type === "quick_scan_result") {
+ if (receivedMessage.payload?.scan_details?.link) {
+ request.get(
+ receivedMessage.payload.scan_details.link,
+ (error: any, response: any, body: any) => {
+ if (error) {
+ resolve(error);
+ } else if (response.statusCode !== 200) {
+ resolve(error);
+ } else {
+ try {
+ const scan_result = JSON.parse(body);
+ resolve(scan_result.scan_report || scan_result);
+ } catch (e) {
+ resolve(body);
+ }
+ }
+
+ ws.close();
+ }
+ );
+ }
+ }
+ else if (receivedMessage.type === "error") {
+ console.log("\n Error received from server:", receivedMessage.payload?.payload?.error_message || receivedMessage.payload?.error_message || "Unknown error");
+ ws.close();
+ reject(receivedMessage.payload?.payload?.error_message || receivedMessage.payload?.error_message || "Unknown error from server");
+ }
+ else {
+ if (spinner) {
+ process.stdout.write(".");
+ }
+ }
+ } catch (error) {
+ console.error("\nError processing message:", error);
+ console.error("\nRaw message data:", data.toString());
+ }
+ });
+
+ ws.on("error", (error: unknown) => {
+ console.log(error);
+ reject(error);
+ });
+
+ ws.on("close", () => {});
+ });
+};
+
+const createProjectZip = async (projectDirectory: string): Promise => {
+ try {
+ const zipFileName = "project.zip";
+ const output = fs.createWriteStream(zipFileName);
+ const archive = archiver("zip", { zlib: { level: 9 } });
+
+ archive.pipe(output);
+
+ const gatherSolFiles = (directory: string) => {
+ const files = fs.readdirSync(directory);
+
+ files.forEach((file) => {
+ const filePath = path.join(directory, file);
+
+ if (fs.statSync(filePath).isDirectory() && file !== "node_modules") {
+ gatherSolFiles(filePath);
+ } else if (path.extname(file) === ".sol") {
+ const relativePath = path.relative(projectDirectory, filePath);
+ const fileContent = fs.readFileSync(filePath);
+ archive.append(fileContent, { name: relativePath });
+ }
+ });
+ };
+
+ gatherSolFiles(projectDirectory);
+
+ await archive.finalize();
+
+ return zipFileName;
+ } catch (error: any) {
+ throw new Error(`Error creating project ZIP: ${error.message}`);
+ }
+};
+
+const getUploadPresignedUrl = async (fileName: string, apiToken?: string) => {
+ try {
+ const apiUrl = `private/api-get-presigned-url/?file_name=${fileName}`;
+ const API = getApi(apiToken);
+ const response = await API.get(apiUrl);
+ if (response.status === 200 && response.data && response.data.result) {
+ return response.data.result.url;
+ } else {
+ return null;
+ }
+ } catch (error: any) {
+ throw new Error(`Failed to get presigned URL: ${error.message}`);
+ }
+};
+
+const uploadToS3 = async (fileData: Buffer | Uint8Array, uploadUrl: string): Promise => {
+ try {
+ const response = await axios.put(uploadUrl, fileData, {
+ headers: {
+ "Content-Type": "application/octet-stream",
+ }
+ });
+
+ if (response.status === 200 || response.status === 204) {
+ return true;
+ } else {
+ return false;
+ }
+ } catch (error) {
+ return false;
+ }
+};
+
+function capitalizeFirstLetter(str: string) {
+ return str.charAt(0).toUpperCase() + str.slice(1);
+}
+
+function formatHtmlForTerminal(htmlContent: string) {
+ if (!htmlContent) return '';
+ let text = htmlContent.replace(/
/gi, '\n');
+ text = text.replace(/(.*?)<\/code>/gi, '`$1`');
+ text = text.replace(/<\/?[^>]+(>|$)/g, '');
+ text = text.replace(/\s+/g, ' ').trim();
+
+ return text;
+}
+
+const displayScanResults = (scan: any): void => {
+ const table = new Table({
+ head: ["#", "NAME", "SEVERITY", "CONFIDENCE", "DESCRIPTION", "REMEDIATION"],
+ chars: {
+ 'top': 'β', 'top-mid': 'β¬', 'top-left': 'β', 'top-right': 'β',
+ 'bottom': 'β', 'bottom-mid': 'β΄', 'bottom-left': 'β', 'bottom-right': 'β',
+ 'left': 'β', 'left-mid': 'β', 'mid': 'β', 'mid-mid': 'βΌ',
+ 'right': 'β', 'right-mid': 'β€', 'middle': 'β'
+ },
+ style: {
+ head: ['bold']
+ },
+ // Configure optimal column widths
+ colWidths: [5, 20, 12, 12, 35, 35],
+ wordWrap: true
+ });
+
+ let issueCount = 0;
+ scan.multi_file_scan_details.forEach((detail: any) => {
+ const { template_details } = detail;
+ if (detail.metric_wise_aggregated_findings) {
+ detail.metric_wise_aggregated_findings.forEach((bug: any) => {
+ issueCount++;
+ const filePath = bug.findings[0].file_path;
+ const location = `${filePath.replace("/project", "")}\nL${bug.findings[0].line_nos_start} - L${bug.findings[0].line_nos_end}`;
+ const description = formatHtmlForTerminal(template_details.issue_description);
+ const fullDescription = `${description}\n\nLocation:\n${location}`;
+
+ const row = [
+ `${issueCount}.`,
+ template_details.issue_name,
+ capitalizeFirstLetter(template_details.issue_severity),
+ template_details.issue_confidence,
+ fullDescription,
+ formatHtmlForTerminal(template_details.issue_remediation)
+ ];
+ table.push(row);
+ });
+ }
+ });
+
+ if (issueCount === 0) {
+ console.log('No security issues found!');
+ } else {
+ console.log('SECURITY SCAN RESULTS:');
+ console.log(table.toString());
+ console.log(`Found ${issueCount} security ${issueCount === 1 ? 'issue' : 'issues'}.`);
+ }
+};
+
+const displayScanSummary = (scan: any): void => {
+ const table = new Table();
+
+ const issues_count =
+ scan.multi_file_scan_summary.issue_severity_distribution.critical +
+ scan.multi_file_scan_summary.issue_severity_distribution.high +
+ scan.multi_file_scan_summary.issue_severity_distribution.medium +
+ scan.multi_file_scan_summary.issue_severity_distribution.low +
+ scan.multi_file_scan_summary.issue_severity_distribution.informational +
+ scan.multi_file_scan_summary.issue_severity_distribution.gas;
+
+ table.push(
+ {
+ Critical:
+ scan.multi_file_scan_summary.issue_severity_distribution.critical,
+ },
+ { High: scan.multi_file_scan_summary.issue_severity_distribution.high },
+ {
+ Medium: scan.multi_file_scan_summary.issue_severity_distribution.medium,
+ },
+ { Low: scan.multi_file_scan_summary.issue_severity_distribution.low },
+ {
+ Informational:
+ scan.multi_file_scan_summary.issue_severity_distribution.informational,
+ },
+ { Gas: scan.multi_file_scan_summary.issue_severity_distribution.gas },
+ { "Security Score": `${scan.multi_file_scan_summary.score_v2} / 100` }
+ );
+ console.log(table.toString());
+ console.log(
+ `Scan successful! ${issues_count} issues found. To view detailed results and generate a report navigate to solidityscan.com.`
+ );
+};
+
+// Function to display a spinner with dynamic status
+async function showSpinnerWithStatus(statusMessage: string, spinnerFrames: string[]): Promise> {
+ process.stdout.write(`${statusMessage}... `);
+
+ let frameIndex = 0;
+
+ const interval = setInterval(() => {
+ process.stdout.write(spinnerFrames[frameIndex]);
+ process.stdout.write("\b");
+ frameIndex = (frameIndex + 1) % spinnerFrames.length;
+ }, 100);
+
+ return interval as ReturnType;
+}
+
+// Function to stop the spinner
+function stopSpinner(interval: ReturnType, statusMessage: string) {
+ clearInterval(interval as any);
+ process.stdout.write("\r");
+ console.log(`${statusMessage}... Done`);
+}
+
+// New helper to serve local directory over WebSocket
+function startLocalFileServer(rootDirectory: string, port: number = 8080) {
+ if (!fs.existsSync(rootDirectory)) {
+ throw new Error(`Directory not found: ${rootDirectory}`);
+ }
+
+ const absoluteRoot = path.resolve(rootDirectory);
+ const wss = new WebSocket.Server({ port, verifyClient: (info: any, done: any) => {
+ if (!originIsAllowed(info.origin)) {
+ done(false)
+ console.log(`Connection from origin ${info.origin} is not allowed`)
+ return
+ }
+ done(true)
+ } });
+
+ console.log(`SolidityScan local file server started\nServing directory: ${absoluteRoot}`);
+
+ wss.on("connection", (socket: any) => {
+ socket.on("message", async (raw: any) => {
+ let message;
+ try {
+ message = JSON.parse(raw);
+ } catch (err) {
+ socket.send(
+ JSON.stringify({ type: "error", error: "Invalid JSON message" })
+ );
+ return;
+ }
+
+ const { action, payload } = message;
+
+ if (action === "listFiles") {
+ // Return hierarchical folder tree with metadata
+ const buildTree = (dir: string, relPath: string = ""): any => {
+ const name = path.basename(dir);
+ const stat = fs.statSync(dir);
+ if (stat.isDirectory()) {
+ const dirs: any[] = [];
+ const files: any[] = [];
+ fs.readdirSync(dir).forEach((entry) => {
+ if (entry === "node_modules") return;
+ const abs = path.join(dir, entry);
+ const rootName = path.basename(absoluteRoot);
+
+ // Build a raw relative path using native separators
+ let childRelRaw: string;
+ if (relPath === "") {
+ childRelRaw = path.join(rootName, entry);
+ } else {
+ childRelRaw = path.join(relPath, entry);
+ }
+
+ // Convert to POSIX style with a single "/" separator for JSON responses
+ const childRel = childRelRaw
+ .split(path.sep)
+ .join("/")
+ .replace(/\/+/g, "/");
+
+ if (fs.statSync(abs).isDirectory()) {
+ // Recurse with the raw path to preserve correct joining behaviour
+ dirs.push(buildTree(abs, childRelRaw + path.sep));
+ } else {
+ const fStat = fs.statSync(abs);
+ files.push({
+ path: childRel,
+ name: entry,
+ size: fStat.size,
+ mtimeMs: fStat.mtimeMs,
+ checked: entry.endsWith(".sol"),
+ });
+ }
+ });
+
+ // Determine checked / isChildCheck flags
+ const numSol = files.filter((f) => f.checked).length;
+ const numNonSol = files.length - numSol;
+ let checkedDir = false;
+ let isChildCheck = false;
+ if (numSol === 0) {
+ checkedDir = false;
+ isChildCheck = false;
+ } else if (numNonSol === 0) {
+ checkedDir = true;
+ isChildCheck = true;
+ } else {
+ checkedDir = false;
+ isChildCheck = true;
+ }
+
+ // Build directory path (raw) and then normalise to POSIX
+ let dirPathRaw: string;
+ if (dir === absoluteRoot) {
+ dirPathRaw = path.basename(absoluteRoot) + path.sep;
+ } else {
+ dirPathRaw = relPath + (relPath && !relPath.endsWith(path.sep) ? path.sep : "");
+ }
+
+ let dirPath = dirPathRaw
+ .split(path.sep)
+ .join("/")
+ .replace(/\/+/g, "/");
+ // Ensure directory paths end with a single trailing slash
+ if (!dirPath.endsWith("/")) {
+ dirPath += "/";
+ }
+
+ return {
+ name,
+ path: dirPath,
+ tree: dirs,
+ isChildCheck,
+ checked: checkedDir,
+ blobs: files,
+ size: 0,
+ mtimeMs: stat.mtimeMs,
+ };
+ }
+ // Should not reach here for files as we handle in parent
+ return undefined as any;
+ };
+
+ const rootTreeInternal: any = buildTree(absoluteRoot, "") as any;
+ const responseTree = {
+ name: "",
+ path: "",
+ tree: [rootTreeInternal],
+ isChildCheck: rootTreeInternal.isChildCheck,
+ checked: rootTreeInternal.checked,
+ blobs: [],
+ size: 0,
+ mtimeMs: rootTreeInternal.mtimeMs,
+ };
+
+ socket.send(
+ JSON.stringify({ type: "folderStructure", tree: responseTree })
+ );
+ } else if (action === "zipAndSendFiles") {
+ const presignedUrl = payload.presigned_url;
+ if (!originIsAllowed(payload.origin)) {
+ socket.send(
+ JSON.stringify({ type: "error", error: "origin not allowed" })
+ );
+ return;
+ }
+ const skip = new Set(payload.skip_file_paths || []);
+ if (!presignedUrl) {
+ socket.send(
+ JSON.stringify({ type: "error", error: "presigned_url missing" })
+ );
+ return;
+ }
+
+ const archive = archiver("zip", { zlib: { level: 9 } });
+ const chunks: Buffer[] = [];
+
+ archive.on("data", (chunk: Buffer) => chunks.push(chunk));
+ archive.on("warning", (err: any) => {
+ if (err.code !== "ENOENT") {
+ socket.send(JSON.stringify({ type: "error", error: err.message }));
+ }
+ });
+ archive.on("error", (err: any) => {
+ socket.send(JSON.stringify({ type: "error", error: err.message }));
+ });
+ archive.on("end", async () => {
+ const buffer = Buffer.concat(chunks);
+
+ let success = false;
+ try {
+ if (presignedUrl.startsWith("memory://")) {
+ // test stub
+ success = true;
+ } else {
+ success = await uploadToS3(buffer, presignedUrl);
+ }
+ } catch (e) {
+ console.log("error uploading file",e)
+ success = false;
+ }
+
+ socket.send(
+ JSON.stringify({
+ type: "uploadStatus",
+ success,
+ })
+ );
+ });
+
+ // recursively walk and add files not skipped
+ const walkAdd = (dir: string, rel: string = "") => {
+ fs.readdirSync(dir).forEach((entry) => {
+ if (entry === "node_modules") return;
+ const abs = path.join(dir, entry);
+ const relPath = path.join(rel, entry);
+ const relPathPosix = relPath
+ .split(path.sep)
+ .join("/")
+ .replace(/\/+/g, "/");
+ const stat = fs.statSync(abs);
+ if (stat.isDirectory()) {
+ walkAdd(abs, relPath);
+ } else {
+ if (!skip.has(relPathPosix)) {
+ // Use POSIX-style path inside the archive to avoid platform-specific separators
+ archive.file(abs, { name: relPathPosix });
+ }
+ }
+ });
+ };
+ walkAdd(absoluteRoot, "");
+ archive.finalize();
+ } else {
+ socket.send(
+ JSON.stringify({ type: "error", error: "Unknown action" })
+ );
+ }
+ });
+ });
+
+ return wss;
+}
+
+function getDomain (url: string) {
+ const domainMatch = url.match(/^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)/img)
+ return domainMatch ? domainMatch[0] : null
+}
+function originIsAllowed (origin: string) {
+ return true;
+ const DOMAIN = getDomain(origin) || "";
+ const allowedOrigins = ["https://solidityscan.com","https://develop.solidityscan.com", "https://credshields-prod.s3.amazonaws.com", "https://credshields-dev.s3.amazonaws.com/"]
+ return allowedOrigins.includes(DOMAIN)
+}
+
+export {
+ initializeWebSocket,
+ createProjectZip,
+ getUploadPresignedUrl,
+ uploadToS3,
+ displayScanResults,
+ displayScanSummary,
+ showSpinnerWithStatus,
+ stopSpinner,
+ startLocalFileServer,
+};
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..ae4c449
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,32 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "CommonJS",
+ "moduleResolution": "Node",
+ "outDir": "dist",
+ "rootDir": ".",
+ "declaration": true,
+ "sourceMap": true,
+ "strict": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "types": ["node"],
+ "allowJs": true
+ },
+ "include": [
+ "index.ts",
+ "src/**/*.ts",
+ "bin/**/*.ts",
+ "types.d.ts"
+ ],
+ "exclude": [
+ "dist",
+ "node_modules",
+ "__tests__"
+ ]
+}
+
diff --git a/types.d.ts b/types.d.ts
new file mode 100644
index 0000000..b91a8dd
--- /dev/null
+++ b/types.d.ts
@@ -0,0 +1,18 @@
+declare module 'request' {
+ const request: any;
+ export default request;
+}
+declare module 'archiver' {
+ const archiver: any;
+ export default archiver;
+}
+declare module 'ws' {
+ export default class WebSocket {
+ static Server: any;
+ constructor(url: string, options?: any);
+ on(event: string, cb: (...args: any[]) => void): void;
+ send(data: any): void;
+ close(): void;
+ }
+}
+