#!/usr/bin/env node
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
  if (typeof require !== "undefined")
    return require.apply(this, arguments);
  throw Error('Dynamic require of "' + x + '" is not supported');
});

// src/cli/index.ts
import { program } from "commander";

// package.json
var package_default = {
  name: "react-email",
  version: "4.1.0-canary.2",
  description: "A live preview of your emails right in your browser.",
  bin: {
    email: "./dist/cli/index.js"
  },
  scripts: {
    build: "tsup-node && node ./scripts/build-preview-server.mjs && pnpm install --frozen-lockfile",
    "caniemail:fetch": "node ./scripts/fill-caniemail-data.mjs",
    clean: "rm -rf dist",
    dev: "tsup-node --watch",
    "dev:preview": "cd ../../apps/demo && tsx ../../packages/react-email/src/cli/index.ts dev",
    test: "vitest run",
    "test:watch": "vitest"
  },
  license: "MIT",
  repository: {
    type: "git",
    url: "https://github.com/resend/react-email.git",
    directory: "packages/react-email"
  },
  keywords: ["react", "email"],
  engines: {
    node: ">=18.0.0"
  },
  dependencies: {
    "@babel/parser": "^7.24.5",
    "@babel/traverse": "^7.25.6",
    chalk: "^4.1.2",
    chokidar: "^4.0.3",
    commander: "^11.1.0",
    debounce: "^2.0.0",
    esbuild: "^0.25.0",
    glob: "^10.3.4",
    "log-symbols": "^4.1.0",
    "mime-types": "^2.1.35",
    next: "^15.2.4",
    "normalize-path": "^3.0.0",
    ora: "^5.4.1",
    "socket.io": "^4.8.1"
  },
  devDependencies: {
    "@babel/core": "7.26.10",
    "@lottiefiles/dotlottie-react": "0.12.3",
    "@radix-ui/colors": "1.0.1",
    "@radix-ui/react-collapsible": "1.1.0",
    "@radix-ui/react-dropdown-menu": "2.1.4",
    "@radix-ui/react-popover": "1.1.1",
    "@radix-ui/react-slot": "1.1.0",
    "@radix-ui/react-tabs": "1.1.1",
    "@radix-ui/react-toggle-group": "1.1.0",
    "@radix-ui/react-tooltip": "1.1.2",
    "@react-email/components": "workspace:*",
    "@swc/core": "1.4.15",
    "@types/babel__core": "7.20.5",
    "@types/babel__traverse": "*",
    "@types/fs-extra": "11.0.1",
    "@types/mime-types": "2.1.4",
    "@types/node": "22.10.2",
    "@types/normalize-path": "3.0.2",
    "@types/react": "19.0.10",
    "@types/react-dom": "19.0.4",
    "@types/webpack": "5.28.5",
    "@vercel/style-guide": "5.1.0",
    autoprefixer: "10.4.20",
    clsx: "2.1.1",
    "framer-motion": "12.0.0-alpha.2",
    jiti: "2.4.2",
    json5: "2.2.3",
    "module-punycode": "npm:punycode@2.3.1",
    "node-html-parser": "6.1.13",
    postcss: "8.4.40",
    "prettier-plugin-tailwindcss": "0.6.6",
    "pretty-bytes": "6.1.1",
    "prism-react-renderer": "2.1.0",
    react: "19.0.0",
    "react-dom": "19.0.0",
    sharp: "0.33.3",
    "socket.io-client": "4.8.0",
    sonner: "1.7.1",
    "source-map-js": "1.0.2",
    spamc: "0.0.5",
    "stacktrace-parser": "0.1.10",
    "tailwind-merge": "2.2.0",
    tailwindcss: "3.4.0",
    tsup: "7.2.0",
    tsx: "4.9.0",
    typescript: "5.8.2",
    "use-debounce": "10.0.4",
    zod: "3.24.2"
  }
};

// src/cli/commands/build.ts
import { spawn } from "node:child_process";
import fs5 from "node:fs";
import path8 from "node:path";
import logSymbols3 from "log-symbols";
import ora2 from "ora";

// src/utils/get-emails-directory-metadata.ts
import fs from "node:fs";
import path from "node:path";
var isFileAnEmail = (fullPath) => {
  const stat = fs.statSync(fullPath);
  if (stat.isDirectory())
    return false;
  const { ext } = path.parse(fullPath);
  if (![".js", ".tsx", ".jsx"].includes(ext))
    return false;
  if (!fs.existsSync(fullPath)) {
    return false;
  }
  const fileContents = fs.readFileSync(fullPath, "utf8");
  const hasES6DefaultExport = /\bexport\s+default\b/gm.test(fileContents);
  const hasCommonJSExport = /\bmodule\.exports\s*=/gm.test(fileContents);
  const hasNamedExport = /\bexport\s+\{[^}]*\bdefault\b[^}]*\}/gm.test(
    fileContents
  );
  return hasES6DefaultExport || hasCommonJSExport || hasNamedExport;
};
var mergeDirectoriesWithSubDirectories = (emailsDirectoryMetadata) => {
  let currentResultingMergedDirectory = emailsDirectoryMetadata;
  while (currentResultingMergedDirectory.emailFilenames.length === 0 && currentResultingMergedDirectory.subDirectories.length === 1) {
    const onlySubDirectory = currentResultingMergedDirectory.subDirectories[0];
    currentResultingMergedDirectory = {
      ...onlySubDirectory,
      directoryName: path.join(
        currentResultingMergedDirectory.directoryName,
        onlySubDirectory.directoryName
      )
    };
  }
  return currentResultingMergedDirectory;
};
var getEmailsDirectoryMetadata = async (absolutePathToEmailsDirectory, keepFileExtensions = false, isSubDirectory = false, baseDirectoryPath = absolutePathToEmailsDirectory) => {
  if (!fs.existsSync(absolutePathToEmailsDirectory))
    return;
  const dirents = await fs.promises.readdir(absolutePathToEmailsDirectory, {
    withFileTypes: true
  });
  const emailFilenames = dirents.filter(
    (dirent) => isFileAnEmail(path.join(absolutePathToEmailsDirectory, dirent.name))
  ).map(
    (dirent) => keepFileExtensions ? dirent.name : dirent.name.replace(path.extname(dirent.name), "")
  );
  const subDirectories = await Promise.all(
    dirents.filter(
      (dirent) => dirent.isDirectory() && !dirent.name.startsWith("_") && dirent.name !== "static"
    ).map((dirent) => {
      const direntAbsolutePath = path.join(
        absolutePathToEmailsDirectory,
        dirent.name
      );
      return getEmailsDirectoryMetadata(
        direntAbsolutePath,
        keepFileExtensions,
        true,
        baseDirectoryPath
      );
    })
  );
  const emailsMetadata = {
    absolutePath: absolutePathToEmailsDirectory,
    relativePath: path.relative(
      baseDirectoryPath,
      absolutePathToEmailsDirectory
    ),
    directoryName: absolutePathToEmailsDirectory.split(path.sep).pop(),
    emailFilenames,
    subDirectories
  };
  return isSubDirectory ? mergeDirectoriesWithSubDirectories(emailsMetadata) : emailsMetadata;
};

