locadot 1.4.1 โ†’ 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,7 +14,7 @@
14
14
  ## ๐Ÿš€ Usage
15
15
 
16
16
  ```bash
17
- npx locadot --host dev.localhost --port 3350
17
+ npx locadot add --host dev.localhost --port 3350
18
18
  ```
19
19
 
20
20
  ---
@@ -26,7 +26,24 @@ npx locadot --host dev.localhost --port 3350
26
26
  ###### Starts a reverse proxy to the specified localhost port.
27
27
 
28
28
  ```bash
29
- npx locadot --host <custom.localhost> --port <localhost-port>
29
+ npx locadot add --host <custom.localhost> --port <localhost-port>
30
+ ```
31
+
32
+ ##### ๐Ÿงพ Update existing host
33
+
34
+ ###### Update domains currently registered with locadot.
35
+
36
+ ```bash
37
+ npx locadot update --host <your.localhost> --port <localhost-port>
38
+ ```
39
+
40
+
41
+ ##### ๐Ÿงพ Remove existing host
42
+
43
+ ###### Remove domains currently registered with locadot.
44
+
45
+ ```bash
46
+ npx locadot remove --host <your.localhost>
30
47
  ```
31
48
 
32
49
  ##### ๐Ÿงพ View Registered Hosts
@@ -42,7 +59,7 @@ npx locadot host
42
59
  ###### Continuously watches and outputs proxy logs in real time.
43
60
 
44
61
  ```bash
45
- npx locadot watch logs
62
+ npx locadot watch:logs
46
63
  ```
47
64
 
48
65
  ##### ๐Ÿงน Clear Logs
@@ -50,15 +67,42 @@ npx locadot watch logs
50
67
  ###### Clears all saved logs.
51
68
 
52
69
  ```bash
53
- npx locadot clear logs
70
+ npx locadot clear:logs
54
71
  ```
72
+
73
+ ##### ๐Ÿงน Clear Hosts
74
+
75
+ ###### Clears all existing hosts.
76
+
77
+ ```bash
78
+ npx locadot clear:hosts
79
+ ```
80
+
81
+ ##### ๐Ÿงน Show Config Path
82
+
83
+ ###### Print the path of config files used.
84
+
85
+ ```bash
86
+ npx locadot path
87
+ ```
88
+
55
89
  ##### ๐Ÿงน Show Logs Path
56
90
 
57
91
  ###### Print the path of logged files used.
58
92
 
59
93
  ```bash
60
- npx locadot path logs
94
+ npx locadot path:logs
61
95
  ```
96
+
97
+
98
+ ##### ๐Ÿงน Show Hosts Path
99
+
100
+ ###### Print the path of hosts files used.
101
+
102
+ ```bash
103
+ npx locadot path:hosts
104
+ ```
105
+
62
106
  ##### ๐Ÿ”„ Restart Proxy
63
107
 
64
108
  ###### Restarts the proxy server and reloads configuration.
package/dist/certs.js CHANGED
@@ -9,18 +9,19 @@ const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const CERT_PATH = (0, appdata_path_1.default)("locadot");
11
11
  const mkcert_1 = require("mkcert");
