@envin/cli 1.1.12 → 1.1.13

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/cli/index.mjs +532 -849
  3. package/dist/preview/.next/BUILD_ID +1 -1
  4. package/dist/preview/.next/build-manifest.json +2 -2
  5. package/dist/preview/.next/fallback-build-manifest.json +2 -2
  6. package/dist/preview/.next/prerender-manifest.json +3 -3
  7. package/dist/preview/.next/server/app/_global-error.html +2 -2
  8. package/dist/preview/.next/server/app/_global-error.rsc +1 -1
  9. package/dist/preview/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  10. package/dist/preview/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/dist/preview/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/dist/preview/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/dist/preview/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/dist/preview/.next/server/app/_not-found.html +1 -1
  15. package/dist/preview/.next/server/app/_not-found.rsc +1 -1
  16. package/dist/preview/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  17. package/dist/preview/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  18. package/dist/preview/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  19. package/dist/preview/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  20. package/dist/preview/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  21. package/dist/preview/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  22. package/dist/preview/.next/server/app/page/server-reference-manifest.json +4 -4
  23. package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -1
  24. package/dist/preview/.next/server/chunks/ssr/[root-of-the-server]__3aaf07ce._.js +1 -1
  25. package/dist/preview/.next/server/chunks/ssr/[root-of-the-server]__3aaf07ce._.js.map +1 -1
  26. package/dist/preview/.next/server/chunks/ssr/[root-of-the-server]__e2e728e5._.js +1 -1
  27. package/dist/preview/.next/server/chunks/ssr/[root-of-the-server]__e2e728e5._.js.map +1 -1
  28. package/dist/preview/.next/server/chunks/ssr/[root-of-the-server]__e3d1c002._.js +3 -3
  29. package/dist/preview/.next/server/chunks/ssr/[root-of-the-server]__e3d1c002._.js.map +1 -1
  30. package/dist/preview/.next/server/pages/404.html +1 -1
  31. package/dist/preview/.next/server/pages/500.html +2 -2
  32. package/dist/preview/.next/server/server-reference-manifest.js +1 -1
  33. package/dist/preview/.next/server/server-reference-manifest.json +5 -5
  34. package/dist/preview/.next/static/chunks/{9bd1b84742da96a1.js → a933bffba6c37967.js} +1 -1
  35. package/dist/preview/.next/trace +1 -1
  36. package/dist/preview/.next/trace-build +1 -1
  37. package/package.json +6 -6
  38. package/tsdown.config.ts +9 -0
  39. /package/dist/preview/.next/static/{y_m2KZXoqJPNnkobTFvMs → 2pe0g3qnZD70MXuT6-2Ym}/_buildManifest.js +0 -0
  40. /package/dist/preview/.next/static/{y_m2KZXoqJPNnkobTFvMs → 2pe0g3qnZD70MXuT6-2Ym}/_clientMiddlewareManifest.json +0 -0
  41. /package/dist/preview/.next/static/{y_m2KZXoqJPNnkobTFvMs → 2pe0g3qnZD70MXuT6-2Ym}/_ssgManifest.js +0 -0
@@ -1,894 +1,577 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/cli/index.ts
4
2
  import { program } from "commander";
5
-
6
- // package.json
7
- var package_default = {
8
- name: "@envin/cli",
9
- version: "1.1.12",
10
- description: "Type-safe env validation with live previews",
11
- keywords: [
12
- "turbostarter",
13
- "environment variables",
14
- "validation",
15
- "zod",
16
- "arktype",
17
- "valibot"
18
- ],
19
- homepage: "https://envin.turbostarter.dev",
20
- bugs: {
21
- url: "https://github.com/turbostarter/envin/issues"
22
- },
23
- repository: {
24
- type: "git",
25
- url: "git+https://github.com/turbostarter/envin.git",
26
- directory: "packages/cli"
27
- },
28
- license: "MIT",
29
- author: "Bartosz Zagrodzki",
30
- bin: {
31
- envin: "dist/cli/index.mjs"
32
- },
33
- scripts: {
34
- build: "tsup-node && bun run build:preview",
35
- "build:preview": "node ./scripts/build-preview-server.mjs",
36
- clean: "rm -rf dist .turbo node_modules .next",
37
- dev: "tsup-node --watch",
38
- "dev:preview": "cd ../../apps/example && tsx ../../packages/cli/src/cli/index.ts dev",
39
- start: "node dist/cli/index.mjs",
40
- typecheck: "tsc --noEmit",
41
- prepack: "bun ../../scripts/replace-workspace-protocol.ts && bun ../../scripts/populate-readme.ts"
42
- },
43
- dependencies: {
44
- "@babel/parser": "^7.27.0",
45
- "@babel/traverse": "^7.27.0",
46
- "@hookform/resolvers": "^5.2.1",
47
- "@radix-ui/react-slot": "1.2.4",
48
- "radix-ui": "catalog:",
49
- "@svgr/webpack": "^8.1.0",
50
- chalk: "^5.4.1",
51
- chokidar: "^4.0.3",
52
- commander: "^13.1.0",
53
- consola: "^3.4.2",
54
- debounce: "^2.2.0",
55
- dotenv: "^16.5.0",
56
- envin: "workspace:*",
57
- esbuild: "^0.25.10",
58
- "log-symbols": "^7.0.0",
59
- "mime-types": "^3.0.1",
60
- next: "catalog:",
61
- ora: "^8.2.0",
62
- "react-hook-form": "^7.62.0",
63
- "socket.io": "^4.8.1",
64
- "socket.io-client": "^4.8.1",
65
- "tsconfig-paths": "^4.2.0",
66
- zod: "catalog:"
67
- },
68
- devDependencies: {
69
- "@babel/core": "7.26.10",
70
- "@swc/core": "1.11.21",
71
- "@tailwindcss/postcss": "catalog:",
72
- "@types/babel__core": "7.20.5",
73
- "@types/babel__traverse": "7.20.7",
74
- "@types/mime-types": "2.1.4",
75
- "@types/node": "catalog:",
76
- "@types/react": "catalog:",
77
- "@types/react-dom": "catalog:",
78
- "class-variance-authority": "catalog:",
79
- clsx: "catalog:",
80
- "lucide-react": "catalog:",
81
- postcss: "catalog:",
82
- react: "catalog:",
83
- "react-dom": "catalog:",
84
- "source-map-js": "1.2.1",
85
- "stacktrace-parser": "0.1.11",
86
- "tailwind-merge": "catalog:",
87
- tailwindcss: "catalog:",
88
- tsup: "catalog:",
89
- tsx: "^4.19.4",
90
- "tw-animate-css": "catalog:",
91
- typescript: "catalog:"
92
- }
93
- };
94
-
95
- // src/cli/commands/dev.ts
96
- import fs4 from "fs";
97
-
98
- // src/cli/utils/hot-reload/setup-hot-reloading.ts
99
- import { promises as fs3 } from "fs";
100
- import path6 from "path";
3
+ import fs, { existsSync, promises, statSync } from "node:fs";
4
+ import path from "node:path";
101
5
  import { watch } from "chokidar";
102
6
  import debounce from "debounce";
103
- import { Server as SocketServer } from "socket.io";
104
-
105
- // src/cli/utils/logger.ts
7
+ import { Server } from "socket.io";
106
8
  import { createConsola } from "consola";
107
- var logger = createConsola({});
108
-
109
- // src/cli/utils/hot-reload/create-dependency-graph.ts
110
- import { existsSync as existsSync2, promises as fs2, statSync } from "fs";
111
- import path5 from "path";
112
-
113
- // src/cli/utils/preview/start-dev-server.ts
114
- import http from "http";
115
- import path3 from "path";
116
- import url from "url";
9
+ import http from "node:http";
10
+ import url from "node:url";
117
11
  import chalk from "chalk";
118
- import logSymbols2 from "log-symbols";
12
+ import logSymbols from "log-symbols";
119
13
  import next from "next";
120
14
  import ora from "ora";
15
+ import { lookup } from "mime-types";
16
+ import { parse } from "@babel/parser";
17
+ import traverseModule from "@babel/traverse";
18
+ import { createMatchPath, loadConfig } from "tsconfig-paths";
121
19
 
