@envin/cli 0.0.1 → 1.1.1

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 (51) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +95 -0
  3. package/dist/cli/index.mjs +464 -55
  4. package/dist/preview/.next/BUILD_ID +1 -1
  5. package/dist/preview/.next/app-build-manifest.json +6 -6
  6. package/dist/preview/.next/build-manifest.json +5 -5
  7. package/dist/preview/.next/next-minimal-server.js.nft.json +1 -1
  8. package/dist/preview/.next/next-server.js.nft.json +1 -1
  9. package/dist/preview/.next/prerender-manifest.json +3 -3
  10. package/dist/preview/.next/required-server-files.json +1 -1
  11. package/dist/preview/.next/server/app/_not-found/page.js +1 -1
  12. package/dist/preview/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  13. package/dist/preview/.next/server/app/_not-found.html +1 -1
  14. package/dist/preview/.next/server/app/_not-found.rsc +2 -2
  15. package/dist/preview/.next/server/app/favicon.ico/route.js +1 -1
  16. package/dist/preview/.next/server/app/index.html +1 -1
  17. package/dist/preview/.next/server/app/index.rsc +3 -3
  18. package/dist/preview/.next/server/app/page.js +8 -7
  19. package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -1
  20. package/dist/preview/.next/server/chunks/191.js +10 -10
  21. package/dist/preview/.next/server/chunks/496.js +3 -3
  22. package/dist/preview/.next/server/chunks/601.js +4 -4
  23. package/dist/preview/.next/server/middleware-build-manifest.js +1 -1
  24. package/dist/preview/.next/server/pages/404.html +1 -1
  25. package/dist/preview/.next/server/pages/500.html +1 -1
  26. package/dist/preview/.next/server/pages/_app.js +1 -1
  27. package/dist/preview/.next/server/pages/_document.js +1 -1
  28. package/dist/preview/.next/server/pages/_error.js +1 -1
  29. package/dist/preview/.next/server/server-reference-manifest.js +1 -1
  30. package/dist/preview/.next/server/server-reference-manifest.json +1 -1
  31. package/dist/preview/.next/server/webpack-runtime.js +1 -1
  32. package/dist/preview/.next/static/chunks/985-f32f025f8cdc74d3.js +1 -0
  33. package/dist/preview/.next/static/chunks/app/page-781d5c4076d3b10d.js +1 -0
  34. package/dist/preview/.next/static/chunks/webpack-464ea5083b838c17.js +1 -0
  35. package/dist/preview/.next/static/css/8b2927e38b2520cf.css +3 -0
  36. package/dist/preview/.next/trace +14 -13
  37. package/package.json +17 -6
  38. package/src/app/page.tsx +11 -2
  39. package/src/components/variables/context.tsx +30 -18
  40. package/src/lib/config.ts +1 -18
  41. package/src/lib/hooks/use-hot-reload.ts +31 -0
  42. package/src/lib/types.ts +10 -0
  43. package/src/lib/validate.ts +3 -1
  44. package/src/lib/variables/index.ts +28 -6
  45. package/src/utils/get-config-file.ts +2 -0
  46. package/dist/preview/.next/static/chunks/174-5a80ff32c1746c12.js +0 -1
  47. package/dist/preview/.next/static/chunks/app/page-5dac690b5d4c8e8b.js +0 -1
  48. package/dist/preview/.next/static/chunks/webpack-e84142516ca52ef7.js +0 -1
  49. package/dist/preview/.next/static/css/6842db20c57f3076.css +0 -3
  50. /package/dist/preview/.next/static/{v9TlUn5liPNhAPJYeB3QH → ti02qYR7TtWD2j2orEzoT}/_buildManifest.js +0 -0
  51. /package/dist/preview/.next/static/{v9TlUn5liPNhAPJYeB3QH → ti02qYR7TtWD2j2orEzoT}/_ssgManifest.js +0 -0