// src/utils/register-spinner-autostopping.ts
import logSymbols from "log-symbols";
var spinners = /* @__PURE__ */ new Set();
process.on("SIGINT", () => {
  spinners.forEach((spinner) => {
    if (spinner.isSpinning) {
      spinner.stop();
    }
  });
});
process.on("exit", (code) => {
  if (code !== 0) {
    spinners.forEach((spinner) => {
      if (spinner.isSpinning) {
        spinner.stopAndPersist({
          symbol: logSymbols.error
        });
      }
    });
  }
});
var registerSpinnerAutostopping = (spinner) => {
  spinners.add(spinner);
};

// src/cli/utils/tree.ts
import { promises as fs2 } from "node:fs";
import os from "node:os";
import path2 from "node:path";
var SYMBOLS = {
  BRANCH: "\u251C\u2500\u2500 ",
  EMPTY: "",
  INDENT: "    ",
  LAST_BRANCH: "\u2514\u2500\u2500 ",
  VERTICAL: "\u2502   "
};
var getTreeLines = async (dirPath, depth, currentDepth = 0) => {
  const base = process.cwd();
  const dirFullpath = path2.resolve(base, dirPath);
  const dirname = path2.basename(dirFullpath);
  let lines = [dirname];
  const dirStat = await fs2.stat(dirFullpath);
  if (dirStat.isDirectory() && currentDepth < depth) {
    const childDirents = await fs2.readdir(dirFullpath, { withFileTypes: true });
    childDirents.sort((a, b) => {
      if (a.isDirectory() && b.isFile()) {
        return -1;
      }
      if (a.isFile() && b.isDirectory()) {
        return 1;
      }
      return b.name > a.name ? -1 : 1;
    });
    for (let i = 0; i < childDirents.length; i++) {
      const dirent = childDirents[i];
      const isLast = i === childDirents.length - 1;
      const branchingSymbol = isLast ? SYMBOLS.LAST_BRANCH : SYMBOLS.BRANCH;
      const verticalSymbol = isLast ? SYMBOLS.INDENT : SYMBOLS.VERTICAL;
      if (dirent.isFile()) {
        lines.push(`${branchingSymbol}${dirent.name}`);
      } else {
        const pathToDirectory = path2.join(dirFullpath, dirent.name);
        const treeLinesForSubDirectory = await getTreeLines(
          pathToDirectory,
          depth,
          currentDepth + 1
        );
        lines = lines.concat(
          treeLinesForSubDirectory.map(
            (line, index) => index === 0 ? `${branchingSymbol}${line}` : `${verticalSymbol}${line}`
          )
        );
      }
    }
  }
  return lines;
};
var tree = async (dirPath, depth) => {
  const lines = await getTreeLines(dirPath, depth);
  return lines.join(os.EOL);
};

// src/cli/utils/preview/hot-reloading/setup-hot-reloading.ts
import path7 from "node:path";
import { watch } from "chokidar";
import debounce from "debounce";
import { Server as SocketServer } from "socket.io";

// src/cli/utils/preview/hot-reloading/create-dependency-graph.ts
import { promises as fs4, existsSync as existsSync2, statSync } from "node:fs";
import path6 from "node:path";

// src/cli/utils/preview/start-dev-server.ts
import http from "node:http";
import path5 from "node:path";
import url from "node:url";
import chalk from "chalk";
import logSymbols2 from "log-symbols";
import next from "next";
import ora from "ora";

// src/cli/utils/preview/get-env-variables-for-preview-app.ts
import path3 from "node:path";
var getEnvVariablesForPreviewApp = (relativePathToEmailsDirectory, cwd) => {
  return {
    EMAILS_DIR_RELATIVE_PATH: relativePathToEmailsDirectory,
    EMAILS_DIR_ABSOLUTE_PATH: path3.resolve(cwd, relativePathToEmailsDirectory),
    USER_PROJECT_LOCATION: cwd,
    NEXT_PUBLIC_IS_PREVIEW_DEVELOPMENT: isDev ? "true" : "false"
  };
};

