locadot 1.4.0 → 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.
@@ -0,0 +1,182 @@
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 fs_1 = __importDefault(require("fs"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const chokidar_1 = __importDefault(require("chokidar"));
9
+ const logger_1 = __importDefault(require("./logger"));
10
+ const constants_1 = __importDefault(require("../constants"));
11
+ class FileModule {
12
+ /**
13
+ * Watches a file: creates folder and file if they do not exist, and listens to changes.
14
+ * @param filePath - Path to the file (relative or absolute)
15
+ * @param onChange - Callback to execute on file change
16
+ * @returns Chokidar watcher instance
17
+ */
18
+ static watchFileWithInit(filePath, onChange) {
19
+ const resolvedPath = path_1.default.resolve(constants_1.default.paths[filePath]);
20
+ const folderPath = path_1.default.dirname(resolvedPath);
21
+ // Ensure folder exists
22
+ if (!fs_1.default.existsSync(folderPath)) {
23
+ fs_1.default.mkdirSync(folderPath, { recursive: true });
24
+ // logger.info(`Created folder: ${folderPath}`);
25
+ }
26
+ // Ensure file exists
27
+ if (!fs_1.default.existsSync(resolvedPath)) {
28
+ fs_1.default.writeFileSync(resolvedPath, "", "utf8");
29
+ // logger.info(`Created file: ${resolvedPath}`);
30
+ }
31
+ // Watch the file
32
+ const watcher = chokidar_1.default.watch(resolvedPath, {
33
+ persistent: true,
34
+ ignoreInitial: true,
35
+ awaitWriteFinish: true,
36
+ });
37
+ watcher
38
+ .on("change", (changedPath) => {
39
+ try {
40
+ if (!fs_1.default.existsSync(resolvedPath)) {
41
+ console.log(`\n[Info] File ${resolvedPath} no longer exists. Stopping watch.`);
42
+ if (watcher)
43
+ watcher.close();
44
+ return;
45
+ }
46
+ onChange();
47
+ }
48
+ catch (error) {
49
+ logger_1.default.error(error);
50
+ }
51
+ })
52
+ .on("error", (error) => {
53
+ console.error("Watcher error:", error);
54
+ watcher.close();
55
+ });
56
+ return watcher;
57
+ }
58
+ static writeFileStream(filePath, stream) {
59
+ const resolvedPath = path_1.default.resolve(constants_1.default.paths[filePath]);
60
+ const folderPath = path_1.default.dirname(resolvedPath);
61
+ // Ensure folder exists
62
+ if (!fs_1.default.existsSync(folderPath)) {
63
+ fs_1.default.mkdirSync(folderPath, { recursive: true });
64
+ // logger.info(`Created folder: ${folderPath}`);
65
+ }
66
+ // Ensure file exists
67
+ if (!fs_1.default.existsSync(resolvedPath)) {
68
+ fs_1.default.writeFileSync(resolvedPath, "", "utf8");
69
+ // logger.info(`Created file: ${resolvedPath}`);
70
+ }
71
+ return fs_1.default.createWriteStream(resolvedPath, stream ? { flags: "a" } : {});
72
+ }
73
+ static async writeFileSync(filePath, data) {
74
+ const resolvedPath = path_1.default.resolve(constants_1.default.paths[filePath]);
75
+ const folderPath = path_1.default.dirname(resolvedPath);
76
+ // Ensure folder exists
77
+ if (!fs_1.default.existsSync(folderPath)) {
78
+ fs_1.default.mkdirSync(folderPath, { recursive: true });
79
+ logger_1.default.info(`Created folder: ${folderPath}`);
80
+ }
81
+ return fs_1.default.writeFileSync(resolvedPath, data, "utf8");
82
+ }
83
+ static async readFileSync(filePath, defaultValue = "") {
84
+ const resolvedPath = path_1.default.resolve(constants_1.default.paths[filePath]);
85
+ const folderPath = path_1.default.dirname(resolvedPath);
86
+ // Ensure folder exists
87
+ if (!fs_1.default.existsSync(folderPath)) {
88
+ fs_1.default.mkdirSync(folderPath, { recursive: true });
89
+ // logger.info(`Created folder: ${folderPath}`);
90
+ }
91
+ if (!fs_1.default.existsSync(resolvedPath)) {
92
+ fs_1.default.writeFileSync(resolvedPath, defaultValue || "", "utf8");
93
+ // logger.info(`Created file: ${resolvedPath}`);
94
+ }
95
+ return fs_1.default.readFileSync(resolvedPath, "utf8");
96
+ }
97
+ static async removeFileSync(filePath) {
98
+ const resolvedPath = path_1.default.resolve(constants_1.default.paths[filePath]);
99
+ const folderPath = path_1.default.dirname(resolvedPath);
100
+ if (!fs_1.default.existsSync(folderPath)) {
101
+ return;
102
+ }
103
+ if (!fs_1.default.existsSync(resolvedPath)) {
104
+ return;
105
+ }
106
+ fs_1.default.rmSync(resolvedPath, { force: true, recursive: true });
107
+ }
108
+ static async tailFile(filePathKey, maxLines = 10) {
109
+ const resolvedPath = path_1.default.resolve(constants_1.default.paths[filePathKey]);
110
+ try {
111
+ const initialContent = await this.readFileSync(filePathKey);
112
+ const lines = initialContent.trim().split(/\r?\n/);
113
+ const nonEmptyLines = lines.filter((line) => line.length > 0);
114
+ if (nonEmptyLines.length > 0) {
115
+ const lastNLines = nonEmptyLines.slice(-Math.abs(maxLines)).join("\n");
116
+ if (lastNLines) {
117
+ process.stdout.write(lastNLines + "\n");
118
+ }
119
+ }
120
+ }
121
+ catch (err) {
122
+ console.error(`[Error] Reading initial content from ${resolvedPath}:`, err);
123
+ }
124
+ let lastKnownSize = 0;
125
+ try {
126
+ lastKnownSize = fs_1.default.statSync(resolvedPath).size;
127
+ }
128
+ catch (err) {
129
+ console.error(`[Error] Getting initial size of ${resolvedPath}. Assuming 0. Error:`, err);
130
+ }
131
+ let watcher = null;
132
+ try {
133
+ watcher = this.watchFileWithInit(filePathKey, () => {
134
+ if (!watcher)
135
+ return;
136
+ try {
137
+ const stats = fs_1.default.statSync(resolvedPath);
138
+ const currentSize = stats.size;
139
+ if (currentSize > lastKnownSize) {
140
+ const stream = fs_1.default.createReadStream(resolvedPath, {
141
+ start: lastKnownSize,
142
+ end: currentSize - 1, // end is inclusive for createReadStream
143
+ encoding: "utf8",
144
+ });
145
+ stream.on("data", (chunk) => {
146
+ process.stdout.write(chunk);
147
+ });
148
+ stream.on("error", (readErr) => {
149
+ console.error(`[Error] Reading new content from ${resolvedPath}:`, readErr);
150
+ });
151
+ lastKnownSize = currentSize;
152
+ }
153
+ else if (currentSize < lastKnownSize) {
154
+ process.stdout.write(`\n[Info] --- File ${resolvedPath} truncated or replaced. Tailing from new end. ---\n`);
155
+ lastKnownSize = currentSize;
156
+ }
157
+ }
158
+ catch (err) {
159
+ console.error(`[Error] Processing file change for ${resolvedPath}:`, err);
160
+ }
161
+ });
162
+ const cleanup = (err) => {
163
+ console.error(`Tailing file exiting with error: ${err}`);
164
+ watcher?.close();
165
+ process.exit(0);
166
+ };
167
+ process.on("exit", () => cleanup("exit"));
168
+ process.on("SIGINT", () => cleanup("stop"));
169
+ process.on("SIGTERM", () => cleanup("stop"));
170
+ process.on("uncaughtException", () => cleanup("uncaughtException"));
171
+ return {
172
+ stop: () => {
173
+ cleanup("stop");
174
+ },
175
+ };
176
+ }
177
+ catch (watchSetupError) {
178
+ console.error(`[Error] Failed to setup watcher for ${resolvedPath}:`, watchSetupError);
179
+ }
180
+ }
181
+ }
182
+ exports.default = FileModule;
@@ -0,0 +1,16 @@
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 winston_1 = require("winston");
7
+ const constants_1 = __importDefault(require("../constants"));
8
+ const logger = (0, winston_1.createLogger)({
9
+ level: "info",
10
+ format: winston_1.format.combine(winston_1.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), winston_1.format.printf(({ timestamp, level, message }) => `${timestamp} [${level}]: ${message}`)),
11
+ transports: [
12
+ new winston_1.transports.Console(),
13
+ new winston_1.transports.File({ filename: constants_1.default.paths.LOGS }),
14
+ ],
15
+ });
16
+ exports.default = logger;
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "locadot",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Secure your local development environment with HTTPS and custom domains like dev.localhost.",
5
5
  "homepage": "https://www.npmjs.com/package/locadot",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
8
  "locadot": "./dist/index.js"
9
9
  },
10
+ "scripts": {
11
+ "dev": "tsx --watch src/index.ts",
12
+ "build": "tsc"
13
+ },
10
14
  "repository": {
11
15
  "type": "git",
12
16
  "url": "git+https://github.com/avinashid/locadot.git"
@@ -28,19 +32,15 @@
28
32
  "@types/http-proxy": "^1.17.16",
29
33
  "@types/yargs": "^17.0.33",
30
34
  "appdata-path": "^1.0.0",
31
- "date-fns": "^4.1.0",
32
- "detect-port": "^2.1.0",
35
+ "chokidar": "^4.0.3",
36
+ "commander": "^14.0.0",
33
37
  "http-proxy": "^1.18.1",
34
38
  "https": "^1.0.0",
35
39
  "mkcert": "^3.2.0",
36
- "yargs": "^17.7.2"
40
+ "winston": "^3.17.0"
37
41
  },
38
42
  "devDependencies": {
39
43
  "tsx": "^4.19.3",
40
44
  "typescript": "^5.8.3"
41
- },
42
- "scripts": {
43
- "dev": "tsx --watch src/index.ts",
44
- "build": "tsc"
45
45
  }
46
- }
46
+ }