@@ -6,7 +6,8 @@ import { program } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@envin/cli",
9
- version: "0.0.1",
9
+ version: "1.1.1",
10
+ description: "Type-safe env validation with live previews",
10
11
  keywords: [
11
12
  "turbostarter",
12
13
  "environment variables",
@@ -15,6 +16,10 @@ var package_default = {
15
16
  "arktype",
16
17
  "valibot"
17
18
  ],
19
+ homepage: "https://envin.turbostarter.dev",
20
+ bugs: {
21
+ url: "https://github.com/turbostarter/envin/issues"
22
+ },
18
23
  repository: {
19
24
  type: "git",
20
25
  url: "git+https://github.com/turbostarter/envin.git",
@@ -32,7 +37,8 @@ var package_default = {
32
37
  dev: "tsup-node --watch",
33
38
  "dev:preview": "cd ../../apps/example && tsx ../../packages/cli/src/cli/index.ts dev",
34
39
  start: "node dist/cli/index.mjs",
35
- typecheck: "tsc --noEmit"
40
+ typecheck: "tsc --noEmit",
41
+ prepack: "bun ../../scripts/replace-workspace-protocol.ts && bun ../../scripts/populate-readme.ts"
36
42
  },
37
43
  dependencies: {
38
44
  "@babel/parser": "^7.27.0",
@@ -47,16 +53,21 @@ var package_default = {
47
53
  "@radix-ui/react-tooltip": "^1.2.4",
48
54
  "@svgr/webpack": "^8.1.0",
49
55
  chalk: "^5.4.1",
56
+ chokidar: "^4.0.3",
50
57
  commander: "^13.1.0",
58
+ debounce: "^2.2.0",
51
59
  dotenv: "^16.5.0",
52
60
  envin: "workspace:*",
53
61
  esbuild: "^0.25.0",
54
62
  "log-symbols": "^7.0.0",
55
63
  "mime-types": "^3.0.1",
56
- next: "^15.3.1",
64
+ next: "^15.3.3",
57
65
  ora: "^8.2.0",
58
66
  "react-hook-form": "^7.56.4",
59
- zod: "^3.25.17"
67
+ "socket.io": "^4.8.1",
68
+ "socket.io-client": "^4.8.1",
69
+ "tsconfig-paths": "^4.2.0",
70
+ zod: "^3.25.56"
60
71
  },
61
72
  devDependencies: {
62
73
  "@babel/core": "7.26.10",
@@ -90,45 +101,17 @@ var package_default = {
90
101
  };
91
102
 
92
103
  // src/cli/commands/dev.ts
93
- import fs2 from "fs";
104
+ import fs3 from "fs";
94
105
 
95
- // src/cli/utils/preview/serve-static-file.ts
96
- import { existsSync, promises as fs } from "fs";
97
- import path from "path";
98
- import { lookup } from "mime-types";
99
- var serveStaticFile = async (res, parsedUrl, staticDirRelativePath) => {
100
- const pathname = parsedUrl.pathname?.replace("/static", "./static") ?? "";
101
- const ext = path.parse(pathname).ext;
102
- const staticBaseDir = path.resolve(process.cwd(), staticDirRelativePath);
103
- const fileAbsolutePath = path.resolve(staticBaseDir, pathname);
104
- if (!fileAbsolutePath.startsWith(staticBaseDir)) {
105
- res.statusCode = 403;
106
- res.end();
107
- return;
108
- }
109
- try {
110
- const fileHandle = await fs.open(fileAbsolutePath, "r");
111
- const fileData = await fs.readFile(fileHandle);
112
- res.setHeader("Content-type", lookup(ext) || "text/plain");
113
- res.end(fileData);
114
- fileHandle.close();
115
- } catch (exception) {
116
- if (!existsSync(fileAbsolutePath)) {
117
- res.statusCode = 404;
118
- res.end();
119
- } else {
120
- const sanitizedFilePath = fileAbsolutePath.replace(/\n|\r/g, "");
121
- console.error(
122
- `Could not read file at ${sanitizedFilePath} to be served, here's the exception:`,
123
- exception
124
- );
125
- res.statusCode = 500;
126
- res.end(
127
- "Could not read file to be served! Check your terminal for more information."
128
- );
129
- }
130
- }
131
- };
106
+ // src/cli/utils/hot-reload/setup-hot-reloading.ts
107
+ import path6 from "path";
108
+ import { watch } from "chokidar";
109
+ import debounce from "debounce";
110
+ import { Server as SocketServer } from "socket.io";
111
+
112
+ // src/cli/utils/hot-reload/create-dependency-graph.ts
113
+ import { existsSync as existsSync2, promises as fs2, statSync } from "fs";
114
+ import path5 from "path";
132
115
 
133
116
  // src/cli/utils/preview/start-dev-server.ts
134
117
  import http from "http";
@@ -165,16 +148,54 @@ var registerSpinnerAutostopping = (spinner) => {
165
148
  };
166
149
 
167
150
  // src/cli/utils/preview/get-env-variables.ts
168
- import path2 from "path";
151
+ import path from "path";
169
152
  var getEnvVariablesForPreviewApp = (relativePathToEnvDirectory, cwd) => {
170
153
  return {
171
154
  ENV_DIR_RELATIVE_PATH: relativePathToEnvDirectory,
172
- ENV_DIR_ABSOLUTE_PATH: path2.resolve(cwd, relativePathToEnvDirectory),
155
+ ENV_DIR_ABSOLUTE_PATH: path.resolve(cwd, relativePathToEnvDirectory),
173
156
  USER_PROJECT_LOCATION: cwd,
174
157
  NEXT_PUBLIC_IS_PREVIEW_DEVELOPMENT: isDev ? "true" : "false"
175
158
  };
176
159
  };
177
160
 
161
+ // src/cli/utils/preview/serve-static-file.ts
162
+ import { existsSync, promises as fs } from "fs";
163
+ import path2 from "path";
164
+ import { lookup } from "mime-types";
165
+ var serveStaticFile = async (res, parsedUrl, staticDirRelativePath) => {
166
+ const pathname = parsedUrl.pathname?.replace("/static", "./static") ?? "";
167
+ const ext = path2.parse(pathname).ext;
168
+ const staticBaseDir = path2.resolve(process.cwd(), staticDirRelativePath);
169
+ const fileAbsolutePath = path2.resolve(staticBaseDir, pathname);
170
+ if (!fileAbsolutePath.startsWith(staticBaseDir)) {
171
+ res.statusCode = 403;
172
+ res.end();
173
+ return;
174
+ }
175
+ try {
176
+ const fileHandle = await fs.open(fileAbsolutePath, "r");
177
+ const fileData = await fs.readFile(fileHandle);
178
+ res.setHeader("Content-type", lookup(ext) || "text/plain");
179
+ res.end(fileData);
180
+ fileHandle.close();
181
+ } catch (exception) {
182
+ if (!existsSync(fileAbsolutePath)) {
183
+ res.statusCode = 404;
184
+ res.end();
185
+ } else {
186
+ const sanitizedFilePath = fileAbsolutePath.replace(/\n|\r/g, "");
187
+ console.error(
188
+ `Could not read file at ${sanitizedFilePath} to be served, here's the exception:`,
189
+ exception
190
+ );
191
+ res.statusCode = 500;
192
+ res.end(
193
+ "Could not read file to be served! Check your terminal for more information."
194
+ );
195
+ }
196
+ }
197
+ };
198
+
178
199
  // src/cli/utils/preview/start-dev-server.ts
179
200
  var devServer;
180
201
  var safeAsyncServerListen = (server, port) => {
@@ -194,7 +215,7 @@ var dirname = path3.dirname(filename);
194
215
  var isDev = !filename.endsWith(path3.join("cli", "index.mjs"));
195
216
  var cliPackageLocation = isDev ? path3.resolve(dirname, "../../../..") : path3.resolve(dirname, "../..");
196
217
  var previewServerLocation = isDev ? path3.resolve(dirname, "../../../..") : path3.resolve(dirname, "../preview");
197
- var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, port) => {
218
+ var startDevServer = async (envDirRelativePath, staticBaseDirRelativePath, port) => {
198
219
  devServer = http.createServer((req, res) => {
199
220
  if (!req.url) {
200
221
  res.end(404);
@@ -234,7 +255,7 @@ var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, po
234
255
  ` ${logSymbols2.warning} Port ${port} is already in use, trying ${nextPortToTry}`
235
256
  );
236
257
  return startDevServer(
237
- emailsDirRelativePath,
258
+ envDirRelativePath,
238
259
  staticBaseDirRelativePath,
239
260
  nextPortToTry
240
261
  );
@@ -259,7 +280,7 @@ var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, po
259
280
  NODE_ENV: "development",
260
281
  ...process.env,
261
282
  ...getEnvVariablesForPreviewApp(
262
- path3.normalize(emailsDirRelativePath),
283
+ path3.normalize(envDirRelativePath),
263
284
  process.cwd()
264
285
  )
265
286
  };
@@ -317,19 +338,403 @@ process.on(
317
338
  makeExitHandler({ shouldKillProcess: true, killWithErrorCode: true })
318
339
  );
319
340
 
341
+ // src/cli/utils/hot-reload/get-imported-modules.ts
342
+ import { parse } from "@babel/parser";
343
+ import traverseModule from "@babel/traverse";
344
+ var traverse = (
345
+ // we keep this check here so that this still works with the dev:preview
346
+ // script's use of tsx
347
+ typeof traverseModule === "function" ? traverseModule : (
348
+ // @ts-expect-error - this is a valid use case
349
+ traverseModule.default
350
+ )
351
+ );
352
+ var getImportedModules = (contents) => {
353
+ const importedPaths = [];
354
+ const parsedContents = parse(contents, {
355
+ sourceType: "unambiguous",
356
+ strictMode: false,
357
+ errorRecovery: true,
358
+ plugins: ["jsx", "typescript", "decorators"]
359
+ });
360
+ traverse(parsedContents, {
361
+ ImportDeclaration({ node }) {
362
+ importedPaths.push(node.source.value);
363
+ },
364
+ ExportAllDeclaration({ node }) {
365
+ importedPaths.push(node.source.value);
366
+ },
367
+ ExportNamedDeclaration({ node }) {
368
+ if (node.source) {
369
+ importedPaths.push(node.source.value);
370
+ }
371
+ },
372
+ TSExternalModuleReference({ node }) {
373
+ importedPaths.push(node.expression.value);
374
+ },
375
+ CallExpression({ node }) {
376
+ if ("name" in node.callee && node.callee.name === "require") {
377
+ if (node.arguments.length === 1) {
378
+ const importPathNode = node.arguments[0];
379
+ if (importPathNode?.type === "StringLiteral") {
380
+ importedPaths.push(importPathNode.value);
381
+ }
382
+ }
383
+ }
384
+ }
385
+ });
386
+ return importedPaths;
387
+ };
388
+
389
+ // src/cli/utils/hot-reload/resolve-path-aliases.ts
390
+ import path4 from "path";
391
+ import { createMatchPath, loadConfig } from "tsconfig-paths";
392
+ var resolvePathAliases = (importPaths, projectPath) => {
393
+ const configLoadResult = loadConfig(projectPath);
394
+ if (configLoadResult.resultType === "success") {
395
+ const matchPath = createMatchPath(
396
+ configLoadResult.absoluteBaseUrl,
397
+ configLoadResult.paths
398
+ );
399
+ return importPaths.map((importedPath) => {
400
+ const unaliasedPath = matchPath(importedPath, void 0, void 0, [
401
+ ".tsx",
402
+ ".ts",
403
+ ".js",
404
+ ".jsx",
405
+ ".cjs",
406
+ ".mjs"
407
+ ]);
408
+ if (unaliasedPath) {
409
+ return `./${path4.relative(projectPath, unaliasedPath)}`;
410
+ }
411
+ return importedPath;
412
+ });
413
+ }
414
+ return importPaths;
415
+ };
416
+
417
+ // src/cli/utils/hot-reload/create-dependency-graph.ts
418
+ var readAllFilesInsideDirectory = async (directory) => {
419
+ let allFilePaths = [];
420
+ const topLevelDirents = await fs2.readdir(directory, { withFileTypes: true });
421
+ for await (const dirent of topLevelDirents) {
422
+ const pathToDirent = path5.join(directory, dirent.name);
423
+ if (dirent.isDirectory()) {
424
+ allFilePaths = allFilePaths.concat(
425
+ await readAllFilesInsideDirectory(pathToDirent)
426
+ );
427
+ } else {
428
+ allFilePaths.push(pathToDirent);
429
+ }
430
+ }
431
+ return allFilePaths;
432
+ };
433
+ var isJavascriptModule = (filePath) => {
434
+ const extensionName = path5.extname(filePath);
435
+ return [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"].includes(extensionName);
436
+ };
437
+ var checkFileExtensionsUntilItExists = (pathWithoutExtension) => {
438
+ if (existsSync2(`${pathWithoutExtension}.ts`)) {
439
+ return `${pathWithoutExtension}.ts`;
440
+ }
441
+ if (existsSync2(`${pathWithoutExtension}.tsx`)) {
442
+ return `${pathWithoutExtension}.tsx`;
443
+ }
444
+ if (existsSync2(`${pathWithoutExtension}.js`)) {
445
+ return `${pathWithoutExtension}.js`;
446
+ }
447
+ if (existsSync2(`${pathWithoutExtension}.jsx`)) {
448
+ return `${pathWithoutExtension}.jsx`;
449
+ }
450
+ if (existsSync2(`${pathWithoutExtension}.mjs`)) {
451
+ return `${pathWithoutExtension}.mjs`;
452
+ }
453
+ if (existsSync2(`${pathWithoutExtension}.cjs`)) {
454
+ return `${pathWithoutExtension}.cjs`;
455
+ }
456
+ };
457
+ var createDependencyGraph = async (directory) => {
458
+ const filePaths = await readAllFilesInsideDirectory(directory);
459
+ const modulePaths = filePaths.filter(isJavascriptModule);
460
+ const graph = Object.fromEntries(
461
+ modulePaths.map((path7) => [
462
+ path7,
463
+ {
464
+ path: path7,
465
+ dependencyPaths: [],
466
+ dependentPaths: [],
467
+ moduleDependencies: []
468
+ }
469
+ ])
470
+ );
471
+ const getDependencyPaths = async (filePath) => {
472
+ const contents = await fs2.readFile(filePath, "utf8");
473
+ const importedPaths = isJavascriptModule(filePath) ? resolvePathAliases(getImportedModules(contents), path5.dirname(filePath)) : [];
474
+ const importedPathsRelativeToDirectory = importedPaths.map(
475
+ (dependencyPath) => {
476
+ const isModulePath = !dependencyPath.startsWith(".");
477
+ if (isModulePath || path5.isAbsolute(dependencyPath)) {
478
+ return dependencyPath;
479
+ }
480
+ let pathToDependencyFromDirectory = path5.resolve(
481
+ /*
482
+ path.resolve resolves paths differently from what imports on javascript do.
483
+
484
+ So if we wouldn't do this, for an email at "/path/to/email.tsx" with a dependency path of "./other-email"
485
+ would end up going into /path/to/email.tsx/other-email instead of /path/to/other-email which is the
486
+ one the import is meant to go to
487
+ */
488
+ path5.dirname(filePath),
489
+ dependencyPath
490
+ );
491
+ let isDirectory = false;
492
+ try {
493
+ isDirectory = statSync(pathToDependencyFromDirectory).isDirectory();
494
+ } catch (_) {
495
+ }
496
+ if (isDirectory) {
497
+ const pathToSubDirectory = pathToDependencyFromDirectory;
498
+ const pathWithExtension = checkFileExtensionsUntilItExists(
499
+ `${pathToSubDirectory}/index`
500
+ );
501
+ if (pathWithExtension) {
502
+ pathToDependencyFromDirectory = pathWithExtension;
503
+ } else if (isDev) {
504
+ console.warn(
505
+ `Could not find index file for directory at ${pathToDependencyFromDirectory}. This is probably going to cause issues with both hot reloading and your code.`
506
+ );
507
+ }
508
+ }
509
+ const extension = path5.extname(pathToDependencyFromDirectory);
510
+ const pathWithEnsuredExtension = (() => {
511
+ if (extension.length > 0 && existsSync2(pathToDependencyFromDirectory)) {
512
+ return pathToDependencyFromDirectory;
513
+ }
514
+ return checkFileExtensionsUntilItExists(
515
+ pathToDependencyFromDirectory.replace(extension, "")
516
+ );
517
+ })();
518
+ if (pathWithEnsuredExtension) {
519
+ pathToDependencyFromDirectory = pathWithEnsuredExtension;
520
+ } else if (isDev) {
521
+ console.warn(
522
+ `Could not find file at ${pathToDependencyFromDirectory}`
523
+ );
524
+ }
525
+ return pathToDependencyFromDirectory;
526
+ }
527
+ );
528
+ const moduleDependencies = importedPathsRelativeToDirectory.filter(
529
+ (dependencyPath) => !dependencyPath.startsWith(".") && !path5.isAbsolute(dependencyPath)
530
+ );
531
+ const nonNodeModuleImportPathsRelativeToDirectory = importedPathsRelativeToDirectory.filter(
532
+ (dependencyPath) => dependencyPath.startsWith(".") || path5.isAbsolute(dependencyPath)
533
+ );
534
+ return {
535
+ dependencyPaths: nonNodeModuleImportPathsRelativeToDirectory,
536
+ moduleDependencies
537
+ };
538
+ };
539
+ const updateModuleDependenciesInGraph = async (moduleFilePath) => {
540
+ if (graph[moduleFilePath] === void 0) {
541
+ graph[moduleFilePath] = {
542
+ path: moduleFilePath,
543
+ dependencyPaths: [],
544
+ dependentPaths: [],
545
+ moduleDependencies: []
546
+ };
547
+ }
548
+ const { moduleDependencies, dependencyPaths: newDependencyPaths } = await getDependencyPaths(moduleFilePath);
549
+ graph[moduleFilePath].moduleDependencies = moduleDependencies;
550
+ for (const dependencyPath of graph[moduleFilePath].dependencyPaths) {
551
+ if (newDependencyPaths.includes(dependencyPath)) continue;
552
+ const dependencyModule = graph[dependencyPath];
553
+ if (dependencyModule !== void 0) {
554
+ dependencyModule.dependentPaths = dependencyModule.dependentPaths.filter(
555
+ (dependentPath) => dependentPath !== moduleFilePath
556
+ );
557
+ }
558
+ }
559
+ graph[moduleFilePath].dependencyPaths = newDependencyPaths;
560
+ for await (const dependencyPath of newDependencyPaths) {
561
+ if (graph[dependencyPath] === void 0) {
562
+ await updateModuleDependenciesInGraph(dependencyPath);
563
+ }
564
+ const dependencyModule = graph[dependencyPath];
565
+ if (dependencyModule === void 0) {
566
+ throw new Error(
567
+ `Loading the dependency path ${dependencyPath} did not initialize it at all. This is a bug in React Email.`
568
+ );
569
+ }
570
+ if (!dependencyModule.dependentPaths.includes(moduleFilePath)) {
571
+ dependencyModule.dependentPaths.push(moduleFilePath);
572
+ }
573
+ }
574
+ };
575
+ const removeModuleFromGraph = (filePath) => {
576
+ const module = graph[filePath];
577
+ if (module) {
578
+ for (const dependencyPath of module.dependencyPaths) {
579
+ if (graph[dependencyPath]) {
580
+ graph[dependencyPath].dependentPaths = graph[dependencyPath].dependentPaths.filter(
581
+ (dependentPath) => dependentPath !== filePath
582
+ );
583
+ }
584
+ }
585
+ delete graph[filePath];
586
+ }
587
+ };
588
+ return [
589
+ graph,
590
+ async (event, pathToModified) => {
591
+ switch (event) {
592
+ case "change":
593
+ if (isJavascriptModule(pathToModified)) {
594
+ await updateModuleDependenciesInGraph(pathToModified);
595
+ }
596
+ break;
597
+ case "add":
598
+ if (isJavascriptModule(pathToModified)) {
599
+ await updateModuleDependenciesInGraph(pathToModified);
600
+ }
601
+ break;
602
+ case "addDir": {
603
+ const filesInsideAddedDirectory = await readAllFilesInsideDirectory(pathToModified);
604
+ const modulesInsideAddedDirectory = filesInsideAddedDirectory.filter(isJavascriptModule);
605
+ for await (const filePath of modulesInsideAddedDirectory) {
606
+ await updateModuleDependenciesInGraph(filePath);
607
+ }
608
+ break;
609
+ }
610
+ case "unlink":
611
+ if (isJavascriptModule(pathToModified)) {
612
+ removeModuleFromGraph(pathToModified);
613
+ }
614
+ break;
615
+ case "unlinkDir": {
616
+ const filesInsideDeletedDirectory = await readAllFilesInsideDirectory(pathToModified);
617
+ const modulesInsideDeletedDirectory = filesInsideDeletedDirectory.filter(isJavascriptModule);
618
+ for await (const filePath of modulesInsideDeletedDirectory) {
619
+ removeModuleFromGraph(filePath);
620
+ }
621
+ break;
622
+ }
623
+ }
624
+ },
625
+ {
626
+ resolveDependentsOf: function resolveDependentsOf(pathToModule) {
627
+ const moduleEntry = graph[pathToModule];
628
+ const dependentPaths = [];
629
+ if (moduleEntry) {
630
+ for (const dependentPath of moduleEntry.dependentPaths) {
631
+ const dependentsOfDependent = resolveDependentsOf(dependentPath);
632
+ dependentPaths.push(...dependentsOfDependent);
633
+ dependentPaths.push(dependentPath);
634
+ }
635
+ }
636
+ return dependentPaths;
637
+ }
638
+ }
639
+ ];
640
+ };
641
+
642
+ // src/cli/utils/hot-reload/setup-hot-reloading.ts
643
+ var setupHotreloading = async (devServer2, envDirRelativePath) => {
644
+ let clients = [];
645
+ const io = new SocketServer(devServer2);
646
+ io.on("connection", (client) => {
647
+ clients.push(client);
648
+ client.on("disconnect", () => {
649
+ clients = clients.filter((item) => item !== client);
650
+ });
651
+ });
652
+ let changes = [];
653
+ const reload = debounce(() => {
654
+ clients.forEach((client) => {
655
+ client.emit(
656
+ "reload",
657
+ changes.filter(
658
+ (change) => (
659
+ // Ensures only changes inside the emails directory are emitted
660
+ path6.resolve(absolutePathToEnvDirectory, change.filename).startsWith(absolutePathToEnvDirectory)
661
+ )
662
+ )
663
+ );
664
+ });
665
+ changes = [];
666
+ }, 150);
667
+ const absolutePathToEnvDirectory = path6.resolve(
668
+ process.cwd(),
669
+ envDirRelativePath
670
+ );
671
+ const [dependencyGraph, updateDependencyGraph, { resolveDependentsOf }] = await createDependencyGraph(absolutePathToEnvDirectory);
672
+ const watcher = watch("", {
673
+ ignoreInitial: true,
674
+ cwd: absolutePathToEnvDirectory
675
+ });
676
+ const getFilesOutsideEnvDirectory = () => Object.keys(dependencyGraph).filter(
677
+ (p) => path6.relative(absolutePathToEnvDirectory, p).startsWith("..")
678
+ );
679
+ let filesOutsideEnvDirectory = getFilesOutsideEnvDirectory();
680
+ for (const p of filesOutsideEnvDirectory) {
681
+ watcher.add(p);
682
+ }
683
+ const exit = async () => {
684
+ await watcher.close();
685
+ };
686
+ process.on("SIGINT", exit);
687
+ process.on("uncaughtException", exit);
688
+ watcher.on("all", async (event, relativePathToChangeTarget) => {
689
+ const file = relativePathToChangeTarget.split(path6.sep);
690
+ if (file.length === 0) {
691
+ return;
692
+ }
693
+ const pathToChangeTarget = path6.resolve(
694
+ absolutePathToEnvDirectory,
695
+ relativePathToChangeTarget
696
+ );
697
+ await updateDependencyGraph(event, pathToChangeTarget);
698
+ const newFilesOutsideEnvDirectory = getFilesOutsideEnvDirectory();
699
+ for (const p of filesOutsideEnvDirectory) {
700
+ if (!newFilesOutsideEnvDirectory.includes(p)) {
701
+ watcher.unwatch(p);
702
+ }
703
+ }
704
+ for (const p of newFilesOutsideEnvDirectory) {
705
+ if (!filesOutsideEnvDirectory.includes(p)) {
706
+ watcher.add(p);
707
+ }
708
+ }
709
+ filesOutsideEnvDirectory = newFilesOutsideEnvDirectory;
710
+ changes.push({
711
+ event,
712
+ filename: relativePathToChangeTarget
713
+ });
714
+ for (const dependentPath of resolveDependentsOf(pathToChangeTarget)) {
715
+ changes.push({
716
+ event: "change",
717
+ filename: path6.relative(absolutePathToEnvDirectory, dependentPath)
718
+ });
719
+ }
720
+ reload();
721
+ });
722
+ return watcher;
723
+ };
724
+
320
725
  // src/cli/commands/dev.ts
321
- var dev = async ({ dir: emailsDirRelativePath, port }) => {
726
+ var dev = async ({ dir: envDirRelativePath, port }) => {
322
727
  try {
323
- if (!fs2.existsSync(emailsDirRelativePath)) {
324
- console.error(`Missing ${emailsDirRelativePath} folder`);
728
+ if (!fs3.existsSync(envDirRelativePath)) {
729
+ console.error(`Missing ${envDirRelativePath} folder`);
325
730
  process.exit(1);
326
731
  }
327
- const _devServer = await startDevServer(
328
- emailsDirRelativePath,
329
- emailsDirRelativePath,
330
- // defaults to ./emails/static for the static files that are served to the preview
732
+ const devServer2 = await startDevServer(
733
+ envDirRelativePath,
734
+ envDirRelativePath,
331
735
  Number.parseInt(port)
332
736
  );
737
+ await setupHotreloading(devServer2, envDirRelativePath);
333
738
  } catch (error) {
334
739
  console.log(error);
335
740
  process.exit(1);
@@ -341,5 +746,9 @@ var PACKAGE_NAME = "@envin/cli";
341
746
  program.name(PACKAGE_NAME).description(
342
747
  "A live preview of your environment variables right in your browser"
343
748
  ).version(package_default.version);
344
- program.command("dev").description("Starts the live preview of your environment variables").option("-d, --dir <path>", "Directory with your email templates", "./").option("-p --port <port>", "Port to run dev server on", "3000").action(dev);
749
+ program.command("dev").description("Starts the live preview of your environment variables").option(
750
+ "-d, --dir <path>",
751
+ "Directory with your envin configuration and .env files",
752
+ "./"
753
+ ).option("-p --port <port>", "Port to run dev server on", "3000").action(dev);
345
754
  program.parse();
@@ -1 +1 @@
1
- v9TlUn5liPNhAPJYeB3QH
1
+ ti02qYR7TtWD2j2orEzoT
@@ -1,27 +1,27 @@
1
1
  {
2
2
  "pages": {
3
3
  "/_not-found/page": [
4
- "static/chunks/webpack-e84142516ca52ef7.js",
4
+ "static/chunks/webpack-464ea5083b838c17.js",
5
5
  "static/chunks/87c73c54-a773d57d245aca41.js",
6
6
  "static/chunks/315-850927f416f0524a.js",
7
7
  "static/chunks/main-app-fd962d6f95339794.js",
8
8
  "static/chunks/app/_not-found/page-60c07ed561e86dd9.js"
9
9
  ],
10
10
  "/layout": [
11
- "static/chunks/webpack-e84142516ca52ef7.js",
11
+ "static/chunks/webpack-464ea5083b838c17.js",
12
12
  "static/chunks/87c73c54-a773d57d245aca41.js",
13
13
  "static/chunks/315-850927f416f0524a.js",
14
14
  "static/chunks/main-app-fd962d6f95339794.js",
15
- "static/css/6842db20c57f3076.css",
15
+ "static/css/8b2927e38b2520cf.css",
16
16
  "static/chunks/app/layout-199c3536e64e10fd.js"
17
17
  ],
18
18
  "/page": [
19
- "static/chunks/webpack-e84142516ca52ef7.js",
19
+ "static/chunks/webpack-464ea5083b838c17.js",
20
20
  "static/chunks/87c73c54-a773d57d245aca41.js",
21
21
  "static/chunks/315-850927f416f0524a.js",
22
22
  "static/chunks/main-app-fd962d6f95339794.js",
23
- "static/chunks/174-5a80ff32c1746c12.js",
24
- "static/chunks/app/page-5dac690b5d4c8e8b.js"
23
+ "static/chunks/985-f32f025f8cdc74d3.js",
24
+ "static/chunks/app/page-781d5c4076d3b10d.js"
25
25
  ]
26
26
  }
27
27
  }
@@ -5,11 +5,11 @@
5
5
  "devFiles": [],
6
6
  "ampDevFiles": [],
7
7
  "lowPriorityFiles": [
8
- "static/v9TlUn5liPNhAPJYeB3QH/_buildManifest.js",
9
- "static/v9TlUn5liPNhAPJYeB3QH/_ssgManifest.js"
8
+ "static/ti02qYR7TtWD2j2orEzoT/_buildManifest.js",
9
+ "static/ti02qYR7TtWD2j2orEzoT/_ssgManifest.js"
10
10
  ],
11
11
  "rootMainFiles": [
12
- "static/chunks/webpack-e84142516ca52ef7.js",
12
+ "static/chunks/webpack-464ea5083b838c17.js",
13
13
  "static/chunks/87c73c54-a773d57d245aca41.js",
14
14
  "static/chunks/315-850927f416f0524a.js",
15
15
  "static/chunks/main-app-fd962d6f95339794.js"
@@ -17,13 +17,13 @@
17
17
  "rootMainFilesTree": {},
18
18
  "pages": {
19
19
  "/_app": [
20
- "static/chunks/webpack-e84142516ca52ef7.js",
20
+ "static/chunks/webpack-464ea5083b838c17.js",
21
21
  "static/chunks/framework-82b0332477a76245.js",
22
22
  "static/chunks/main-c9e901861bf9798e.js",
23
23
  "static/chunks/pages/_app-a48f070af90c9683.js"
24
24
  ],
25
25
  "/_error": [
26
- "static/chunks/webpack-e84142516ca52ef7.js",
26
+ "static/chunks/webpack-464ea5083b838c17.js",
27
27
  "static/chunks/framework-82b0332477a76245.js",
28
28
  "static/chunks/main-c9e901861bf9798e.js",
29
29
  "static/chunks/pages/_error-b8c2e08355edc3b4.js"