// src/cli/utils/preview/serve-static-file.ts
import { promises as fs3, existsSync } from "node:fs";
import path4 from "node:path";
import { lookup } from "mime-types";
var serveStaticFile = async (res, parsedUrl, staticDirRelativePath) => {
  const staticBaseDir = path4.join(process.cwd(), staticDirRelativePath);
  const pathname = parsedUrl.pathname;
  const ext = path4.parse(pathname).ext;
  const fileAbsolutePath = path4.join(staticBaseDir, pathname);
  try {
    const fileHandle = await fs3.open(fileAbsolutePath, "r");
    const fileData = await fs3.readFile(fileHandle);
    res.setHeader("Content-type", lookup(ext) || "text/plain");
    res.end(fileData);
    fileHandle.close();
  } catch (exception) {
    if (!existsSync(fileAbsolutePath)) {
      res.statusCode = 404;
      res.end();
    } else {
      const sanitizedFilePath = fileAbsolutePath.replace(/\n|\r/g, "");
      console.error(
        `Could not read file at ${sanitizedFilePath} to be served, here's the exception:`,
        exception
      );
      res.statusCode = 500;
      res.end(
        "Could not read file to be served! Check your terminal for more information."
      );
    }
  }
};

// src/cli/utils/preview/start-dev-server.ts
var devServer;
var safeAsyncServerListen = (server, port) => {
  return new Promise((resolve) => {
    server.listen(port, () => {
      resolve({ portAlreadyInUse: false });
    });
    server.on("error", (e) => {
      if (e.code === "EADDRINUSE") {
        resolve({ portAlreadyInUse: true });
      }
    });
  });
};
var isDev = !__filename.endsWith(path5.join("cli", "index.js"));
var cliPackageLocation = isDev ? path5.resolve(__dirname, "../../../..") : path5.resolve(__dirname, "../..");
var previewServerLocation = isDev ? path5.resolve(__dirname, "../../../..") : path5.resolve(__dirname, "../preview");
var startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, port) => {
  devServer = http.createServer((req, res) => {
    if (!req.url) {
      res.end(404);
      return;
    }
    const parsedUrl = url.parse(req.url, true);
    res.setHeader(
      "Cache-Control",
      "no-cache, max-age=0, must-revalidate, no-store"
    );
    res.setHeader("Pragma", "no-cache");
    res.setHeader("Expires", "-1");
    try {
      if (parsedUrl.path?.includes("static/") && !parsedUrl.path.includes("_next/static/")) {
        void serveStaticFile(res, parsedUrl, staticBaseDirRelativePath);
      } else if (!isNextReady) {
        void nextReadyPromise.then(
          () => nextHandleRequest?.(req, res, parsedUrl)
        );
      } else {
        void nextHandleRequest?.(req, res, parsedUrl);
      }
    } catch (e) {
      console.error("caught error", e);
      res.writeHead(500);
      res.end();
    }
  });
  const { portAlreadyInUse } = await safeAsyncServerListen(devServer, port);
  if (!portAlreadyInUse) {
    console.log(chalk.greenBright(`    React Email ${package_default.version}`));
    console.log(`    Running preview at:          http://localhost:${port}
`);
  } else {
    const nextPortToTry = port + 1;
    console.warn(
      ` ${logSymbols2.warning} Port ${port} is already in use, trying ${nextPortToTry}`
    );
    return startDevServer(
      emailsDirRelativePath,
      staticBaseDirRelativePath,
      nextPortToTry
    );
  }
  devServer.on("close", async () => {
    await app.close();
  });
  devServer.on("error", (e) => {
    console.error(
      ` ${logSymbols2.error} preview server error: `,
      JSON.stringify(e)
    );
    process.exit(1);
  });
  const spinner = ora({
    text: "Getting react-email preview server ready...\n",
    prefixText: " "
  }).start();
  registerSpinnerAutostopping(spinner);
  const timeBeforeNextReady = performance.now();
  process.env = {
    NODE_ENV: "development",
    ...process.env,
    ...getEnvVariablesForPreviewApp(
      // If we don't do normalization here, stuff like https://github.com/resend/react-email/issues/1354 happens.
      path5.normalize(emailsDirRelativePath),
      process.cwd()
    )
  };
  const app = next({
    // passing in env here does not get the environment variables there
    dev: isDev,
    conf: {
      images: {
        // This is to avoid the warning with sharp
        unoptimized: true
      }
    },
    hostname: "localhost",
    port,
    dir: previewServerLocation
  });
  let isNextReady = false;
  const nextReadyPromise = app.prepare();
  await nextReadyPromise;
  isNextReady = true;
  const nextHandleRequest = app.getRequestHandler();
  const secondsToNextReady = ((performance.now() - timeBeforeNextReady) / 1e3).toFixed(1);
  spinner.stopAndPersist({
    text: `Ready in ${secondsToNextReady}s
`,
    symbol: logSymbols2.success
  });
  return devServer;
};
var makeExitHandler = (options) => (_codeOrSignal) => {
  if (typeof devServer !== "undefined") {
    console.log("\nshutting down dev server");
    devServer.close();
    devServer = void 0;
  }
  if (options?.shouldKillProcess) {
    process.exit(options.killWithErrorCode ? 1 : 0);
  }
};
process.on("exit", makeExitHandler());
process.on(
  "SIGINT",
  makeExitHandler({ shouldKillProcess: true, killWithErrorCode: false })
);
process.on(
  "SIGUSR1",
  makeExitHandler({ shouldKillProcess: true, killWithErrorCode: false })
);
process.on(
  "SIGUSR2",
  makeExitHandler({ shouldKillProcess: true, killWithErrorCode: false })
);
process.on(
  "uncaughtException",
  makeExitHandler({ shouldKillProcess: true, killWithErrorCode: true })
);