122
- // src/utils/register-spinner-autostopping.ts
123
- import logSymbols from "log-symbols";
124
- var spinners = /* @__PURE__ */ new Set();
20
+ //#region package.json
21
+ var version = "1.1.13";
22
+
23
+ //#endregion
24
+ //#region src/cli/utils/logger.ts
25
+ const logger = createConsola({});
26
+
27
+ //#endregion
28
+ //#region src/utils/register-spinner-autostopping.ts
29
+ const spinners = /* @__PURE__ */ new Set();
125
30
  process.on("SIGINT", () => {
126
- spinners.forEach((spinner) => {
127
- if (spinner.isSpinning) {
128
- spinner.stop();
129
- }
130
- });
31
+ spinners.forEach((spinner) => {
32
+ if (spinner.isSpinning) spinner.stop();
33
+ });
131
34
  });
132
35
  process.on("exit", (code) => {
133
- if (code !== 0) {
134
- spinners.forEach((spinner) => {
135
- if (spinner.isSpinning) {
136
- spinner.stopAndPersist({
137
- symbol: logSymbols.error
138
- });
139
- }
140
- });
141
- }
36
+ if (code !== 0) spinners.forEach((spinner) => {
37
+ if (spinner.isSpinning) spinner.stopAndPersist({ symbol: logSymbols.error });
38
+ });
142
39
  });