12
+ const logger_1 = __importDefault(require("./utils/logger"));
12
13
  async function createSSL(domain) {
13
- console.log(`๐Ÿ” Preparing SSL cert for ${domain}`);
14
+ logger_1.default.info(`๐Ÿ” Preparing SSL cert for ${domain}`);
14
15
  const KEY_FILE = path_1.default.join(CERT_PATH, domain + ".key");
15
16
  const CERT_FILE = path_1.default.join(CERT_PATH, domain + ".pem");
16
17
  if (fs_1.default.existsSync(KEY_FILE) && fs_1.default.existsSync(CERT_FILE)) {
17
- console.log(`๐Ÿ”„ Using existing certificate for ${domain}`);
18
+ logger_1.default.info(`๐Ÿ”„ Using existing certificate for ${domain}`);
18
19
  const key = fs_1.default.readFileSync(KEY_FILE, "utf-8");
19
20
  const cert = fs_1.default.readFileSync(CERT_FILE, "utf-8");
20
21
  return { key, cert };
21
22
  }
22
23
  // Otherwise, generate a new one
23
- console.log(`๐Ÿ” Generating SSL cert for ${domain}`);
24
+ logger_1.default.info(`๐Ÿ” Generating SSL cert for ${domain}`);
24
25
  const ca = await (0, mkcert_1.createCA)({
25
26
  organization: "Locadot",
26
27
  countryCode: "IN",
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const appdata_path_1 = __importDefault(require("appdata-path"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const PACKAGE_PATH = (0, appdata_path_1.default)("locadot");
9
+ const LOGS = path_1.default.join(PACKAGE_PATH, ".locadot.log");
10
+ const LOCK_FILE = path_1.default.join(PACKAGE_PATH, ".locadot.lock");
11
+ const REGISTRY_FILE = path_1.default.join(PACKAGE_PATH, ".locadot-registry.json");
12
+ class Constants {
13
+ }
14
+ Constants.paths = {
15
+ LOCK_FILE: LOCK_FILE,
16
+ REGISTRY_FILE: REGISTRY_FILE,
17
+ LOGS: LOGS,
18
+ };
19
+ Constants.proxyInfo = {
20
+ invalidHost: "โŒ Invalid domain. Please use a valid localhost domain like dev.localhost, localhost, test.localhost, etc.",
21
+ hostExist: "โŒ Domain already in use. Please choose another domain or stop the existing instance.",
22
+ hostNotFound: "โŒ Domain not found. Please choose another domain or stop the existing instance.",
23
+ proxyClose: "โ˜‘๏ธ Successfully stopped all locadot instances.",
24
+ softClose: "โ˜‘๏ธ Successfully stopped central proxy..",
25
+ };
26
+ exports.default = Constants;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.proxyNotFound = void 0;
4
+ const proxyNotFound = (host) => `
5
+ <!DOCTYPE html>
6
+ <html lang="en">
7
+ <head>
8
+ <meta charset="UTF-8" />
9
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
10
+ <title>Proxy Error</title>
11
+ <style>
12
+ body {
13
+ background-color: #121212;
14
+ color: #f8d7da;
15
+ font-family: 'Segoe UI', sans-serif;
16
+ margin: 0;
17
+ padding: 20px;
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: center;
21
+ min-height: 90vh;
22
+ }
23
+
24
+ .error-box {
25
+ background-color: #1e1e1e;
26
+ border: 1px solid #d9534f;
27
+ padding: 24px;
28
+ border-radius: 8px;
29
+ max-width: 600px;
30
+ width: 100%;
31
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.7);
32
+ }
33
+
34
+ .error-box code {
35
+ background: #2e2e2e;
36
+ color: #ffd5d5;
37
+ padding: 2px 6px;
38
+ border-radius: 4px;
39
+ font-family: monospace;
40
+ }
41
+
42
+ .error-box a {
43
+ color: #61dafb;
44
+ text-decoration: none;
45
+ font-weight: bold;
46
+ }
47
+
48
+ .error-box a:hover {
49
+ text-decoration: underline;
50
+ }
51
+ </style>
52
+ </head>
53
+ <body>
54
+ <div class="error-box">
55
+ <strong style="color: #ff6b6b;">Connection failed:</strong>
56
+ Proxy does not exist for
57
+ <code>${host}</code>.<br/><br/>
58
+ Please use
59
+ <code>npx locadot --host ${host} --port PORT</code><br/><br/>
60
+ <a href="https://github.com/avinashid/locadot#readme" target="_blank">
61
+ ๐Ÿ“˜ View on GitHub
62
+ </a>
63
+ </div>
64
+ </body>
65
+ </html>
66
+ `;
67
+ exports.proxyNotFound = proxyNotFound;
package/dist/core.js CHANGED
@@ -3,11 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const locadot_file_1 = __importDefault(require("./lib/locadot-file"));
7
- const server_1 = __importDefault(require("./server"));
6
+ const proxy_1 = __importDefault(require("./proxy"));
7
+ const logger_1 = __importDefault(require("./utils/logger"));
8
8
  async function run() {
9
- locadot_file_1.default.updateLogs("๐Ÿ”„ Starting central proxy.");
10
- await server_1.default.startCentralProxy();
11
- locadot_file_1.default.updateLogs("โ˜‘๏ธ Central proxy started.");
9
+ logger_1.default.info(`๐Ÿ”„ Starting central proxy.`);
10
+ await proxy_1.default.startCentralProxy();
11
+ logger_1.default.info("โ˜‘๏ธ Central proxy started.");
12
12
  }
13
13
  run();
package/dist/index.js CHANGED
@@ -4,56 +4,97 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- const yargs_1 = __importDefault(require("yargs"));
8
- const helpers_1 = require("yargs/helpers");
7
+ const commander_1 = require("commander");
9
8
  const commands_1 = __importDefault(require("./lib/commands"));
10
- const constants_1 = require("./utils/constants");
11
- async function run() {
12
- await (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
13
- .scriptName("locadot")
14
- .usage("Usage: npx locadot --host local.dev --port 3350")
15
- .command("$0", "Run the proxy with a domain and port", (yargs) => {
16
- return yargs
17
- .option("host", {
18
- alias: "h",
19
- describe: "Domain to map (must point to 127.0.0.1 in hosts file)",
20
- demandOption: true,
21
- type: "string",
22
- })
23
- .option("port", {
24
- alias: "p",
25
- describe: "Local port to forward to",
26
- demandOption: true,
27
- type: "number",
28
- });
29
- }, async (argv) => {
30
- await commands_1.default.start(argv);
31
- })
32
- .command("host", "Show all hosts.", () => {
33
- commands_1.default.getRegistry();
34
- })
35
- .command("watch logs", "Watch log files", () => { }, async (argv) => {
36
- commands_1.default.watchLogs();
37
- })
38
- .command("clear logs", "Clear logs", () => { }, async (argv) => {
39
- commands_1.default.clearLogs();
40
- })
41
- .command("path logs", "Show log path", () => { }, async (argv) => {
42
- commands_1.default.logPath();
43
- })
44
- .command("restart", "Restart locadot", () => { }, async (argv) => {
45
- commands_1.default.restart();
46
- })
47
- .command("stop", "Stop central proxy and logs.", () => { }, async (argv) => {
48
- await commands_1.default.stop();
49
- console.log(constants_1.errorConstants.proxyClose);
50
- process.exit(0);
51
- })
52
- .command("kill", "Stop central proxy and clear all logs and also port mapping.", () => { }, async (argv) => {
53
- await commands_1.default.kill();
54
- console.log(constants_1.errorConstants.proxyClose);
55
- process.exit(0);
56
- })
57
- .help().argv;
58
- }
59
- run();
9
+ const logger_1 = __importDefault(require("./utils/logger"));
10
+ const package_json_1 = require("../package.json");
11
+ const constants_1 = __importDefault(require("./constants"));
12
+ const program = new commander_1.Command();
13
+ program
14
+ .name("locadot")
15
+ .description("Locadot CLI - Local domain proxy manager")
16
+ .version(package_json_1.version);
17
+ program
18
+ .command("add")
19
+ .description("Add a new localhost domain and port")
20
+ .requiredOption("-h, --host <host>", "Domain to map must be ends with localhost. Example: dev.localhost, localhost, test.localhost, etc.")
21
+ .requiredOption("-p, --port <port>", "Local port to forward to")
22
+ .action(async (options) => {
23
+ await commands_1.default.add(options);
24
+ });
25
+ program
26
+ .command("update")
27
+ .requiredOption("-h, --host <host>", "Domain to map must be ends with localhost. Example: dev.localhost, localhost, test.localhost, etc.")
28
+ .requiredOption("-p, --port <port>", "Local port to forward to")
29
+ .description("Update a domain")
30
+ .action(async (options) => await commands_1.default.update(options));
31
+ program
32
+ .command("remove")
33
+ .requiredOption("-h, --host <host>", "Host must ends with localhost. Example: dev.localhost, localhost, test.localhost, etc.")
34
+ .description("Remove a domain")
35
+ .action(async (options) => await commands_1.default.remove(options));
36
+ program
37
+ .command("host")
38
+ .description("Show all hosts")
39
+ .action(() => {
40
+ commands_1.default.getRegistry();
41
+ });
42
+ program
43
+ .command("watch:logs")
44
+ .description("Watch log files")
45
+ .action(() => {
46
+ commands_1.default.watchLogs();
47
+ });
48
+ program
49
+ .command("clear:logs")
50
+ .description("Clear logs")
51
+ .action(() => {
52
+ commands_1.default.clearLogs();
53
+ });
54
+ program
55
+ .command("clear:hosts")
56
+ .description("Clear all host file.")
57
+ .action(() => {
58
+ commands_1.default.clearHosts();
59
+ });
60
+ program
61
+ .command("path")
62
+ .description("Show configuration paths.")
63
+ .action(() => {
64
+ commands_1.default.configPath();
65
+ });
66
+ program
67
+ .command("path:logs")
68
+ .description("Show logs path file.")
69
+ .action(() => {
70
+ commands_1.default.logPath();
71
+ });
72
+ program
73
+ .command("path:hosts")
74
+ .description("Show hosts path file.")
75
+ .action(() => {
76
+ commands_1.default.hostPath();
77
+ });
78
+ program
79
+ .command("restart")
80
+ .description("Restart locadot")
81
+ .action(() => {
82
+ commands_1.default.restart();
83
+ });
84
+ program
85
+ .command("stop")
86
+ .description("Stop central proxy and logs")
87
+ .action(async () => {
88
+ await commands_1.default.stop();
89
+ logger_1.default.info(constants_1.default.proxyInfo.softClose);
90
+ process.exit(0);
91
+ });
92
+ program
93
+ .command("kill")
94
+ .description("Stop proxy, clear logs, and hosts file.")
95
+ .action(async () => {
96
+ await commands_1.default.kill();
97
+ logger_1.default.info(constants_1.default.proxyInfo.softClose);
98
+ process.exit(0);
99
+ });
100
+ program.parse(process.argv);
@@ -1,95 +1,98 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.CloudflaredTunnel = void 0;
7
- const child_process_1 = __importDefault(require("child_process"));
8
- const process_1 = __importDefault(require("process"));
9
- const command_exists_1 = require("command-exists");
10
- class CloudflaredTunnel {
11
- constructor(cloudflaredPath = "cloudflared") {
12
- this.childProcess = null;
13
- this.running = false;
14
- this.cloudflaredPath = cloudflaredPath;
15
- this.url = "http://localhost:80";
16
- this.hostname = "";
17
- }
18
- get token() {
19
- return this._token;
20
- }
21
- set token(token) {
22
- if (token && typeof token === "string") {
23
- token = token.trim();
24
- // try to strip out "cloudflared.exe service install"
25
- const array = token.split(" ");
26
- if (array.length > 1) {
27
- for (let i = 0; i < array.length - 1; i++) {
28
- if (array[i] === "install") {
29
- token = array[i + 1];
30
- }
31
- }
32
- }
33
- }
34
- this._token = token;
35
- }
36
- checkInstalled() {
37
- return (0, command_exists_1.sync)(this.cloudflaredPath);
38
- }
39
- emitChange(msg, code) {
40
- if (this.change) {
41
- this.change(this.running, msg, code);
42
- }
43
- }
44
- emitError(msg) {
45
- if (this.error) {
46
- this.error(msg);
47
- }
48
- }
49
- start() {
50
- if (this.childProcess) {
51
- this.emitError("Already started");
52
- return;
53
- }
54
- if (!this.checkInstalled()) {
55
- this.emitError(`Cloudflared error: ${this.cloudflaredPath} is not found`);
56
- return;
57
- }
58
- if (!this.token) {
59
- this.emitError("Cloudflared error: Token is not set");
60
- return;
61
- }
62
- const args = ["tunnel", "--no-autoupdate", "run", "--token", this.token];
63
- this.running = true;
64
- this.emitChange("Starting cloudflared");
65
- this.childProcess = child_process_1.default.spawn(this.cloudflaredPath, args);
66
- this.childProcess.stdout.pipe(process_1.default.stdout);
67
- this.childProcess.stderr.pipe(process_1.default.stderr);
68
- this.childProcess.on("close", (code) => {
69
- this.running = false;
70
- this.childProcess = null;
71
- this.emitChange("Stopped cloudflared", code);
72
- });
73
- this.childProcess.on("error", (err) => {
74
- if (err.code === "ENOENT") {
75
- this.emitError(`Cloudflared error: ${this.cloudflaredPath} is not found`);
76
- }
77
- else {
78
- this.emitError(err);
79
- }
80
- });
81
- this.childProcess.stderr.on("data", (data) => {
82
- this.emitError(data.toString());
83
- });
84
- }
85
- stop() {
86
- this.emitChange("Stopping cloudflared");
87
- if (this.childProcess) {
88
- this.childProcess.kill("SIGINT");
89
- this.childProcess = null;
90
- }
91
- }
92
- }
93
- exports.CloudflaredTunnel = CloudflaredTunnel;
94
- const cloudflared = new CloudflaredTunnel();
95
- exports.default = cloudflared;
2
+ // import childProcess, { ChildProcessWithoutNullStreams } from "child_process";
3
+ // import process from "process";
4
+ // import { sync as commandExistsSync } from "command-exists";
5
+ // type ChangeCallback = (running: boolean, msg: string, code?: number) => void;
6
+ // type ErrorCallback = (msg: string | Error) => void;
7
+ // export class CloudflaredTunnel {
8
+ // private cloudflaredPath: string;
9
+ // private _token?: string;
10
+ // private childProcess: ChildProcessWithoutNullStreams | null = null;
11
+ // private running = false;
12
+ // public url: string;
13
+ // public hostname: string;
14
+ // public change?: ChangeCallback;
15
+ // public error?: ErrorCallback;
16
+ // constructor(cloudflaredPath: string = "cloudflared") {
17
+ // this.cloudflaredPath = cloudflaredPath;
18
+ // this.url = "http://localhost:80";
19
+ // this.hostname = "";
20
+ // }
21
+ // get token(): string | undefined {
22
+ // return this._token;
23
+ // }
24
+ // set token(token: string | undefined) {
25
+ // if (token && typeof token === "string") {
26
+ // token = token.trim();
27
+ // // try to strip out "cloudflared.exe service install"
28
+ // const array = token.split(" ");
29
+ // if (array.length > 1) {
30
+ // for (let i = 0; i < array.length - 1; i++) {
31
+ // if (array[i] === "install") {
32
+ // token = array[i + 1];
33
+ // }
34
+ // }
35
+ // }
36
+ // }
37
+ // this._token = token;
38
+ // }
39
+ // checkInstalled(): boolean {
40
+ // return commandExistsSync(this.cloudflaredPath);
41
+ // }
42
+ // private emitChange(msg: string, code?: number): void {
43
+ // if (this.change) {
44
+ // this.change(this.running, msg, code);
45
+ // }
46
+ // }
47
+ // private emitError(msg: string | Error): void {
48
+ // if (this.error) {
49
+ // this.error(msg);
50
+ // }
51
+ // }
52
+ // start(): void {
53
+ // if (this.childProcess) {
54
+ // this.emitError("Already started");
55
+ // return;
56
+ // }
57
+ // if (!this.checkInstalled()) {
58
+ // this.emitError(`Cloudflared error: ${this.cloudflaredPath} is not found`);
59
+ // return;
60
+ // }
61
+ // if (!this.token) {
62
+ // this.emitError("Cloudflared error: Token is not set");
63
+ // return;
64
+ // }
65
+ // const args = ["tunnel", "--no-autoupdate", "run", "--token", this.token];
66
+ // this.running = true;
67
+ // this.emitChange("Starting cloudflared");
68
+ // this.childProcess = childProcess.spawn(this.cloudflaredPath, args);
69
+ // this.childProcess.stdout.pipe(process.stdout);
70
+ // this.childProcess.stderr.pipe(process.stderr);
71
+ // this.childProcess.on("close", (code: number) => {
72
+ // this.running = false;
73
+ // this.childProcess = null;
74
+ // this.emitChange("Stopped cloudflared", code);
75
+ // });
76
+ // this.childProcess.on("error", (err: NodeJS.ErrnoException) => {
77
+ // if (err.code === "ENOENT") {
78
+ // this.emitError(
79
+ // `Cloudflared error: ${this.cloudflaredPath} is not found`
80
+ // );
81
+ // } else {
82
+ // this.emitError(err);
83
+ // }
84
+ // });
85
+ // this.childProcess.stderr.on("data", (data: Buffer) => {
86
+ // this.emitError(data.toString());
87
+ // });
88
+ // }
89
+ // stop(): void {
90
+ // this.emitChange("Stopping cloudflared");
91
+ // if (this.childProcess) {
92
+ // this.childProcess.kill("SIGINT");
93
+ // this.childProcess = null;
94
+ // }
95
+ // }
96
+ // }
97
+ // const cloudflared = new CloudflaredTunnel();
98
+ // export default cloudflared;