// src/cli/utils/preview/hot-reloading/get-imported-modules.ts
import { parse } from "@babel/parser";
import traverse from "@babel/traverse";
var getImportedModules = (contents) => {
  const importedPaths = [];
  const parsedContents = parse(contents, {
    sourceType: "unambiguous",
    strictMode: false,
    errorRecovery: true,
    plugins: ["jsx", "typescript", "decorators"]
  });
  traverse(parsedContents, {
    ImportDeclaration({ node }) {
      importedPaths.push(node.source.value);
    },
    ExportAllDeclaration({ node }) {
      importedPaths.push(node.source.value);
    },
    ExportNamedDeclaration({ node }) {
      if (node.source) {
        importedPaths.push(node.source.value);
      }
    },
    CallExpression({ node }) {
      if ("name" in node.callee && node.callee.name === "require") {
        if (node.arguments.length === 1) {
          const importPathNode = node.arguments[0];
          if (importPathNode.type === "StringLiteral") {
            importedPaths.push(importPathNode.value);
          }
        }
      }
    }
  });
  return importedPaths;
};

// src/cli/utils/preview/hot-reloading/create-dependency-graph.ts
var readAllFilesInsideDirectory = async (directory) => {
  let allFilePaths = [];
  const topLevelDirents = await fs4.readdir(directory, { withFileTypes: true });
  for await (const dirent of topLevelDirents) {
    const pathToDirent = path6.join(directory, dirent.name);
    if (dirent.isDirectory()) {
      allFilePaths = allFilePaths.concat(
        await readAllFilesInsideDirectory(pathToDirent)
      );
    } else {
      allFilePaths.push(pathToDirent);
    }
  }
  return allFilePaths;
};
var isJavascriptModule = (filePath) => {
  const extensionName = path6.extname(filePath);
  return [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"].includes(extensionName);
};
var checkFileExtensionsUntilItExists = (pathWithoutExtension) => {
  if (existsSync2(`${pathWithoutExtension}.ts`)) {
    return `${pathWithoutExtension}.ts`;
  }
  if (existsSync2(`${pathWithoutExtension}.tsx`)) {
    return `${pathWithoutExtension}.tsx`;
  }
  if (existsSync2(`${pathWithoutExtension}.js`)) {
    return `${pathWithoutExtension}.js`;
  }
  if (existsSync2(`${pathWithoutExtension}.jsx`)) {
    return `${pathWithoutExtension}.jsx`;
  }
  if (existsSync2(`${pathWithoutExtension}.mjs`)) {
    return `${pathWithoutExtension}.mjs`;
  }
  if (existsSync2(`${pathWithoutExtension}.cjs`)) {
    return `${pathWithoutExtension}.cjs`;
  }
};
var createDependencyGraph = async (directory) => {
  const filePaths = await readAllFilesInsideDirectory(directory);
  const modulePaths = filePaths.filter(isJavascriptModule);
  const graph = Object.fromEntries(
    modulePaths.map((path12) => [
      path12,
      {
        path: path12,
        dependencyPaths: [],
        dependentPaths: [],
        moduleDependencies: []
      }
    ])
  );
  const getDependencyPaths = async (filePath) => {
    const contents = await fs4.readFile(filePath, "utf8");
    const importedPaths = getImportedModules(contents);
    const importedPathsRelativeToDirectory = importedPaths.map(
      (dependencyPath) => {
        const isModulePath = !dependencyPath.startsWith(".");
        if (isModulePath || path6.isAbsolute(dependencyPath)) {
          return dependencyPath;
        }
        let pathToDependencyFromDirectory = path6.resolve(
          /*
                      path.resolve resolves paths differently from what imports on javascript do.
          
                      So if we wouldn't do this, for an email at "/path/to/email.tsx" with a dependecy path of "./other-email" 
                      would end up going into /path/to/email.tsx/other-email instead of /path/to/other-email which is the
                      one the import is meant to go to
                    */
          path6.dirname(filePath),
          dependencyPath
        );
        let isDirectory = false;
        try {
          isDirectory = statSync(pathToDependencyFromDirectory).isDirectory();
        } catch (_) {
        }
        if (isDirectory) {
          const pathToSubDirectory = pathToDependencyFromDirectory;
          const pathWithExtension = checkFileExtensionsUntilItExists(
            `${pathToSubDirectory}/index`
          );
          if (pathWithExtension) {
            pathToDependencyFromDirectory = pathWithExtension;
          } else if (isDev) {
            console.warn(
              `Could not find index file for directory at ${pathToDependencyFromDirectory}. This is probably going to cause issues with both hot reloading and your code.`
            );
          }
        }
        if (!isJavascriptModule(pathToDependencyFromDirectory)) {
          const pathWithExtension = checkFileExtensionsUntilItExists(
            pathToDependencyFromDirectory
          );
          if (pathWithExtension) {
            pathToDependencyFromDirectory = pathWithExtension;
          } else if (isDev) {
            console.warn(
              `Could not determine the file extension for the file at ${pathToDependencyFromDirectory}`
            );
          }
        }
        return pathToDependencyFromDirectory;
      }
    );
    const moduleDependencies = importedPathsRelativeToDirectory.filter(
      (dependencyPath) => !dependencyPath.startsWith(".") && !path6.isAbsolute(dependencyPath)
    );
    const nonNodeModuleImportPathsRelativeToDirectory = importedPathsRelativeToDirectory.filter(
      (dependencyPath) => dependencyPath.startsWith(".") || path6.isAbsolute(dependencyPath)
    );
    return {
      dependencyPaths: nonNodeModuleImportPathsRelativeToDirectory,
      moduleDependencies
    };
  };
  const updateModuleDependenciesInGraph = async (moduleFilePath) => {
    const module = graph[moduleFilePath] ?? {
      path: moduleFilePath,
      dependencyPaths: [],
      dependentPaths: [],
      moduleDependencies: []
    };
    const { moduleDependencies, dependencyPaths: newDependencyPaths } = await getDependencyPaths(moduleFilePath);
    module.moduleDependencies = moduleDependencies;
    for (const dependencyPath of module.dependencyPaths) {
      if (newDependencyPaths.includes(dependencyPath))
        continue;
      const dependencyModule = graph[dependencyPath];
      if (dependencyModule !== void 0) {
        dependencyModule.dependentPaths = dependencyModule.dependentPaths.filter(
          (dependentPath) => dependentPath !== moduleFilePath
        );
      }
    }
    module.dependencyPaths = newDependencyPaths;
    for (const dependencyPath of newDependencyPaths) {
      const dependencyModule = graph[dependencyPath];
      if (dependencyModule !== void 0 && !dependencyModule.dependentPaths.includes(moduleFilePath)) {
        dependencyModule.dependentPaths.push(moduleFilePath);
      } else {
        graph[dependencyPath] = {
          path: dependencyPath,
          moduleDependencies: [],
          dependencyPaths: [],
          dependentPaths: [moduleFilePath]
        };
      }
    }
    graph[moduleFilePath] = module;
  };
  for (const filePath of modulePaths) {
    await updateModuleDependenciesInGraph(filePath);
  }
  const removeModuleFromGraph = (filePath) => {
    const module = graph[filePath];
    if (module) {
      for (const dependencyPath of module.dependencyPaths) {
        if (graph[dependencyPath]) {
          graph[dependencyPath].dependentPaths = graph[dependencyPath].dependentPaths.filter(
            (dependentPath) => dependentPath !== filePath
          );
        }
      }
      delete graph[filePath];
    }
  };
  return [
    graph,
    async (event, pathToModified) => {
      switch (event) {
        case "change":
          if (isJavascriptModule(pathToModified)) {
            await updateModuleDependenciesInGraph(pathToModified);
          }
          break;
        case "add":
          if (isJavascriptModule(pathToModified)) {
            await updateModuleDependenciesInGraph(pathToModified);
          }
          break;
        case "addDir": {
          const filesInsideAddedDirectory = await readAllFilesInsideDirectory(pathToModified);
          const modulesInsideAddedDirectory = filesInsideAddedDirectory.filter(isJavascriptModule);
          for await (const filePath of modulesInsideAddedDirectory) {
            await updateModuleDependenciesInGraph(filePath);
          }
          break;
        }
        case "unlink":
          if (isJavascriptModule(pathToModified)) {
            removeModuleFromGraph(pathToModified);
          }
          break;
        case "unlinkDir": {
          const filesInsideDeletedDirectory = await readAllFilesInsideDirectory(pathToModified);
          const modulesInsideDeletedDirectory = filesInsideDeletedDirectory.filter(isJavascriptModule);
          for await (const filePath of modulesInsideDeletedDirectory) {
            removeModuleFromGraph(filePath);
          }
          break;
        }
      }
    },
    {
      resolveDependentsOf: function resolveDependentsOf(pathToModule) {
        const moduleEntry = graph[pathToModule];
        const dependentPaths = [];
        if (moduleEntry) {
          for (const dependentPath of moduleEntry.dependentPaths) {
            const dependentsOfDependent = resolveDependentsOf(dependentPath);
            dependentPaths.push(...dependentsOfDependent);
            dependentPaths.push(dependentPath);
          }
        }
        return dependentPaths;
      }
    }
  ];
};

// src/cli/utils/preview/hot-reloading/setup-hot-reloading.ts
var setupHotreloading = async (devServer2, emailDirRelativePath) => {
  let clients = [];
  const io = new SocketServer(devServer2);
  io.on("connection", (client) => {
    clients.push(client);
    client.on("disconnect", () => {
      clients = clients.filter((item) => item !== client);
    });
  });
  let changes = [];
  const reload = debounce(() => {
    clients.forEach((client) => {
      client.emit("reload", changes);
    });
    changes = [];
  }, 150);
  const absolutePathToEmailsDirectory = path7.resolve(
    process.cwd(),
    emailDirRelativePath
  );
  const [dependencyGraph, updateDependencyGraph, { resolveDependentsOf }] = await createDependencyGraph(absolutePathToEmailsDirectory);
  const watcher = watch("", {
    ignoreInitial: true,
    cwd: absolutePathToEmailsDirectory
  });
  const getFilesOutsideEmailsDirectory = () => Object.keys(dependencyGraph).filter(
    (p) => path7.relative(absolutePathToEmailsDirectory, p).startsWith("..")
  );
  let filesOutsideEmailsDirectory = getFilesOutsideEmailsDirectory();
  for (const p of filesOutsideEmailsDirectory) {
    watcher.add(p);
  }
  const exit = async () => {
    await watcher.close();
  };
  process.on("SIGINT", exit);
  process.on("uncaughtException", exit);
  watcher.on("all", async (event, relativePathToChangeTarget) => {
    const file = relativePathToChangeTarget.split(path7.sep);
    if (file.length === 0) {
      return;
    }
    const pathToChangeTarget = path7.resolve(
      absolutePathToEmailsDirectory,
      relativePathToChangeTarget
    );
    await updateDependencyGraph(event, pathToChangeTarget);
    const newFilesOutsideEmailsDirectory = getFilesOutsideEmailsDirectory();
    for (const p of filesOutsideEmailsDirectory) {
      if (!newFilesOutsideEmailsDirectory.includes(p)) {
        watcher.unwatch(p);
      }
    }
    for (const p of newFilesOutsideEmailsDirectory) {
      if (!filesOutsideEmailsDirectory.includes(p)) {
        watcher.add(p);
      }
    }
    filesOutsideEmailsDirectory = newFilesOutsideEmailsDirectory;
    changes.push({
      event,
      filename: relativePathToChangeTarget
    });
    for (const dependentPath of resolveDependentsOf(pathToChangeTarget)) {
      changes.push({
        event: "change",
        filename: path7.relative(absolutePathToEmailsDirectory, dependentPath)
      });
    }
    reload();
  });
  return watcher;
};

// src/cli/commands/build.ts
var buildPreviewApp = (absoluteDirectory) => {
  return new Promise((resolve, reject) => {
    const nextBuild = spawn("npm", ["run", "build"], {
      cwd: absoluteDirectory,
      shell: true
    });
    nextBuild.stdout.pipe(process.stdout);
    nextBuild.stderr.pipe(process.stderr);
    nextBuild.on("close", (code) => {
      if (code === 0) {
        resolve();
      } else {
        reject(
          new Error(
            `Unable to build the Next app and it exited with code: ${code}`
          )
        );
      }
    });
  });
};
var setNextEnvironmentVariablesForBuild = async (emailsDirRelativePath, builtPreviewAppPath) => {
  const nextConfigContents = `
const path = require('path');
const emailsDirRelativePath = path.normalize('${emailsDirRelativePath}');
const userProjectLocation = path.resolve(process.cwd(), '../');
/** @type {import('next').NextConfig} */
module.exports = {
  env: {
    NEXT_PUBLIC_IS_BUILDING: 'true',
    EMAILS_DIR_RELATIVE_PATH: emailsDirRelativePath,
    EMAILS_DIR_ABSOLUTE_PATH: path.resolve(userProjectLocation, emailsDirRelativePath),
    USER_PROJECT_LOCATION: userProjectLocation
  },
  // this is needed so that the code for building emails works properly
  webpack: (
    /** @type {import('webpack').Configuration & { externals: string[] }} */
    config,
    { isServer }
  ) => {
    if (isServer) {
      config.externals.push('esbuild');
    }

    return config;
  },
  typescript: {
    ignoreBuildErrors: true
  },
  eslint: {
    ignoreDuringBuilds: true
  },
  experimental: {
    webpackBuildWorker: true
  },
}`;
  await fs5.promises.writeFile(
    path8.resolve(builtPreviewAppPath, "./next.config.js"),
    nextConfigContents,
    "utf8"
  );
};
var getEmailSlugsFromEmailDirectory = (emailDirectory, emailsDirectoryAbsolutePath) => {
  const directoryPathRelativeToEmailsDirectory = emailDirectory.absolutePath.replace(emailsDirectoryAbsolutePath, "").trim();
  const slugs = [];
  emailDirectory.emailFilenames.forEach(
    (filename) => slugs.push(
      path8.join(directoryPathRelativeToEmailsDirectory, filename).split(path8.sep).filter((segment) => segment.length > 0)
    )
  );
  emailDirectory.subDirectories.forEach((directory) => {
    slugs.push(
      ...getEmailSlugsFromEmailDirectory(
        directory,
        emailsDirectoryAbsolutePath
      )
    );
  });
  return slugs;
};
var forceSSGForEmailPreviews = async (emailsDirPath, builtPreviewAppPath) => {
  const emailDirectoryMetadata = (
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    await getEmailsDirectoryMetadata(emailsDirPath)
  );
  const parameters = getEmailSlugsFromEmailDirectory(
    emailDirectoryMetadata,
    emailsDirPath
  ).map((slug) => ({ slug }));
  const removeForceDynamic = async (filePath) => {
    const contents = await fs5.promises.readFile(filePath, "utf8");
    await fs5.promises.writeFile(
      filePath,
      contents.replace("export const dynamic = 'force-dynamic';", ""),
      "utf8"
    );
  };
  await removeForceDynamic(
    path8.resolve(builtPreviewAppPath, "./src/app/layout.tsx")
  );
  await removeForceDynamic(
    path8.resolve(builtPreviewAppPath, "./src/app/preview/[...slug]/page.tsx")
  );
  await fs5.promises.appendFile(
    path8.resolve(builtPreviewAppPath, "./src/app/preview/[...slug]/page.tsx"),
    `

export function generateStaticParams() { 
  return Promise.resolve(
    ${JSON.stringify(parameters)}
  );
}`,
    "utf8"
  );
};
var updatePackageJson = async (builtPreviewAppPath) => {
  const packageJsonPath = path8.resolve(builtPreviewAppPath, "./package.json");
  const packageJson = JSON.parse(
    await fs5.promises.readFile(packageJsonPath, "utf8")
  );
  packageJson.scripts.build = "next build";
  packageJson.scripts.start = "next start";
  packageJson.name = "preview-server";
  delete packageJson.devDependencies["@react-email/render"];
  delete packageJson.devDependencies["@react-email/components"];
  delete packageJson.scripts.prepare;
  await fs5.promises.writeFile(
    packageJsonPath,
    JSON.stringify(packageJson),
    "utf8"
  );
};
var npmInstall = async (builtPreviewAppPath, packageManager) => {
  return new Promise((resolve, reject) => {
    const childProc = spawn(
      packageManager,
      [
        "install",
        packageManager === "deno" ? "" : "--include=dev",
        packageManager === "deno" ? "--quiet" : "--silent"
      ],
      {
        cwd: builtPreviewAppPath,
        shell: true
      }
    );
    childProc.stdout.pipe(process.stdout);
    childProc.stderr.pipe(process.stderr);
    childProc.on("close", (code) => {
      if (code === 0) {
        resolve();
      } else {
        reject(
          new Error(
            `Unable to install the dependencies and it exited with code: ${code}`
          )
        );
      }
    });
  });
};
var build = async ({
  dir: emailsDirRelativePath,
  packageManager
}) => {
  try {
    const spinner = ora2({
      text: "Starting build process...",
      prefixText: "  "
    }).start();
    registerSpinnerAutostopping(spinner);
    spinner.text = `Checking if ${emailsDirRelativePath} folder exists`;
    if (!fs5.existsSync(emailsDirRelativePath)) {
      process.exit(1);
    }
    const emailsDirPath = path8.join(process.cwd(), emailsDirRelativePath);
    const staticPath = path8.join(emailsDirPath, "static");
    const builtPreviewAppPath = path8.join(process.cwd(), ".react-email");
    if (fs5.existsSync(builtPreviewAppPath)) {
      spinner.text = "Deleting pre-existing `.react-email` folder";
      await fs5.promises.rm(builtPreviewAppPath, { recursive: true });
    }
    spinner.text = "Copying preview app from CLI to `.react-email`";
    await fs5.promises.cp(cliPackageLocation, builtPreviewAppPath, {
      recursive: true,
      filter: (source) => {
        return !/(\/|\\)cli(\/|\\)?/.test(source) && !/(\/|\\)\.next(\/|\\)?/.test(source) && !/(\/|\\)\.turbo(\/|\\)?/.test(source) && !/(\/|\\)node_modules(\/|\\)?$/.test(source);
      }
    });
    if (fs5.existsSync(staticPath)) {
      spinner.text = "Copying `static` folder into `.react-email/public/static`";
      const builtStaticDirectory = path8.resolve(
        builtPreviewAppPath,
        "./public/static"
      );
      await fs5.promises.cp(staticPath, builtStaticDirectory, {
        recursive: true
      });
    }
    spinner.text = "Setting Next environment variables for preview app to work properly";
    await setNextEnvironmentVariablesForBuild(
      emailsDirRelativePath,
      builtPreviewAppPath
    );
    spinner.text = "Setting server side generation for the email preview pages";
    await forceSSGForEmailPreviews(emailsDirPath, builtPreviewAppPath);
    spinner.text = "Updating package.json's build and start scripts";
    await updatePackageJson(builtPreviewAppPath);
    spinner.text = "Installing dependencies on `.react-email`";
    await npmInstall(builtPreviewAppPath, packageManager);
    spinner.stopAndPersist({
      text: "Successfully prepared `.react-email` for `next build`",
      symbol: logSymbols3.success
    });
    await buildPreviewApp(builtPreviewAppPath);
  } catch (error) {
    console.log(error);
    process.exit(1);
  }
};

// src/cli/commands/dev.ts
import fs6 from "node:fs";
var dev = async ({ dir: emailsDirRelativePath, port }) => {
  try {
    if (!fs6.existsSync(emailsDirRelativePath)) {
      console.error(`Missing ${emailsDirRelativePath} folder`);
      process.exit(1);
    }
    const devServer2 = await startDevServer(
      emailsDirRelativePath,
      emailsDirRelativePath,
      // defaults to ./emails/static for the static files that are served to the preview
      Number.parseInt(port)
    );
    await setupHotreloading(devServer2, emailsDirRelativePath);
  } catch (error) {
    console.log(error);
    process.exit(1);
  }
};

// src/cli/commands/export.ts
import fs8, { unlinkSync, writeFileSync } from "node:fs";
import path10 from "node:path";
import { build as build2 } from "esbuild";
import { glob } from "glob";
import logSymbols4 from "log-symbols";
import normalize from "normalize-path";
import ora3 from "ora";

// src/utils/esbuild/renderring-utilities-exporter.ts
import { promises as fs7 } from "node:fs";
import path9 from "node:path";

// src/utils/esbuild/escape-string-for-regex.ts
function escapeStringForRegex(string) {
  return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
}

// src/utils/esbuild/renderring-utilities-exporter.ts
var renderingUtilitiesExporter = (emailTemplates) => ({
  name: "rendering-utilities-exporter",
  setup: (b) => {
    b.onLoad(
      {
        filter: new RegExp(
          emailTemplates.map((emailPath) => escapeStringForRegex(emailPath)).join("|")
        )
      },
      async ({ path: pathToFile }) => {
        return {
          contents: `${await fs7.readFile(pathToFile, "utf8")};
          export { render, pretty } from 'react-email-module-that-will-export-render'
          export { createElement as reactEmailCreateReactElement } from 'react';
        `,
          loader: path9.extname(pathToFile).slice(1)
        };
      }
    );
    b.onResolve(
      { filter: /^react-email-module-that-will-export-render$/ },
      async (args) => {
        const options = {
          kind: "import-statement",
          importer: args.importer,
          resolveDir: args.resolveDir,
          namespace: args.namespace
        };
        let result = await b.resolve("@react-email/render", options);
        if (result.errors.length === 0) {
          return result;
        }
        result = await b.resolve("@react-email/components", options);
        if (result.errors.length > 0 && result.errors[0]) {
          result.errors[0].text = "Failed trying to import `render` from either `@react-email/render` or `@react-email/components` to be able to render your email template.\n Maybe you don't have either of them installed?";
        }
        return result;
      }
    );
  }
});

// src/cli/commands/export.ts
var getEmailTemplatesFromDirectory = (emailDirectory) => {
  const templatePaths = [];
  emailDirectory.emailFilenames.forEach(
    (filename) => templatePaths.push(path10.join(emailDirectory.absolutePath, filename))
  );
  emailDirectory.subDirectories.forEach((directory) => {
    templatePaths.push(...getEmailTemplatesFromDirectory(directory));
  });
  return templatePaths;
};
var exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirectoryPath, options) => {
  if (fs8.existsSync(pathToWhereEmailMarkupShouldBeDumped)) {
    fs8.rmSync(pathToWhereEmailMarkupShouldBeDumped, { recursive: true });
  }
  let spinner;
  if (!options.silent) {
    spinner = ora3("Preparing files...\n").start();
    registerSpinnerAutostopping(spinner);
  }
  const emailsDirectoryMetadata = await getEmailsDirectoryMetadata(
    path10.resolve(process.cwd(), emailsDirectoryPath),
    true
  );
  if (typeof emailsDirectoryMetadata === "undefined") {
    if (spinner) {
      spinner.stopAndPersist({
        symbol: logSymbols4.error,
        text: `Could not find the directory at ${emailsDirectoryPath}`
      });
    }
    return;
  }
  const allTemplates = getEmailTemplatesFromDirectory(emailsDirectoryMetadata);
  try {
    await build2({
      bundle: true,
      entryPoints: allTemplates,
      plugins: [renderingUtilitiesExporter(allTemplates)],
      platform: "node",
      format: "cjs",
      loader: { ".js": "jsx" },
      outExtension: { ".js": ".cjs" },
      jsx: "transform",
      write: true,
      outdir: pathToWhereEmailMarkupShouldBeDumped
    });
  } catch (exception) {
    const buildFailure = exception;
    if (spinner) {
      spinner.stopAndPersist({
        symbol: logSymbols4.error,
        text: "Failed to build emails"
      });
    }
    process.exit(1);
  }
  if (spinner) {
    spinner.succeed();
  }
  const allBuiltTemplates = glob.sync(
    normalize(`${pathToWhereEmailMarkupShouldBeDumped}/**/*.cjs`),
    {
      absolute: true
    }
  );
  for await (const template of allBuiltTemplates) {
    try {
      if (spinner) {
        spinner.text = `rendering ${template.split("/").pop()}`;
        spinner.render();
      }
      delete __require.cache[template];
      const emailModule = __require(template);
      let rendered = await emailModule.render(
        emailModule.reactEmailCreateReactElement(emailModule.default, {}),
        options
      );
      if (!options.plainText && options.pretty)
        rendered = await emailModule.pretty(rendered);
      const htmlPath = template.replace(
        ".cjs",
        options.plainText ? ".txt" : ".html"
      );
      writeFileSync(htmlPath, rendered);
      unlinkSync(template);
    } catch (exception) {
      if (spinner) {
        spinner.stopAndPersist({
          symbol: logSymbols4.error,
          text: `failed when rendering ${template.split("/").pop()}`
        });
      }
      console.error(exception);
      process.exit(1);
    }
  }
  if (spinner) {
    spinner.succeed("Rendered all files");
    spinner.text = "Copying static files";
    spinner.render();
  }
  const staticDirectoryPath = path10.join(emailsDirectoryPath, "static");
  if (fs8.existsSync(staticDirectoryPath)) {
    const pathToDumpStaticFilesInto = path10.join(
      pathToWhereEmailMarkupShouldBeDumped,
      "static"
    );
    if (fs8.existsSync(pathToDumpStaticFilesInto))
      await fs8.promises.rm(pathToDumpStaticFilesInto, { recursive: true });
    try {
      await fs8.promises.cp(staticDirectoryPath, pathToDumpStaticFilesInto, {
        recursive: true
      });
    } catch (exception) {
      console.error(exception);
      if (spinner) {
        spinner.stopAndPersist({
          symbol: logSymbols4.error,
          text: "Failed to copy static files"
        });
      }
      console.error(
        `Something went wrong while copying the file to ${pathToWhereEmailMarkupShouldBeDumped}/static, ${exception}`
      );
      process.exit(1);
    }
  }
  if (spinner && !options.silent) {
    spinner.succeed();
    const fileTree = await tree(pathToWhereEmailMarkupShouldBeDumped, 4);
    console.log(fileTree);
    spinner.stopAndPersist({
      symbol: logSymbols4.success,
      text: "Successfully exported emails"
    });
  }
};