143
- var registerSpinnerAutostopping = (spinner) => {
144
- spinners.add(spinner);
40
+ const registerSpinnerAutostopping = (spinner) => {
41
+ spinners.add(spinner);
145
42
  };
146
43
 
147
- // src/cli/utils/preview/get-env-variables.ts
148
- import path from "path";
149
- var getEnvVariablesForPreviewApp = (relativePathToEnvDirectory, cwd) => {
150
- return {
151
- ENV_DIR_RELATIVE_PATH: relativePathToEnvDirectory,
152
- ENV_DIR_ABSOLUTE_PATH: path.resolve(cwd, relativePathToEnvDirectory),
153
- USER_PROJECT_LOCATION: cwd,
154
- NEXT_PUBLIC_IS_PREVIEW_DEVELOPMENT: isDev ? "true" : "false"
155
- };
44
+ //#endregion
45
+ //#region src/cli/utils/preview/get-env-variables.ts
46
+ const getEnvVariablesForPreviewApp = (relativePathToEnvDirectory, cwd) => {
47
+ return {
48
+ ENV_DIR_RELATIVE_PATH: relativePathToEnvDirectory,
49
+ ENV_DIR_ABSOLUTE_PATH: path.resolve(cwd, relativePathToEnvDirectory),
50
+ USER_PROJECT_LOCATION: cwd,
51
+ NEXT_PUBLIC_IS_PREVIEW_DEVELOPMENT: isDev ? "true" : "false"
52
+ };
156
53
  };
157
54
 
158
- // src/cli/utils/preview/serve-static-file.ts
159
- import { existsSync, promises as fs } from "fs";
160
- import path2 from "path";
161
- import { lookup } from "mime-types";
162
- var serveStaticFile = async (res, parsedUrl, staticDirRelativePath) => {
163
- const pathname = parsedUrl.pathname?.replace("/static", "./static") ?? "";
164
- const ext = path2.parse(pathname).ext;
165
- const staticBaseDir = path2.resolve(process.cwd(), staticDirRelativePath);
166
- const fileAbsolutePath = path2.resolve(staticBaseDir, pathname);
167
- if (!fileAbsolutePath.startsWith(staticBaseDir)) {
168
- res.statusCode = 403;
169
- res.end();
170
- return;
171
- }
172
- try {
173
- const fileHandle = await fs.open(fileAbsolutePath, "r");
174
- const fileData = await fs.readFile(fileHandle);
175
- res.setHeader("Content-type", lookup(ext) || "text/plain");
176
- res.end(fileData);
177
- fileHandle.close();
178
- } catch (exception) {
179
- if (!existsSync(fileAbsolutePath)) {
180
- res.statusCode = 404;
181
- res.end();
182
- } else {
183
- const sanitizedFilePath = fileAbsolutePath.replace(/\n|\r/g, "");
184
- logger.error(
185
- new Error(
186
- `Could not read file at ${sanitizedFilePath} to be served, here's the exception:`
187
- ),
188
- exception
189
- );
190
- res.statusCode = 500;
191
- res.end(
192
- "Could not read file to be served! Check your terminal for more information."
193
- );
194
- }
195
- }
55
+ //#endregion
56
+ //#region src/cli/utils/preview/serve-static-file.ts
57
+ const serveStaticFile = async (res, parsedUrl, staticDirRelativePath) => {
58
+ const pathname = parsedUrl.pathname?.replace("/static", "./static") ?? "";
59
+ const ext = path.parse(pathname).ext;
60
+ const staticBaseDir = path.resolve(process.cwd(), staticDirRelativePath);
61
+ const fileAbsolutePath = path.resolve(staticBaseDir, pathname);
62
+ if (!fileAbsolutePath.startsWith(staticBaseDir)) {
63
+ res.statusCode = 403;
64
+ res.end();
65
+ return;
66
+ }
67
+ try {
68
+ const fileHandle = await promises.open(fileAbsolutePath, "r");
69
+ const fileData = await promises.readFile(fileHandle);
70
+ res.setHeader("Content-type", lookup(ext) || "text/plain");
71
+ res.end(fileData);
72
+ fileHandle.close();
73
+ } catch (exception) {
74
+ if (!existsSync(fileAbsolutePath)) {
75
+ res.statusCode = 404;
76
+ res.end();
77
+ } else {
78
+ const sanitizedFilePath = fileAbsolutePath.replace(/\n|\r/g, "");
79
+ logger.error(/* @__PURE__ */ new Error(`Could not read file at ${sanitizedFilePath} to be served, here's the exception:`), exception);
80
+ res.statusCode = 500;
81
+ res.end("Could not read file to be served! Check your terminal for more information.");
82
+ }
83
+ }
196
84
  };
197
85
 
198
- // src/cli/utils/preview/start-dev-server.ts
199
- var devServer;
200
- var safeAsyncServerListen = (server, port) => {
201
- return new Promise((resolve) => {
202
- server.listen(port, () => {
203
- resolve({ portAlreadyInUse: false });
204
- });
205
- server.on("error", (e) => {
206
- if (e.code === "EADDRINUSE") {
207
- resolve({ portAlreadyInUse: true });
208
- }
209
- });
210
- });
86
+ //#endregion
87
+ //#region src/cli/utils/preview/start-dev-server.ts
88
+ let devServer;
89
+ const safeAsyncServerListen = (server, port) => {
90
+ return new Promise((resolve) => {
91
+ server.listen(port, () => {
92
+ resolve({ portAlreadyInUse: false });
93
+ });
94
+ server.on("error", (e) => {
95
+ if (e.code === "EADDRINUSE") resolve({ portAlreadyInUse: true });
96
+ });
97
+ });
211
98
  };
212
- var filename = url.fileURLToPath(import.meta.url);
213
- var dirname = path3.dirname(filename);
214
- var isDev = !filename.endsWith(path3.join("cli", "index.mjs"));
215
- var cliPackageLocation = isDev ? path3.resolve(dirname, "../../../..") : path3.resolve(dirname, "../..");
216
- var previewServerLocation = isDev ? path3.resolve(dirname, "../../../..") : path3.resolve(dirname, "../preview");
217
- var startDevServer = async ({
218
- envDirRelativePath,
219
- staticBaseDirRelativePath,
220
- port,
221
- verbose
222
- }) => {
223
- const [majorNodeVersion] = process.versions.node.split(".");
224
- if (majorNodeVersion && Number.parseInt(majorNodeVersion) < 18) {
225
- logger.error(
226
- `Node ${majorNodeVersion} is not supported. Please upgrade to Node 18 or higher.`
227
- );
228
- process.exit(1);
229
- }
230
- devServer = http.createServer((req, res) => {
231
- if (!req.url) {
232
- res.end(404);
233
- return;
234
- }
235
- if (verbose) {
236
- logger.debug("Creating HTTP server...", {
237
- envDirRelativePath,
238
- staticBaseDirRelativePath,
239
- port
240
- });
241
- }
242
- const parsedUrl = url.parse(req.url, true);
243
- res.setHeader(
244
- "Cache-Control",
245
- "no-cache, max-age=0, must-revalidate, no-store"
246
- );
247
- res.setHeader("Pragma", "no-cache");
248
- res.setHeader("Expires", "-1");
249
- try {
250
- if (parsedUrl.path?.includes("static/") && !parsedUrl.path.includes("_next/static/")) {
251
- void serveStaticFile(res, parsedUrl, staticBaseDirRelativePath);
252
- } else if (!isNextReady) {
253
- void nextReadyPromise.then(
254
- () => nextHandleRequest?.(req, res, parsedUrl)
255
- );
256
- } else {
257
- void nextHandleRequest?.(req, res, parsedUrl);
258
- }
259
- } catch (e) {
260
- logger.error(new Error("Error while handling request!"), e);
261
- res.writeHead(500);
262
- res.end();
263
- }
264
- });
265
- const { portAlreadyInUse } = await safeAsyncServerListen(devServer, port);
266
- if (!portAlreadyInUse) {
267
- logger.log(chalk.greenBright(`
268
- Envin ${package_default.version}`));
269
- logger.log(` Running preview at: http://localhost:${port}
270
- `);
271
- } else {
272
- const nextPortToTry = port + 1;
273
- logger.warn(`Port ${port} is already in use, trying ${nextPortToTry}...`);
274
- return startDevServer({
275
- envDirRelativePath,
276
- staticBaseDirRelativePath,
277
- port: nextPortToTry,
278
- verbose
279
- });
280
- }
281
- devServer.on("close", async () => {
282
- await app.close();
283
- });
284
- devServer.on("error", (e) => {
285
- logger.error(new Error("Preview server error!"), e);
286
- process.exit(1);
287
- });
288
- const spinner = ora({
289
- text: "Getting envin preview server ready...\n",
290
- prefixText: " "
291
- }).start();
292
- registerSpinnerAutostopping(spinner);
293
- const timeBeforeNextReady = performance.now();
294
- process.env = {
295
- NODE_ENV: "development",
296
- ...process.env,
297
- ...getEnvVariablesForPreviewApp(
298
- path3.normalize(envDirRelativePath),
299
- process.cwd()
300
- )
301
- };
302
- const app = next({
303
- // passing in env here does not get the environment variables there
304
- dev: isDev,
305
- conf: {
306
- images: {
307
- // This is to avoid the warning with sharp
308
- unoptimized: true
309
- }
310
- },
311
- hostname: "localhost",
312
- port,
313
- dir: previewServerLocation
314
- });
315
- let isNextReady = false;
316
- const nextReadyPromise = app.prepare();
317
- await nextReadyPromise;
318
- isNextReady = true;
319
- const nextHandleRequest = app.getRequestHandler();
320
- const secondsToNextReady = ((performance.now() - timeBeforeNextReady) / 1e3).toFixed(1);
321
- spinner.stopAndPersist({
322
- text: `Ready in ${secondsToNextReady}s
323
- `,
324
- symbol: logSymbols2.success
325
- });
326
- return devServer;
99
+ const filename = url.fileURLToPath(import.meta.url);
100
+ const dirname = path.dirname(filename);
101
+ const isDev = !filename.endsWith(path.join("cli", "index.mjs"));
102
+ const cliPackageLocation = isDev ? path.resolve(dirname, "../../../..") : path.resolve(dirname, "../..");
103
+ const previewServerLocation = isDev ? path.resolve(dirname, "../../../..") : path.resolve(dirname, "../preview");
104
+ const startDevServer = async ({ envDirRelativePath, staticBaseDirRelativePath, port, verbose }) => {
105
+ const [majorNodeVersion] = process.versions.node.split(".");
106
+ if (majorNodeVersion && Number.parseInt(majorNodeVersion) < 18) {
107
+ logger.error(`Node ${majorNodeVersion} is not supported. Please upgrade to Node 18 or higher.`);
108
+ process.exit(1);
109
+ }
110
+ devServer = http.createServer((req, res) => {
111
+ if (!req.url) {
112
+ res.end(404);
113
+ return;
114
+ }
115
+ if (verbose) logger.debug("Creating HTTP server...", {
116
+ envDirRelativePath,
117
+ staticBaseDirRelativePath,
118
+ port
119
+ });
120
+ const parsedUrl = url.parse(req.url, true);
121
+ res.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate, no-store");
122
+ res.setHeader("Pragma", "no-cache");
123
+ res.setHeader("Expires", "-1");
124
+ try {
125
+ if (parsedUrl.path?.includes("static/") && !parsedUrl.path.includes("_next/static/")) serveStaticFile(res, parsedUrl, staticBaseDirRelativePath);
126
+ else if (!isNextReady) nextReadyPromise.then(() => nextHandleRequest?.(req, res, parsedUrl));
127
+ else nextHandleRequest?.(req, res, parsedUrl);
128
+ } catch (e) {
129
+ logger.error(/* @__PURE__ */ new Error("Error while handling request!"), e);
130
+ res.writeHead(500);
131
+ res.end();
132
+ }
133
+ });
134
+ const { portAlreadyInUse } = await safeAsyncServerListen(devServer, port);
135
+ if (!portAlreadyInUse) {
136
+ logger.log(chalk.greenBright(`\n Envin ${version}`));
137
+ logger.log(` Running preview at: http://localhost:${port}\n`);
138
+ } else {
139
+ const nextPortToTry = port + 1;
140
+ logger.warn(`Port ${port} is already in use, trying ${nextPortToTry}...`);
141
+ return startDevServer({
142
+ envDirRelativePath,
143
+ staticBaseDirRelativePath,
144
+ port: nextPortToTry,
145
+ verbose
146
+ });
147
+ }
148
+ devServer.on("close", async () => {
149
+ await app.close();
150
+ });
151
+ devServer.on("error", (e) => {
152
+ logger.error(/* @__PURE__ */ new Error("Preview server error!"), e);
153
+ process.exit(1);
154
+ });
155
+ const spinner = ora({
156
+ text: "Getting envin preview server ready...\n",
157
+ prefixText: " "
158
+ }).start();
159
+ registerSpinnerAutostopping(spinner);
160
+ const timeBeforeNextReady = performance.now();
161
+ process.env = {
162
+ NODE_ENV: "development",
163
+ ...process.env,
164
+ ...getEnvVariablesForPreviewApp(path.normalize(envDirRelativePath), process.cwd())
165
+ };
166
+ const app = next({
167
+ dev: isDev,
168
+ conf: { images: { unoptimized: true } },
169
+ hostname: "localhost",
170
+ port,
171
+ dir: previewServerLocation
172
+ });
173
+ let isNextReady = false;
174
+ const nextReadyPromise = app.prepare();
175
+ await nextReadyPromise;
176
+ isNextReady = true;
177
+ const nextHandleRequest = app.getRequestHandler();
178
+ const secondsToNextReady = ((performance.now() - timeBeforeNextReady) / 1e3).toFixed(1);
179
+ spinner.stopAndPersist({
180
+ text: `Ready in ${secondsToNextReady}s\n`,
181
+ symbol: logSymbols.success
182
+ });
183
+ return devServer;
327
184
  };
328
- var makeExitHandler = (options) => (_codeOrSignal) => {
329
- if (typeof devServer !== "undefined") {
330
- logger.log("\nShutting down dev server...");
331
- devServer.close();
332
- devServer = void 0;
333
- }
334
- if (options?.shouldKillProcess) {
335
- process.exit(options.killWithErrorCode ? 1 : 0);
336
- }
185
+ const makeExitHandler = (options) => (_codeOrSignal) => {
186
+ if (typeof devServer !== "undefined") {
187
+ logger.log("\nShutting down dev server...");
188
+ devServer.close();
189
+ devServer = void 0;
190
+ }
191
+ if (options?.shouldKillProcess) process.exit(options.killWithErrorCode ? 1 : 0);
337
192
  };
338
193
  process.on("exit", makeExitHandler());
339
- process.on(
340
- "SIGINT",
341
- makeExitHandler({ shouldKillProcess: true, killWithErrorCode: false })
342
- );
343
- process.on(
344
- "SIGUSR1",
345
- makeExitHandler({ shouldKillProcess: true, killWithErrorCode: false })
346
- );
347
- process.on(
348
- "SIGUSR2",
349
- makeExitHandler({ shouldKillProcess: true, killWithErrorCode: false })
350
- );
351
- process.on(
352
- "uncaughtException",
353
- makeExitHandler({ shouldKillProcess: true, killWithErrorCode: true })
354
- );
194
+ process.on("SIGINT", makeExitHandler({
195
+ shouldKillProcess: true,
196
+ killWithErrorCode: false
197
+ }));
198
+ process.on("SIGUSR1", makeExitHandler({
199
+ shouldKillProcess: true,
200
+ killWithErrorCode: false
201
+ }));
202
+ process.on("SIGUSR2", makeExitHandler({
203
+ shouldKillProcess: true,
204
+ killWithErrorCode: false
205
+ }));
206
+ process.on("uncaughtException", makeExitHandler({
207
+ shouldKillProcess: true,
208
+ killWithErrorCode: true
209
+ }));
355
210
 
356
- // src/cli/utils/hot-reload/get-imported-modules.ts
357
- import { parse } from "@babel/parser";
358
- import traverseModule from "@babel/traverse";
359
- var traverse = (
360
- // we keep this check here so that this still works with the dev:preview
361
- // script's use of tsx
362
- typeof traverseModule === "function" ? traverseModule : (
363
- // @ts-expect-error - this is a valid use case
364
- traverseModule.default
365
- )
366
- );
367
- var getImportedModules = (contents) => {
368
- const importedPaths = [];
369
- const parsedContents = parse(contents, {
370
- sourceType: "unambiguous",
371
- strictMode: false,
372
- errorRecovery: true,
373
- plugins: ["jsx", "typescript", "decorators"]
374
- });
375
- traverse(parsedContents, {
376
- ImportDeclaration({ node }) {
377
- importedPaths.push(node.source.value);
378
- },
379
- ExportAllDeclaration({ node }) {
380
- importedPaths.push(node.source.value);
381
- },
382
- ExportNamedDeclaration({ node }) {
383
- if (node.source) {
384
- importedPaths.push(node.source.value);
385
- }
386
- },
387
- TSExternalModuleReference({ node }) {
388
- importedPaths.push(node.expression.value);
389
- },
390
- CallExpression({ node }) {
391
- if ("name" in node.callee && node.callee.name === "require") {
392
- if (node.arguments.length === 1) {
393
- const importPathNode = node.arguments[0];
394
- if (importPathNode?.type === "StringLiteral") {
395
- importedPaths.push(importPathNode.value);
396
- }
397
- }
398
- }
399
- }
400
- });
401
- return importedPaths;
211
+ //#endregion
212
+ //#region src/cli/utils/hot-reload/get-imported-modules.ts
213
+ const traverse = typeof traverseModule === "function" ? traverseModule : traverseModule.default;
214
+ const getImportedModules = (contents) => {
215
+ const importedPaths = [];
216
+ traverse(parse(contents, {
217
+ sourceType: "unambiguous",
218
+ strictMode: false,
219
+ errorRecovery: true,
220
+ plugins: [
221
+ "jsx",
222
+ "typescript",
223
+ "decorators"
224
+ ]
225
+ }), {
226
+ ImportDeclaration({ node }) {
227
+ importedPaths.push(node.source.value);
228
+ },
229
+ ExportAllDeclaration({ node }) {
230
+ importedPaths.push(node.source.value);
231
+ },
232
+ ExportNamedDeclaration({ node }) {
233
+ if (node.source) importedPaths.push(node.source.value);
234
+ },
235
+ TSExternalModuleReference({ node }) {
236
+ importedPaths.push(node.expression.value);
237
+ },
238
+ CallExpression({ node }) {
239
+ if ("name" in node.callee && node.callee.name === "require") {
240
+ if (node.arguments.length === 1) {
241
+ const importPathNode = node.arguments[0];
242
+ if (importPathNode?.type === "StringLiteral") importedPaths.push(importPathNode.value);
243
+ }
244
+ }
245
+ }
246
+ });
247
+ return importedPaths;
402
248
  };
403
249
 
404
- // src/cli/utils/hot-reload/resolve-path-aliases.ts
405
- import path4 from "path";
406
- import { createMatchPath, loadConfig } from "tsconfig-paths";
407
- var resolvePathAliases = (importPaths, projectPath) => {
408
- const configLoadResult = loadConfig(projectPath);
409
- if (configLoadResult.resultType === "success") {
410
- const matchPath = createMatchPath(
411
- configLoadResult.absoluteBaseUrl,
412
- configLoadResult.paths
413
- );
414
- return importPaths.map((importedPath) => {
415
- const unaliasedPath = matchPath(importedPath, void 0, void 0, [
416
- ".tsx",
417
- ".ts",
418
- ".js",
419
- ".jsx",
420
- ".cjs",
421
- ".mjs"
422
- ]);
423
- if (unaliasedPath) {
424
- return `./${path4.relative(projectPath, unaliasedPath)}`;
425
- }
426
- return importedPath;
427
- });
428
- }
429
- return importPaths;
250
+ //#endregion
251
+ //#region src/cli/utils/hot-reload/resolve-path-aliases.ts
252
+ const resolvePathAliases = (importPaths, projectPath) => {
253
+ const configLoadResult = loadConfig(projectPath);
254
+ if (configLoadResult.resultType === "success") {
255
+ const matchPath = createMatchPath(configLoadResult.absoluteBaseUrl, configLoadResult.paths);
256
+ return importPaths.map((importedPath) => {
257
+ const unaliasedPath = matchPath(importedPath, void 0, void 0, [
258
+ ".tsx",
259
+ ".ts",
260
+ ".js",
261
+ ".jsx",
262
+ ".cjs",
263
+ ".mjs"
264
+ ]);
265
+ if (unaliasedPath) return `./${path.relative(projectPath, unaliasedPath)}`;
266
+ return importedPath;
267
+ });
268
+ }
269
+ return importPaths;
430
270
  };
431
271
 
432
- // src/cli/utils/hot-reload/create-dependency-graph.ts
433
- var readAllFilesInsideDirectory = async (directory) => {
434
- let allFilePaths = [];
435
- const topLevelDirents = await fs2.readdir(directory, { withFileTypes: true });
436
- for await (const dirent of topLevelDirents) {
437
- const pathToDirent = path5.join(directory, dirent.name);
438
- if (dirent.isDirectory()) {
439
- allFilePaths = allFilePaths.concat(
440
- await readAllFilesInsideDirectory(pathToDirent)
441
- );
442
- } else {
443
- allFilePaths.push(pathToDirent);
444
- }
445
- }
446
- return allFilePaths;
272
+ //#endregion
273
+ //#region src/cli/utils/hot-reload/create-dependency-graph.ts
274
+ const readAllFilesInsideDirectory = async (directory) => {
275
+ let allFilePaths = [];
276
+ const topLevelDirents = await promises.readdir(directory, { withFileTypes: true });
277
+ for await (const dirent of topLevelDirents) {
278
+ const pathToDirent = path.join(directory, dirent.name);
279
+ if (dirent.isDirectory()) allFilePaths = allFilePaths.concat(await readAllFilesInsideDirectory(pathToDirent));
280
+ else allFilePaths.push(pathToDirent);
281
+ }
282
+ return allFilePaths;
447
283
  };
448
- var isJavascriptModule = (filePath) => {
449
- const extensionName = path5.extname(filePath);
450
- return [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"].includes(extensionName);
284
+ const isJavascriptModule = (filePath) => {
285
+ const extensionName = path.extname(filePath);
286
+ return [
287
+ ".js",
288
+ ".ts",
289
+ ".jsx",
290
+ ".tsx",
291
+ ".mjs",
292
+ ".cjs"
293
+ ].includes(extensionName);
451
294
  };
452
- var checkFileExtensionsUntilItExists = (pathWithoutExtension) => {
453
- if (existsSync2(`${pathWithoutExtension}.ts`)) {
454
- return `${pathWithoutExtension}.ts`;
455
- }
456
- if (existsSync2(`${pathWithoutExtension}.tsx`)) {
457
- return `${pathWithoutExtension}.tsx`;
458
- }
459
- if (existsSync2(`${pathWithoutExtension}.js`)) {
460
- return `${pathWithoutExtension}.js`;
461
- }
462
- if (existsSync2(`${pathWithoutExtension}.jsx`)) {
463
- return `${pathWithoutExtension}.jsx`;
464
- }
465
- if (existsSync2(`${pathWithoutExtension}.mjs`)) {
466
- return `${pathWithoutExtension}.mjs`;
467
- }
468
- if (existsSync2(`${pathWithoutExtension}.cjs`)) {
469
- return `${pathWithoutExtension}.cjs`;
470
- }
295
+ const checkFileExtensionsUntilItExists = (pathWithoutExtension) => {
296
+ if (existsSync(`${pathWithoutExtension}.ts`)) return `${pathWithoutExtension}.ts`;
297
+ if (existsSync(`${pathWithoutExtension}.tsx`)) return `${pathWithoutExtension}.tsx`;
298
+ if (existsSync(`${pathWithoutExtension}.js`)) return `${pathWithoutExtension}.js`;
299
+ if (existsSync(`${pathWithoutExtension}.jsx`)) return `${pathWithoutExtension}.jsx`;
300
+ if (existsSync(`${pathWithoutExtension}.mjs`)) return `${pathWithoutExtension}.mjs`;
301
+ if (existsSync(`${pathWithoutExtension}.cjs`)) return `${pathWithoutExtension}.cjs`;
471
302
  };
472
- var createDependencyGraph = async (directory) => {
473
- const filePaths = await readAllFilesInsideDirectory(directory);
474
- const modulePaths = filePaths.filter(isJavascriptModule);
475
- const graph = Object.fromEntries(
476
- modulePaths.map((path7) => [
477
- path7,
478
- {
479
- path: path7,
480
- dependencyPaths: [],
481
- dependentPaths: [],
482
- moduleDependencies: []
483
- }
484
- ])
485
- );
486
- const getDependencyPaths = async (filePath) => {
487
- const contents = await fs2.readFile(filePath, "utf8");
488
- const importedPaths = isJavascriptModule(filePath) ? resolvePathAliases(getImportedModules(contents), path5.dirname(filePath)) : [];
489
- const importedPathsRelativeToDirectory = importedPaths.map(
490
- (dependencyPath) => {
491
- const isModulePath = !dependencyPath.startsWith(".");
492
- if (isModulePath || path5.isAbsolute(dependencyPath)) {
493
- return dependencyPath;
494
- }
495
- let pathToDependencyFromDirectory = path5.resolve(
496
- /*
497
- path.resolve resolves paths differently from what imports on javascript do.
498
-
499
- So if we wouldn't do this, for an email at "/path/to/email.tsx" with a dependency path of "./other-email"
500
- would end up going into /path/to/email.tsx/other-email instead of /path/to/other-email which is the
501
- one the import is meant to go to
502
- */
503
- path5.dirname(filePath),
504
- dependencyPath
505
- );
506
- let isDirectory = false;
507
- try {
508
- isDirectory = statSync(pathToDependencyFromDirectory).isDirectory();
509
- } catch (_) {
510
- }
511
- if (isDirectory) {
512
- const pathToSubDirectory = pathToDependencyFromDirectory;
513
- const pathWithExtension = checkFileExtensionsUntilItExists(
514
- `${pathToSubDirectory}/index`
515
- );
516
- if (pathWithExtension) {
517
- pathToDependencyFromDirectory = pathWithExtension;
518
- } else if (isDev) {
519
- logger.warn(
520
- `Could not find index file for directory at ${pathToDependencyFromDirectory}. This is probably going to cause issues with both hot reloading and your code.`
521
- );
522
- }
523
- }
524
- const extension = path5.extname(pathToDependencyFromDirectory);
525
- const pathWithEnsuredExtension = (() => {
526
- if (extension.length > 0 && existsSync2(pathToDependencyFromDirectory)) {
527
- return pathToDependencyFromDirectory;
528
- }
529
- return checkFileExtensionsUntilItExists(
530
- pathToDependencyFromDirectory.replace(extension, "")
531
- );
532
- })();
533
- if (pathWithEnsuredExtension) {
534
- pathToDependencyFromDirectory = pathWithEnsuredExtension;
535
- } else if (isDev) {
536
- logger.warn(
537
- `Could not find file at ${pathToDependencyFromDirectory}`
538
- );
539
- }
540
- return pathToDependencyFromDirectory;
541
- }
542
- );
543
- const moduleDependencies = importedPathsRelativeToDirectory.filter(
544
- (dependencyPath) => !dependencyPath.startsWith(".") && !path5.isAbsolute(dependencyPath)
545
- );
546
- const nonNodeModuleImportPathsRelativeToDirectory = importedPathsRelativeToDirectory.filter(
547
- (dependencyPath) => dependencyPath.startsWith(".") || path5.isAbsolute(dependencyPath)
548
- );
549
- return {
550
- dependencyPaths: nonNodeModuleImportPathsRelativeToDirectory,
551
- moduleDependencies
552
- };
553
- };
554
- const updateModuleDependenciesInGraph = async (moduleFilePath) => {
555
- if (graph[moduleFilePath] === void 0) {
556
- graph[moduleFilePath] = {
557
- path: moduleFilePath,
558
- dependencyPaths: [],
559
- dependentPaths: [],
560
- moduleDependencies: []
561
- };
562
- }
563
- const { moduleDependencies, dependencyPaths: newDependencyPaths } = await getDependencyPaths(moduleFilePath);
564
- graph[moduleFilePath].moduleDependencies = moduleDependencies;
565
- for (const dependencyPath of graph[moduleFilePath].dependencyPaths) {
566
- if (newDependencyPaths.includes(dependencyPath)) continue;
567
- const dependencyModule = graph[dependencyPath];
568
- if (dependencyModule !== void 0) {
569
- dependencyModule.dependentPaths = dependencyModule.dependentPaths.filter(
570
- (dependentPath) => dependentPath !== moduleFilePath
571
- );
572
- }
573
- }
574
- graph[moduleFilePath].dependencyPaths = newDependencyPaths;
575
- for await (const dependencyPath of newDependencyPaths) {
576
- if (graph[dependencyPath] === void 0) {
577
- await updateModuleDependenciesInGraph(dependencyPath);
578
- }
579
- const dependencyModule = graph[dependencyPath];
580
- if (dependencyModule === void 0) {
581
- throw new Error(
582
- `Loading the dependency path ${dependencyPath} did not initialize it at all. This is a bug in React Email.`
583
- );
584
- }
585
- if (!dependencyModule.dependentPaths.includes(moduleFilePath)) {
586
- dependencyModule.dependentPaths.push(moduleFilePath);
587
- }
588
- }
589
- };
590
- const removeModuleFromGraph = (filePath) => {
591
- const module = graph[filePath];
592
- if (module) {
593
- for (const dependencyPath of module.dependencyPaths) {
594
- if (graph[dependencyPath]) {
595
- graph[dependencyPath].dependentPaths = graph[dependencyPath].dependentPaths.filter(
596
- (dependentPath) => dependentPath !== filePath
597
- );
598
- }
599
- }
600
- delete graph[filePath];
601
- }
602
- };
603
- return [
604
- graph,
605
- async (event, pathToModified) => {
606
- switch (event) {
607
- case "change":
608
- if (isJavascriptModule(pathToModified)) {
609
- await updateModuleDependenciesInGraph(pathToModified);
610
- }
611
- break;
612
- case "add":
613
- if (isJavascriptModule(pathToModified)) {
614
- await updateModuleDependenciesInGraph(pathToModified);
615
- }
616
- break;
617
- case "addDir": {
618
- const filesInsideAddedDirectory = await readAllFilesInsideDirectory(pathToModified);
619
- const modulesInsideAddedDirectory = filesInsideAddedDirectory.filter(isJavascriptModule);
620
- for await (const filePath of modulesInsideAddedDirectory) {
621
- await updateModuleDependenciesInGraph(filePath);
622
- }
623
- break;
624
- }
625
- case "unlink":
626
- if (isJavascriptModule(pathToModified)) {
627
- removeModuleFromGraph(pathToModified);
628
- }
629
- break;
630
- case "unlinkDir": {
631
- const filesInsideDeletedDirectory = await readAllFilesInsideDirectory(pathToModified);
632
- const modulesInsideDeletedDirectory = filesInsideDeletedDirectory.filter(isJavascriptModule);
633
- for await (const filePath of modulesInsideDeletedDirectory) {
634
- removeModuleFromGraph(filePath);
635
- }
636
- break;
637
- }
638
- }
639
- },
640
- {
641
- resolveDependentsOf: function resolveDependentsOf(pathToModule) {
642
- const moduleEntry = graph[pathToModule];
643
- const dependentPaths = [];
644
- if (moduleEntry) {
645
- for (const dependentPath of moduleEntry.dependentPaths) {
646
- const dependentsOfDependent = resolveDependentsOf(dependentPath);
647
- dependentPaths.push(...dependentsOfDependent);
648
- dependentPaths.push(dependentPath);
649
- }
650
- }
651
- return dependentPaths;
652
- }
653
- }
654
- ];
303
+ /**
304
+ * Creates a stateful dependency graph that is structured in a way that you can get
305
+ * the dependents of a module from its path.
306
+ *
307
+ * Stateful in the sense that it provides a `getter` and an "`updater`". The updater
308
+ * will receive changes to the files, that can be perceived through some file watching mechanism,
309
+ * so that it doesn't need to recompute the entire dependency graph but only the parts changed.
310
+ */
311
+ const createDependencyGraph = async (directory) => {
312
+ const modulePaths = (await readAllFilesInsideDirectory(directory)).filter(isJavascriptModule);
313
+ const graph = Object.fromEntries(modulePaths.map((path$1) => [path$1, {
314
+ path: path$1,
315
+ dependencyPaths: [],
316
+ dependentPaths: [],
317
+ moduleDependencies: []
318
+ }]));
319
+ const getDependencyPaths = async (filePath) => {
320
+ const contents = await promises.readFile(filePath, "utf8");
321
+ const importedPathsRelativeToDirectory = (isJavascriptModule(filePath) ? resolvePathAliases(getImportedModules(contents), path.dirname(filePath)) : []).map((dependencyPath) => {
322
+ if (!dependencyPath.startsWith(".") || path.isAbsolute(dependencyPath)) return dependencyPath;
323
+ let pathToDependencyFromDirectory = path.resolve(path.dirname(filePath), dependencyPath);
324
+ let isDirectory = false;
325
+ try {
326
+ isDirectory = statSync(pathToDependencyFromDirectory).isDirectory();
327
+ } catch (_) {}
328
+ if (isDirectory) {
329
+ const pathWithExtension = checkFileExtensionsUntilItExists(`${pathToDependencyFromDirectory}/index`);
330
+ if (pathWithExtension) pathToDependencyFromDirectory = pathWithExtension;
331
+ else if (isDev) logger.warn(`Could not find index file for directory at ${pathToDependencyFromDirectory}. This is probably going to cause issues with both hot reloading and your code.`);
332
+ }
333
+ const extension = path.extname(pathToDependencyFromDirectory);
334
+ const pathWithEnsuredExtension = (() => {
335
+ if (extension.length > 0 && existsSync(pathToDependencyFromDirectory)) return pathToDependencyFromDirectory;
336
+ return checkFileExtensionsUntilItExists(pathToDependencyFromDirectory.replace(extension, ""));
337
+ })();
338
+ if (pathWithEnsuredExtension) pathToDependencyFromDirectory = pathWithEnsuredExtension;
339
+ else if (isDev) logger.warn(`Could not find file at ${pathToDependencyFromDirectory}`);
340
+ return pathToDependencyFromDirectory;
341
+ });
342
+ const moduleDependencies = importedPathsRelativeToDirectory.filter((dependencyPath) => !dependencyPath.startsWith(".") && !path.isAbsolute(dependencyPath));
343
+ return {
344
+ dependencyPaths: importedPathsRelativeToDirectory.filter((dependencyPath) => dependencyPath.startsWith(".") || path.isAbsolute(dependencyPath)),
345
+ moduleDependencies
346
+ };
347
+ };
348
+ const updateModuleDependenciesInGraph = async (moduleFilePath) => {
349
+ if (graph[moduleFilePath] === void 0) graph[moduleFilePath] = {
350
+ path: moduleFilePath,
351
+ dependencyPaths: [],
352
+ dependentPaths: [],
353
+ moduleDependencies: []
354
+ };
355
+ const { moduleDependencies, dependencyPaths: newDependencyPaths } = await getDependencyPaths(moduleFilePath);
356
+ graph[moduleFilePath].moduleDependencies = moduleDependencies;
357
+ for (const dependencyPath of graph[moduleFilePath].dependencyPaths) {
358
+ if (newDependencyPaths.includes(dependencyPath)) continue;
359
+ const dependencyModule = graph[dependencyPath];
360
+ if (dependencyModule !== void 0) dependencyModule.dependentPaths = dependencyModule.dependentPaths.filter((dependentPath) => dependentPath !== moduleFilePath);
361
+ }
362
+ graph[moduleFilePath].dependencyPaths = newDependencyPaths;
363
+ for await (const dependencyPath of newDependencyPaths) {
364
+ if (graph[dependencyPath] === void 0) await updateModuleDependenciesInGraph(dependencyPath);
365
+ const dependencyModule = graph[dependencyPath];
366
+ if (dependencyModule === void 0) throw new Error(`Loading the dependency path ${dependencyPath} did not initialize it at all. This is a bug in React Email.`);
367
+ if (!dependencyModule.dependentPaths.includes(moduleFilePath)) dependencyModule.dependentPaths.push(moduleFilePath);
368
+ }
369
+ };
370
+ const removeModuleFromGraph = (filePath) => {
371
+ const module = graph[filePath];
372
+ if (module) {
373
+ for (const dependencyPath of module.dependencyPaths) if (graph[dependencyPath]) graph[dependencyPath].dependentPaths = graph[dependencyPath].dependentPaths.filter((dependentPath) => dependentPath !== filePath);
374
+ delete graph[filePath];
375
+ }
376
+ };
377
+ return [
378
+ graph,
379
+ async (event, pathToModified) => {
380
+ switch (event) {
381
+ case "change":
382
+ if (isJavascriptModule(pathToModified)) await updateModuleDependenciesInGraph(pathToModified);
383
+ break;
384
+ case "add":
385
+ if (isJavascriptModule(pathToModified)) await updateModuleDependenciesInGraph(pathToModified);
386
+ break;
387
+ case "addDir": {
388
+ const modulesInsideAddedDirectory = (await readAllFilesInsideDirectory(pathToModified)).filter(isJavascriptModule);
389
+ for await (const filePath of modulesInsideAddedDirectory) await updateModuleDependenciesInGraph(filePath);
390
+ break;
391
+ }
392
+ case "unlink":
393
+ if (isJavascriptModule(pathToModified)) removeModuleFromGraph(pathToModified);
394
+ break;
395
+ case "unlinkDir": {
396
+ const modulesInsideDeletedDirectory = (await readAllFilesInsideDirectory(pathToModified)).filter(isJavascriptModule);
397
+ for await (const filePath of modulesInsideDeletedDirectory) removeModuleFromGraph(filePath);
398
+ break;
399
+ }
400
+ }
401
+ },
402
+ { resolveDependentsOf: function resolveDependentsOf(pathToModule) {
403
+ const moduleEntry = graph[pathToModule];
404
+ const dependentPaths = [];
405
+ if (moduleEntry) for (const dependentPath of moduleEntry.dependentPaths) {
406
+ const dependentsOfDependent = resolveDependentsOf(dependentPath);
407
+ dependentPaths.push(...dependentsOfDependent);
408
+ dependentPaths.push(dependentPath);
409
+ }
410
+ return dependentPaths;
411
+ } }
412
+ ];
655
413
  };
656
414
 
657
- // src/cli/utils/hot-reload/setup-hot-reloading.ts
658
- var IGNORED_DIR_NAMES = [
659
- "node_modules",
660
- ".git",
661
- "dist",
662
- "build",
663
- "out",
664
- "coverage",
665
- ".cache",
666
- "tmp"
415
+ //#endregion
416
+ //#region src/cli/utils/hot-reload/setup-hot-reloading.ts
417
+ const IGNORED_DIR_NAMES = [
418
+ "node_modules",
419
+ ".git",
420
+ "dist",
421
+ "build",
422
+ "out",
423
+ "coverage",
424
+ ".cache",
425
+ "tmp"
667
426
  ];
668
- var normalizePath = (p) => p.split(path6.sep).join("/");
669
- var isPathInIgnoredDir = (p) => {
670
- const normalized = normalizePath(p);
671
- return IGNORED_DIR_NAMES.some(
672
- (dir) => normalized.includes(`/${dir}/`) || normalized.endsWith(`/${dir}`) || normalized.startsWith(`${dir}/`)
673
- );
427
+ const normalizePath = (p) => p.split(path.sep).join("/");
428
+ const isPathInIgnoredDir = (p) => {
429
+ const normalized = normalizePath(p);
430
+ return IGNORED_DIR_NAMES.some((dir) => normalized.includes(`/${dir}/`) || normalized.endsWith(`/${dir}`) || normalized.startsWith(`${dir}/`));
674
431
  };
675
- var toDirGlob = (dir) => [`**/${dir}/**`, `${dir}/**`];
676
- var readGitignoreGlobs = async (baseDir) => {
677
- try {
678
- const gitignorePath = path6.join(baseDir, ".gitignore");
679
- const data = await fs3.readFile(gitignorePath, "utf8");
680
- const lines = data.split(/\r?\n/);
681
- const globs = [];
682
- for (const rawLine of lines) {
683
- const line = rawLine.trim();
684
- if (line.length === 0 || line.startsWith("#") || line.startsWith("!")) {
685
- continue;
686
- }
687
- let pattern = line.replace(/^\//, "");
688
- if (pattern.endsWith("/")) {
689
- pattern = pattern.slice(0, -1);
690
- globs.push(`**/${pattern}/**`, `${pattern}/**`);
691
- continue;
692
- }
693
- if (pattern.includes("*") || pattern.includes("?")) {
694
- globs.push(`**/${pattern}`, pattern);
695
- } else {
696
- globs.push(
697
- `**/${pattern}/**`,
698
- `${pattern}/**`,
699
- `**/${pattern}`,
700
- pattern
701
- );
702
- }
703
- }
704
- return globs;
705
- } catch {
706
- return [];
707
- }
432
+ const toDirGlob = (dir) => [`**/${dir}/**`, `${dir}/**`];
433
+ const readGitignoreGlobs = async (baseDir) => {
434
+ try {
435
+ const gitignorePath = path.join(baseDir, ".gitignore");
436
+ const lines = (await promises.readFile(gitignorePath, "utf8")).split(/\r?\n/);
437
+ const globs = [];
438
+ for (const rawLine of lines) {
439
+ const line = rawLine.trim();
440
+ if (line.length === 0 || line.startsWith("#") || line.startsWith("!")) continue;
441
+ let pattern = line.replace(/^\//, "");
442
+ if (pattern.endsWith("/")) {
443
+ pattern = pattern.slice(0, -1);
444
+ globs.push(`**/${pattern}/**`, `${pattern}/**`);
445
+ continue;
446
+ }
447
+ if (pattern.includes("*") || pattern.includes("?")) globs.push(`**/${pattern}`, pattern);
448
+ else globs.push(`**/${pattern}/**`, `${pattern}/**`, `**/${pattern}`, pattern);
449
+ }
450
+ return globs;
451
+ } catch {
452
+ return [];
453
+ }
708
454
  };
709
- var buildIgnoredGlobs = async (baseDir) => {
710
- const defaultIgnoredGlobs = IGNORED_DIR_NAMES.flatMap(toDirGlob);
711
- const gitignoreGlobs = await readGitignoreGlobs(baseDir);
712
- return [...defaultIgnoredGlobs, ...gitignoreGlobs];
455
+ const buildIgnoredGlobs = async (baseDir) => {
456
+ const defaultIgnoredGlobs = IGNORED_DIR_NAMES.flatMap(toDirGlob);
457
+ const gitignoreGlobs = await readGitignoreGlobs(baseDir);
458
+ return [...defaultIgnoredGlobs, ...gitignoreGlobs];
713
459
  };
714
- var createEnvWatcher = async (baseDir) => {
715
- const ignoredGlobs = await buildIgnoredGlobs(baseDir);
716
- return watch(["**/*.{js,ts,jsx,tsx,mjs,cjs}"], {
717
- cwd: baseDir,
718
- ignoreInitial: true,
719
- ignored: ignoredGlobs,
720
- ignorePermissionErrors: true,
721
- awaitWriteFinish: { stabilityThreshold: 50, pollInterval: 10 }
722
- });
460
+ const createEnvWatcher = async (baseDir) => {
461
+ return watch(["**/*.{js,ts,jsx,tsx,mjs,cjs}"], {
462
+ cwd: baseDir,
463
+ ignoreInitial: true,
464
+ ignored: await buildIgnoredGlobs(baseDir),
465
+ ignorePermissionErrors: true,
466
+ awaitWriteFinish: {
467
+ stabilityThreshold: 50,
468
+ pollInterval: 10
469
+ }
470
+ });
723
471
  };
724
- var addExternalFilesToWatcher = (w, files) => {
725
- for (const p of files) {
726
- if (!isPathInIgnoredDir(p)) {
727
- w.add(p);
728
- }
729
- }
472
+ const addExternalFilesToWatcher = (w, files) => {
473
+ for (const p of files) if (!isPathInIgnoredDir(p)) w.add(p);
730
474
  };
731
- var attachShutdownHandlers = (w, verbose) => {
732
- const exit = async () => {
733
- if (verbose) {
734
- logger.info("Stopping file watcher and cleaning up...");
735
- }
736
- await w.close();
737
- };
738
- process.on("SIGINT", exit);
739
- process.on("uncaughtException", exit);
475
+ const attachShutdownHandlers = (w, verbose) => {
476
+ const exit = async () => {
477
+ if (verbose) logger.info("Stopping file watcher and cleaning up...");
478
+ await w.close();
479
+ };
480
+ process.on("SIGINT", exit);
481
+ process.on("uncaughtException", exit);
740
482
  };
741
- var setupHotreloading = async ({
742
- devServer: devServer2,
743
- envDirRelativePath,
744
- verbose
745
- }) => {
746
- if (verbose) {
747
- logger.start("Initializing socket.io server for hot reloading...");
748
- }
749
- let clients = [];
750
- const io = new SocketServer(devServer2);
751
- io.on("connection", (client) => {
752
- if (verbose) {
753
- logger.debug("Client connected to hot reload socket");
754
- }
755
- clients.push(client);
756
- client.on("disconnect", () => {
757
- if (verbose) {
758
- logger.debug("Client disconnected from hot reload socket");
759
- }
760
- clients = clients.filter((item) => item !== client);
761
- });
762
- });
763
- let changes = [];
764
- const reload = debounce(() => {
765
- if (verbose) {
766
- logger.debug(
767
- "Emitting reload event to",
768
- clients.length,
769
- "clients",
770
- changes
771
- );
772
- }
773
- clients.forEach((client) => {
774
- client.emit(
775
- "reload",
776
- changes.filter(
777
- (change) => (
778
- // Ensures only changes inside the emails directory are emitted
779
- path6.resolve(absolutePathToEnvDirectory, change.filename).startsWith(absolutePathToEnvDirectory)
780
- )
781
- )
782
- );
783
- });
784
- changes = [];
785
- }, 150);
786
- const absolutePathToEnvDirectory = path6.resolve(
787
- process.cwd(),
788
- envDirRelativePath
789
- );
790
- const [dependencyGraph, updateDependencyGraph, { resolveDependentsOf }] = await createDependencyGraph(absolutePathToEnvDirectory);
791
- if (verbose) {
792
- logger.info("Dependency graph created", {
793
- modules: Object.keys(dependencyGraph).length,
794
- root: absolutePathToEnvDirectory
795
- });
796
- }
797
- const watcher = await createEnvWatcher(absolutePathToEnvDirectory);
798
- const getFilesOutsideEnvDirectory = () => Object.keys(dependencyGraph).filter(
799
- (p) => path6.relative(absolutePathToEnvDirectory, p).startsWith("..")
800
- );
801
- let filesOutsideEnvDirectory = getFilesOutsideEnvDirectory();
802
- addExternalFilesToWatcher(watcher, filesOutsideEnvDirectory);
803
- attachShutdownHandlers(watcher, verbose);
804
- watcher.on("all", async (event, relativePathToChangeTarget) => {
805
- if (verbose) {
806
- logger.debug("File system event", {
807
- event,
808
- file: relativePathToChangeTarget
809
- });
810
- }
811
- const file = relativePathToChangeTarget.split(path6.sep);
812
- if (file.length === 0) {
813
- return;
814
- }
815
- const pathToChangeTarget = path6.resolve(
816
- absolutePathToEnvDirectory,
817
- relativePathToChangeTarget
818
- );
819
- await updateDependencyGraph(event, pathToChangeTarget);
820
- const newFilesOutsideEnvDirectory = getFilesOutsideEnvDirectory();
821
- for (const p of filesOutsideEnvDirectory) {
822
- if (!newFilesOutsideEnvDirectory.includes(p)) {
823
- watcher.unwatch(p);
824
- }
825
- }
826
- for (const p of newFilesOutsideEnvDirectory) {
827
- if (!filesOutsideEnvDirectory.includes(p) && !isPathInIgnoredDir(p)) {
828
- watcher.add(p);
829
- }
830
- }
831
- filesOutsideEnvDirectory = newFilesOutsideEnvDirectory;
832
- changes.push({
833
- event,
834
- filename: relativePathToChangeTarget
835
- });
836
- for (const dependentPath of resolveDependentsOf(pathToChangeTarget)) {
837
- changes.push({
838
- event: "change",
839
- filename: path6.relative(absolutePathToEnvDirectory, dependentPath)
840
- });
841
- }
842
- reload();
843
- });
844
- return watcher;
483
+ const setupHotreloading = async ({ devServer: devServer$1, envDirRelativePath, verbose }) => {
484
+ if (verbose) logger.start("Initializing socket.io server for hot reloading...");
485
+ let clients = [];
486
+ new Server(devServer$1).on("connection", (client) => {
487
+ if (verbose) logger.debug("Client connected to hot reload socket");
488
+ clients.push(client);
489
+ client.on("disconnect", () => {
490
+ if (verbose) logger.debug("Client disconnected from hot reload socket");
491
+ clients = clients.filter((item) => item !== client);
492
+ });
493
+ });
494
+ let changes = [];
495
+ const reload = debounce(() => {
496
+ if (verbose) logger.debug("Emitting reload event to", clients.length, "clients", changes);
497
+ clients.forEach((client) => {
498
+ client.emit("reload", changes.filter((change) => path.resolve(absolutePathToEnvDirectory, change.filename).startsWith(absolutePathToEnvDirectory)));
499
+ });
500
+ changes = [];
501
+ }, 150);
502
+ const absolutePathToEnvDirectory = path.resolve(process.cwd(), envDirRelativePath);
503
+ const [dependencyGraph, updateDependencyGraph, { resolveDependentsOf }] = await createDependencyGraph(absolutePathToEnvDirectory);
504
+ if (verbose) logger.info("Dependency graph created", {
505
+ modules: Object.keys(dependencyGraph).length,
506
+ root: absolutePathToEnvDirectory
507
+ });
508
+ const watcher = await createEnvWatcher(absolutePathToEnvDirectory);
509
+ const getFilesOutsideEnvDirectory = () => Object.keys(dependencyGraph).filter((p) => path.relative(absolutePathToEnvDirectory, p).startsWith(".."));
510
+ let filesOutsideEnvDirectory = getFilesOutsideEnvDirectory();
511
+ addExternalFilesToWatcher(watcher, filesOutsideEnvDirectory);
512
+ attachShutdownHandlers(watcher, verbose);
513
+ watcher.on("all", async (event, relativePathToChangeTarget) => {
514
+ if (verbose) logger.debug("File system event", {
515
+ event,
516
+ file: relativePathToChangeTarget
517
+ });
518
+ if (relativePathToChangeTarget.split(path.sep).length === 0) return;
519
+ const pathToChangeTarget = path.resolve(absolutePathToEnvDirectory, relativePathToChangeTarget);
520
+ await updateDependencyGraph(event, pathToChangeTarget);
521
+ const newFilesOutsideEnvDirectory = getFilesOutsideEnvDirectory();
522
+ for (const p of filesOutsideEnvDirectory) if (!newFilesOutsideEnvDirectory.includes(p)) watcher.unwatch(p);
523
+ for (const p of newFilesOutsideEnvDirectory) if (!filesOutsideEnvDirectory.includes(p) && !isPathInIgnoredDir(p)) watcher.add(p);
524
+ filesOutsideEnvDirectory = newFilesOutsideEnvDirectory;
525
+ changes.push({
526
+ event,
527
+ filename: relativePathToChangeTarget
528
+ });
529
+ for (const dependentPath of resolveDependentsOf(pathToChangeTarget)) changes.push({
530
+ event: "change",
531
+ filename: path.relative(absolutePathToEnvDirectory, dependentPath)
532
+ });
533
+ reload();
534
+ });
535
+ return watcher;
845
536
  };
846
537
 
847
- // src/cli/commands/dev.ts
848
- var dev = async ({ dir: envDirRelativePath, port, verbose }) => {
849
- try {
850
- if (verbose) {
851
- logger.debug("Starting dev command...", {
852
- cwd: process.cwd(),
853
- dir: envDirRelativePath,
854
- port
855
- });
856
- }
857
- if (!fs4.existsSync(envDirRelativePath)) {
858
- logger.error(`Missing ${envDirRelativePath} folder!`);
859
- process.exit(1);
860
- }
861
- const devServer2 = await startDevServer({
862
- envDirRelativePath,
863
- staticBaseDirRelativePath: envDirRelativePath,
864
- port: Number.parseInt(port),
865
- verbose
866
- });
867
- if (verbose) {
868
- logger.start("Dev server started, setting up hot reloading...");
869
- }
870
- await setupHotreloading({
871
- devServer: devServer2,
872
- envDirRelativePath,
873
- verbose
874
- });
875
- if (verbose) {
876
- logger.success("Hot reloading setup complete");
877
- }
878
- } catch (error) {
879
- logger.error(new Error("Error while running dev!"), error);
880
- process.exit(1);
881
- }
538
+ //#endregion
539
+ //#region src/cli/commands/dev.ts
540
+ const dev = async ({ dir: envDirRelativePath, port, verbose }) => {
541
+ try {
542
+ if (verbose) logger.debug("Starting dev command...", {
543
+ cwd: process.cwd(),
544
+ dir: envDirRelativePath,
545
+ port
546
+ });
547
+ if (!fs.existsSync(envDirRelativePath)) {
548
+ logger.error(`Missing ${envDirRelativePath} folder!`);
549
+ process.exit(1);
550
+ }
551
+ const devServer$1 = await startDevServer({
552
+ envDirRelativePath,
553
+ staticBaseDirRelativePath: envDirRelativePath,
554
+ port: Number.parseInt(port),
555
+ verbose
556
+ });
557
+ if (verbose) logger.start("Dev server started, setting up hot reloading...");
558
+ await setupHotreloading({
559
+ devServer: devServer$1,
560
+ envDirRelativePath,
561
+ verbose
562
+ });
563
+ if (verbose) logger.success("Hot reloading setup complete");
564
+ } catch (error) {
565
+ logger.error(/* @__PURE__ */ new Error("Error while running dev!"), error);
566
+ process.exit(1);
567
+ }
882
568
  };
883
569
 
884
- // src/cli/index.ts
885
- var PACKAGE_NAME = "@envin/cli";
886
- program.name(PACKAGE_NAME).description(
887
- "A live preview of your environment variables right in your browser"
888
- ).version(package_default.version);
889
- program.command("dev").description("Starts the live preview of your environment variables").option(
890
- "-d, --dir <path>",
891
- "Directory with your envin configuration and .env files",
892
- "./"
893
- ).option("-p --port <port>", "Port to run dev server on", "3000").option("-v, --verbose", "Enable verbose logging", false).action(dev);
570
+ //#endregion
571
+ //#region src/cli/index.ts
572
+ program.name("@envin/cli").description("A live preview of your environment variables right in your browser").version(version);
573
+ program.command("dev").description("Starts the live preview of your environment variables").option("-d, --dir <path>", "Directory with your envin configuration and .env files", "./").option("-p --port <port>", "Port to run dev server on", "3000").option("-v, --verbose", "Enable verbose logging", false).action(dev);
894
574
  program.parse();
575
+
576
+ //#endregion
577
+ export { };