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.
@@ -4,37 +4,74 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const localhost_1 = __importDefault(require("./localhost"));
7
- const constants_1 = require("../utils/constants");
8
- const server_1 = __importDefault(require("../server"));
7
+ const proxy_1 = __importDefault(require("../proxy"));
9
8
  const locadot_file_1 = __importDefault(require("./locadot-file"));
9
+ const constants_1 = __importDefault(require("../constants"));
10
10
  class Commands {
11
- static async start(argv) {
11
+ static async add(argv) {
12
12
  if (!localhost_1.default.isValidLocalhostDomain(argv.host)) {
13
- console.error(constants_1.errorConstants.invalidHost);
13
+ console.error(constants_1.default.proxyInfo.invalidHost);
14
14
  process.exit(1);
15
15
  }
16
16
  if (await localhost_1.default.isLocalhostOpen(argv.host, argv.port)) {
17
- console.error(constants_1.errorConstants.hostExist);
17
+ console.error(constants_1.default.proxyInfo.hostExist);
18
+ process.exit(1);
18
19
  }
19
20
  try {
20
- await server_1.default.registerDomain(argv.host, argv.port);
21
+ await proxy_1.default.addProxy(argv.host, argv.port);
22
+ }
23
+ catch (error) {
24
+ console.error(error);
25
+ }
26
+ }
27
+ static async remove(argv) {
28
+ if (!localhost_1.default.isValidLocalhostDomain(argv.host)) {
29
+ console.error(constants_1.default.proxyInfo.invalidHost);
30
+ process.exit(1);
31
+ }
32
+ try {
33
+ await proxy_1.default.removeProxy(argv.host);
34
+ }
35
+ catch (error) {
36
+ console.error(error);
37
+ }
38
+ }
39
+ static async update(argv) {
40
+ if (!localhost_1.default.isValidLocalhostDomain(argv.host)) {
41
+ console.error(constants_1.default.proxyInfo.invalidHost);
42
+ process.exit(1);
43
+ }
44
+ if (!(await localhost_1.default.isLocalhostOpen(argv.host, argv.port))) {
45
+ console.error(constants_1.default.proxyInfo.hostNotFound);
46
+ process.exit(1);
47
+ }
48
+ try {
49
+ await proxy_1.default.updateProxy(argv.host, argv.port);
50
+ }
51
+ catch (error) {
52
+ console.error(error);
21
53
  }
22
- catch (error) { }
23
54
  }
24
55
  static async stop() {
25
56
  try {
26
- await server_1.default.stopProxy();
57
+ await proxy_1.default.stopProxy();
58
+ }
59
+ catch (error) { }
60
+ }
61
+ static async clearHosts() {
62
+ try {
63
+ await locadot_file_1.default.removeAllRegistry();
27
64
  }
28
65
  catch (error) { }
29
66
  }
30
67
  static async kill() {
31
68
  try {
32
- await server_1.default.killProxy();
69
+ await proxy_1.default.killProxy();
33
70
  }
34
71
  catch (error) { }
35
72
  }
36
73
  static async restart() {
37
- await server_1.default.restartProxy();
74
+ await proxy_1.default.restartProxy();
38
75
  console.log("☑️ Proxy successfully restarted.");
39
76
  }
40
77
  static async getRegistry() {
@@ -47,7 +84,6 @@ class Commands {
47
84
  }
48
85
  static watchLogs() {
49
86
  try {
50
- console.log("☑️ Watching logs files.");
51
87
  locadot_file_1.default.watchLogs();
52
88
  }
53
89
  catch (error) { }
@@ -60,7 +96,14 @@ class Commands {
60
96
  catch (error) { }
61
97
  }
62
98
  static async logPath() {
63
- console.log(constants_1.locadotPath.LOGS);
99
+ console.log(constants_1.default.paths.LOGS);
100
+ }
101
+ static async hostPath() {
102
+ console.log(constants_1.default.paths.REGISTRY_FILE);
103
+ }
104
+ static async configPath() {
105
+ console.log(constants_1.default.paths.REGISTRY_FILE);
106
+ console.log(constants_1.default.paths.LOGS);
64
107
  }
65
108
  }
66
109
  exports.default = Commands;
@@ -0,0 +1,64 @@
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 template_1 = require("../constants/template");
7
+ const logger_1 = __importDefault(require("../utils/logger"));
8
+ class HttpModule {
9
+ static requestHandler(req, res, proxy, domainMap) {
10
+ try {
11
+ const host = req.headers.host?.split(":")[0];
12
+ const targetPort = domainMap[host];
13
+ if (!targetPort) {
14
+ res.writeHead(502, { "Content-Type": "text/html" });
15
+ res.end((0, template_1.proxyNotFound)(host));
16
+ }
17
+ proxy.web(req, res, {
18
+ target: `http://localhost:${targetPort}`,
19
+ changeOrigin: true,
20
+ headers: {
21
+ "X-Original-Host": host || "localhost",
22
+ },
23
+ }, (err) => {
24
+ logger_1.default.warn(host || "", "warn", `${err.name}=> ${err.message}`);
25
+ res.writeHead(502);
26
+ res.end("Connection failed. Host not found.");
27
+ });
28
+ }
29
+ catch (error) {
30
+ logger_1.default.error(error);
31
+ }
32
+ }
33
+ }
34
+ HttpModule.requestUpgrade = (req, socket, head, proxy, domainMap) => {
35
+ try {
36
+ const host = req.headers.host?.split(":")[0];
37
+ const targetPort = domainMap[host];
38
+ if (!targetPort) {
39
+ socket.end();
40
+ return;
41
+ }
42
+ logger_1.default.info(host || "", "log", `WebSocket upgrade request for ${host}`);
43
+ proxy.ws(req, socket, head, {
44
+ target: `ws://localhost:${targetPort}`,
45
+ ws: true,
46
+ changeOrigin: true,
47
+ headers: {
48
+ host: `localhost:${targetPort}`,
49
+ "X-Original-Host": host || "localhost",
50
+ },
51
+ }, (err) => {
52
+ // locadotFile.updateLogs(
53
+ // host || "",
54
+ // "warn",
55
+ // `WebSocket Error: ${err.name}=> ${err.message}`
56
+ // );
57
+ socket.end();
58
+ });
59
+ }
60
+ catch (error) {
61
+ logger_1.default.error(error);
62
+ }
63
+ };
64
+ exports.default = HttpModule;
@@ -3,110 +3,92 @@ 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 constants_1 = require("../utils/constants");
7
- const fs_1 = __importDefault(require("fs"));
8
- const date_fns_1 = require("date-fns");
6
+ const file_1 = __importDefault(require("../utils/file"));
7
+ const logger_1 = __importDefault(require("../utils/logger"));
8
+ const path_1 = __importDefault(require("path"));
9
9
  class locadotFile {
10
10
  static async createLockFile(processId) {
11
- fs_1.default.writeFileSync(constants_1.locadotPath.LOCK_FILE, processId);
11
+ await file_1.default.writeFileSync("LOCK_FILE", processId);
12
12
  }
13
13
  static async getProcessId() {
14
14
  try {
15
- if (fs_1.default.existsSync(constants_1.locadotPath.LOCK_FILE)) {
16
- const pid = parseInt(fs_1.default.readFileSync(constants_1.locadotPath.LOCK_FILE, "utf-8"));
17
- return pid.toString();
18
- }
15
+ const lockFile = await file_1.default.readFileSync("LOCK_FILE");
16
+ return parseInt(lockFile).toString();
19
17
  }
20
18
  catch (err) {
19
+ await file_1.default.removeFileSync("LOCK_FILE");
21
20
  return;
22
21
  }
23
22
  }
24
23
  static async deleteLockFile() {
25
- fs_1.default.rmSync(constants_1.locadotPath.LOCK_FILE);
24
+ await file_1.default.removeFileSync("LOCK_FILE");
26
25
  }
27
26
  static async getRegistry() {
28
- if (!fs_1.default.existsSync(constants_1.locadotPath.REGISTRY_FILE)) {
29
- fs_1.default.writeFileSync(constants_1.locadotPath.REGISTRY_FILE, "{}");
27
+ try {
28
+ return JSON.parse(await file_1.default.readFileSync("REGISTRY_FILE"));
29
+ }
30
+ catch (error) {
31
+ logger_1.default.error(error);
32
+ return {};
30
33
  }
31
- return JSON.parse(fs_1.default.readFileSync(constants_1.locadotPath.REGISTRY_FILE, "utf-8"));
32
34
  }
33
35
  static async addRegistry(domain, port) {
34
36
  const registry = await locadotFile.getRegistry();
35
37
  registry[domain] = port;
36
- fs_1.default.writeFileSync(constants_1.locadotPath.REGISTRY_FILE, JSON.stringify(registry, null, 2));
38
+ file_1.default.writeFileSync("REGISTRY_FILE", JSON.stringify(registry));
37
39
  }
38
40
  static async removeAllRegistry() {
39
- fs_1.default.writeFileSync(constants_1.locadotPath.REGISTRY_FILE, "{}");
41
+ file_1.default.writeFileSync("REGISTRY_FILE", "{}");
40
42
  }
41
43
  static async updateRegistry(domain, port) {
42
44
  const registry = await locadotFile.getRegistry();
43
45
  registry[domain] = port;
44
- fs_1.default.writeFileSync(constants_1.locadotPath.REGISTRY_FILE, JSON.stringify(registry, null, 2));
46
+ file_1.default.writeFileSync("REGISTRY_FILE", JSON.stringify(registry));
45
47
  }
46
48
  static async deleteRegistry(domain) {
47
49
  const registry = await locadotFile.getRegistry();
48
50
  delete registry[domain];
49
- fs_1.default.writeFileSync(constants_1.locadotPath.REGISTRY_FILE, JSON.stringify(registry, null, 2));
51
+ file_1.default.writeFileSync("REGISTRY_FILE", JSON.stringify(registry));
50
52
  }
51
53
  static async watchRegistry(callBackOnChange) {
52
- return fs_1.default.watch(constants_1.locadotPath.REGISTRY_FILE, async (eventType) => {
53
- if (eventType === "change") {
54
- this.updateLogs("🔄 Updated domain mappings.");
55
- callBackOnChange && callBackOnChange();
56
- }
57
- });
54
+ return file_1.default.watchFileWithInit("REGISTRY_FILE", () => callBackOnChange?.());
58
55
  }
59
56
  static async getLogs() {
60
- if (!fs_1.default.existsSync(constants_1.locadotPath.LOGS)) {
61
- fs_1.default.writeFileSync(constants_1.locadotPath.LOGS, "{}");
57
+ try {
58
+ return await file_1.default.readFileSync("LOGS");
62
59
  }
63
- return JSON.parse(fs_1.default.readFileSync(constants_1.locadotPath.LOGS, "utf-8"));
64
- }
65
- static async updateLogs(message, status = "log", description) {
66
- const logs = (await locadotFile.getLogs()).logs || [];
67
- if (!Array.isArray(logs)) {
68
- fs_1.default.writeFileSync(constants_1.locadotPath.LOGS, "{}");
60
+ catch (error) {
61
+ file_1.default.removeFileSync("LOGS");
62
+ return "";
69
63
  }
70
- logs.push({
71
- message,
72
- timestamp: Date.now(),
73
- status: status,
74
- description,
75
- });
76
- fs_1.default.writeFileSync(constants_1.locadotPath.LOGS, JSON.stringify({ logs: logs }));
77
64
  }
78
65
  static async clearLogs() {
79
- fs_1.default.writeFileSync(constants_1.locadotPath.LOGS, "{}");
80
- }
81
- static async printLogs(log) {
82
- console[log.status || "log"](`${(0, date_fns_1.format)(log.timestamp, "yyyy-MM-dd HH:mm:ss")}: ${log.message} ${log.description ? "==> " : ""}${log.description ? log.description : ""}\n`);
66
+ file_1.default.writeFileSync("LOGS", "");
83
67
  }
84
68
  static async watchLogs() {
85
- const logs = await locadotFile.getLogs();
86
- let length = logs.logs?.length || 0;
87
- logs.logs?.forEach((log) => this.printLogs(log));
88
- fs_1.default.watch(constants_1.locadotPath.LOGS, async (eventType) => {
89
- try {
90
- if (eventType === "change") {
91
- const newLog = await locadotFile.getLogs();
92
- newLog.logs?.forEach((log, i) => {
93
- if (i > length - 1) {
94
- this.printLogs(log);
95
- }
96
- });
97
- length = newLog.logs?.length || 0;
98
- }
99
- }
100
- catch (error) { }
101
- });
69
+ file_1.default.tailFile("LOGS");
70
+ }
71
+ static getStartProxyFile() {
72
+ if (process.env.NODE_ENV === "production") {
73
+ const filePath = path_1.default.join(process.cwd(), "core.js");
74
+ return {
75
+ command: "node",
76
+ path: [filePath],
77
+ };
78
+ }
79
+ const filePath = path_1.default.join(process.cwd(), "dist", "core.js");
80
+ return {
81
+ command: "node",
82
+ path: [filePath],
83
+ };
102
84
  }
103
85
  static async destroy(watcher) {
104
86
  try {
105
87
  const pid = await locadotFile.getProcessId();
106
- locadotFile.deleteLockFile();
107
- locadotFile.removeAllRegistry();
108
- locadotFile.clearLogs();
109
- watcher?.close();
88
+ await locadotFile.deleteLockFile();
89
+ await locadotFile.removeAllRegistry();
90
+ await locadotFile.clearLogs();
91
+ await watcher?.close();
110
92
  if (pid) {
111
93
  process.kill(parseInt(pid));
112
94
  }
@@ -116,14 +98,16 @@ class locadotFile {
116
98
  static async softDestroy(watcher) {
117
99
  try {
118
100
  const pid = await locadotFile.getProcessId();
119
- locadotFile.deleteLockFile();
120
- locadotFile.clearLogs();
121
- watcher?.close();
101
+ await locadotFile.deleteLockFile();
102
+ await locadotFile.clearLogs();
103
+ await watcher?.close();
122
104
  if (pid) {
123
105
  process.kill(parseInt(pid));
124
106
  }
125
107
  }
126
- catch (error) { }
108
+ catch (error) {
109
+ logger_1.default.error(error);
110
+ }
127
111
  }
128
112
  }
129
113
  exports.default = locadotFile;
package/dist/proxy.js ADDED
@@ -0,0 +1,139 @@
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 http_proxy_1 = __importDefault(require("http-proxy"));
7
+ const certs_1 = require("./utils/certs");
8
+ const https_1 = __importDefault(require("https"));
9
+ const http_1 = __importDefault(require("http"));
10
+ const locadot_file_1 = __importDefault(require("./lib/locadot-file"));
11
+ const child_process_1 = require("child_process");
12
+ const file_1 = __importDefault(require("./utils/file"));
13
+ const logger_1 = __importDefault(require("./utils/logger"));
14
+ const http_2 = __importDefault(require("./lib/http"));
15
+ class ProxyHandler {
16
+ async startCentralProxy() {
17
+ try {
18
+ let domainMap = await locadot_file_1.default.getRegistry();
19
+ const proxy = http_proxy_1.default.createProxyServer({});
20
+ const defaultCert = await (0, certs_1.createSSL)("localhost");
21
+ const watcher = await locadot_file_1.default.watchRegistry(async () => {
22
+ logger_1.default.info("🔄 Updated domain mapping");
23
+ domainMap = await locadot_file_1.default.getRegistry();
24
+ });
25
+ process.on("SIGINT", async (err) => {
26
+ logger_1.default.error("🛑 Proxy stopped. Proxy soft destroyed as process SIGINT", err);
27
+ await locadot_file_1.default.softDestroy(watcher);
28
+ });
29
+ process.on("SIGTERM", async (err) => {
30
+ logger_1.default.error("🛑 Proxy stopped. Proxy soft destroyed as process SIGTERM", err);
31
+ await locadot_file_1.default.softDestroy(watcher);
32
+ });
33
+ process.on("exit", (code, signal) => {
34
+ logger_1.default.error(`Process exited with error ${code} and signal ${signal}`);
35
+ locadot_file_1.default.softDestroy(watcher);
36
+ });
37
+ const httpsServer = https_1.default.createServer(defaultCert, (req, res) => {
38
+ http_2.default.requestHandler(req, res, proxy, domainMap);
39
+ });
40
+ const httpServer = http_1.default.createServer((req, res) => {
41
+ http_2.default.requestHandler(req, res, proxy, domainMap);
42
+ });
43
+ httpsServer.listen(443, () => {
44
+ logger_1.default.info("🛜 HTTPS proxy running on port 443");
45
+ });
46
+ httpsServer.on("upgrade", (req, res, head) => {
47
+ http_2.default.requestUpgrade(req, res, head, proxy, domainMap);
48
+ });
49
+ httpServer.listen(80, () => {
50
+ logger_1.default.info("🛜 HTTP proxy running on port 80");
51
+ });
52
+ httpServer.on("upgrade", (req, socket, head) => {
53
+ http_2.default.requestUpgrade(req, socket, head, proxy, domainMap);
54
+ });
55
+ }
56
+ catch (error) {
57
+ logger_1.default.error("Failed to start central proxy", error);
58
+ }
59
+ }
60
+ static async isProxyRunning() {
61
+ try {
62
+ const pid = Number(await locadot_file_1.default.getProcessId());
63
+ if (!pid || isNaN(pid)) {
64
+ return false;
65
+ }
66
+ process.kill(pid, 0);
67
+ return true;
68
+ }
69
+ catch (error) {
70
+ return false;
71
+ }
72
+ }
73
+ async startProxy() {
74
+ try {
75
+ if (await ProxyHandler.isProxyRunning()) {
76
+ logger_1.default.error("Proxy is already running");
77
+ return;
78
+ }
79
+ const command = locadot_file_1.default.getStartProxyFile();
80
+ const proxyProcess = (0, child_process_1.spawn)(command.command, command.path, {
81
+ detached: true,
82
+ stdio: ["ignore", "ignore", "pipe"],
83
+ });
84
+ const logStream = file_1.default.writeFileStream("LOGS", true);
85
+ proxyProcess.stderr.pipe(logStream);
86
+ proxyProcess.on("error", (err) => {
87
+ console.error("Failed to start child process:", err);
88
+ });
89
+ if (!proxyProcess.pid) {
90
+ logger_1.default.error("❌ Central proxy failed to start");
91
+ process.exit(1);
92
+ }
93
+ else {
94
+ locadot_file_1.default.createLockFile(proxyProcess.pid?.toString());
95
+ }
96
+ proxyProcess.unref();
97
+ logger_1.default.info("🚀 Central proxy started in background.");
98
+ }
99
+ catch (error) {
100
+ logger_1.default.error("Failed to start central proxy", error);
101
+ }
102
+ }
103
+ async addProxy(domain, port) {
104
+ if (!(await ProxyHandler.isProxyRunning())) {
105
+ await this.startProxy();
106
+ }
107
+ let registry = await locadot_file_1.default.getRegistry();
108
+ if (registry[domain]) {
109
+ console.error(`❌ ${domain} already mapped to port ${registry[domain]} use update instead.`);
110
+ process.exit(1);
111
+ }
112
+ await locadot_file_1.default.addRegistry(domain, port);
113
+ logger_1.default.info(`✅ ${domain} => http://localhost:${port}`);
114
+ }
115
+ async removeProxy(domain) {
116
+ if (!(await ProxyHandler.isProxyRunning())) {
117
+ await this.startProxy();
118
+ }
119
+ await locadot_file_1.default.deleteRegistry(domain);
120
+ }
121
+ async updateProxy(domain, port) {
122
+ if (!(await ProxyHandler.isProxyRunning())) {
123
+ await this.startProxy();
124
+ }
125
+ await locadot_file_1.default.updateRegistry(domain, port);
126
+ }
127
+ async stopProxy() {
128
+ await locadot_file_1.default.softDestroy();
129
+ }
130
+ async killProxy() {
131
+ await locadot_file_1.default.destroy();
132
+ }
133
+ async restartProxy() {
134
+ await locadot_file_1.default.softDestroy();
135
+ await this.startProxy();
136
+ }
137
+ }
138
+ const locadotProxy = new ProxyHandler();
139
+ exports.default = locadotProxy;