// src/cli/commands/start.ts
import { spawn as spawn2 } from "node:child_process";
import fs9 from "node:fs";
import path11 from "node:path";
var start = async () => {
  try {
    const usersProjectLocation = process.cwd();
    const builtPreviewPath = path11.resolve(
      usersProjectLocation,
      "./.react-email"
    );
    if (!fs9.existsSync(builtPreviewPath)) {
      console.error(
        "Could not find .react-email, maybe you haven't ran email build?"
      );
      process.exit(1);
    }
    const nextStart = spawn2("npm", ["start"], {
      cwd: builtPreviewPath,
      stdio: "inherit"
    });
    process.on("SIGINT", () => {
      nextStart.kill("SIGINT");
    });
    nextStart.on("exit", (code) => {
      process.exit(code ?? 0);
    });
  } catch (error) {
    console.log(error);
    process.exit(1);
  }
};

// src/cli/index.ts
var PACKAGE_NAME = "react-email";
program.name(PACKAGE_NAME).description("A live preview of your emails right in your browser").version(package_default.version);
program.command("dev").description("Starts the preview email development app").option("-d, --dir <path>", "Directory with your email templates", "./emails").option("-p --port <port>", "Port to run dev server on", "3000").action(dev);
program.command("build").description("Copies the preview app for onto .react-email and builds it").option("-d, --dir <path>", "Directory with your email templates", "./emails").option(
  "-p --packageManager <name>",
  "Package name to use on installation on `.react-email`",
  "npm"
).action(build);
program.command("start").description('Runs the built preview app that is inside of ".react-email"').action(start);
program.command("export").description("Build the templates to the `out` directory").option("--outDir <path>", "Output directory", "out").option("-p, --pretty", "Pretty print the output", false).option("-t, --plainText", "Set output format as plain text", false).option("-d, --dir <path>", "Directory with your email templates", "./emails").option(
  "-s, --silent",
  "To, or not to show a spinner with process information",
  false
).action(
  ({ outDir, pretty, plainText, silent, dir: srcDir }) => exportTemplates(outDir, srcDir, { silent, plainText, pretty })
);
program.parse();
