@emailens/cli 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,72 +1,71 @@
1
- {
2
- "name": "@emailens/cli",
3
- "version": "0.1.0",
4
- "description": "CLI tool for email compatibility analysis — analyze, preview, and export email rendering across 12 email clients.",
5
- "type": "module",
6
- "bin": {
7
- "emailens": "./dist/index.js"
8
- },
9
- "exports": {
10
- ".": {
11
- "types": "./dist/index.d.ts",
12
- "import": "./dist/index.js"
13
- }
14
- },
15
- "main": "./dist/index.js",
16
- "types": "./dist/index.d.ts",
17
- "files": [
18
- "dist",
19
- "LICENSE"
20
- ],
21
- "scripts": {
22
- "build": "tsup",
23
- "dev": "tsup --watch",
24
- "start": "bun run dist/index.js",
25
- "typecheck": "tsc --noEmit",
26
- "test": "bun test",
27
- "prepublishOnly": "bun run build"
28
- },
29
- "dependencies": {
30
- "@emailens/engine": "^0.1.0",
31
- "citty": "^0.1.6",
32
- "cli-table3": "^0.6.5",
33
- "ora": "^8.2.0",
34
- "picocolors": "^1.1.1"
35
- },
36
- "optionalDependencies": {
37
- "sucrase": "^3.35.0",
38
- "@react-email/components": "^0.0.36",
39
- "@react-email/render": "^1.0.6",
40
- "mjml": "^5.0.0-alpha.4",
41
- "@maizzle/framework": "^5.0.0",
42
- "playwright-core": "^1.52.0"
43
- },
44
- "devDependencies": {
45
- "@types/mjml": "^4.7.4",
46
- "@types/node": "^25.3.0",
47
- "bun-types": "^1.3.9",
48
- "tsup": "^8.4.0",
49
- "typescript": "^5.9.3"
50
- },
51
- "keywords": [
52
- "email",
53
- "html-email",
54
- "css",
55
- "compatibility",
56
- "cli",
57
- "gmail",
58
- "outlook",
59
- "apple-mail",
60
- "email-testing",
61
- "dark-mode"
62
- ],
63
- "license": "MIT",
64
- "repository": {
65
- "type": "git",
66
- "url": "git+https://github.com/emailens/cli.git"
67
- },
68
- "homepage": "https://github.com/emailens/cli#readme",
69
- "bugs": {
70
- "url": "https://github.com/emailens/cli/issues"
71
- }
72
- }
1
+ {
2
+ "name": "@emailens/cli",
3
+ "version": "0.3.0",
4
+ "description": "CLI tool for email compatibility analysis — analyze, preview, and export email rendering across 12 email clients.",
5
+ "type": "module",
6
+ "bin": {
7
+ "emailens": "./dist/index.js"
8
+ },
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "files": [
18
+ "dist",
19
+ "LICENSE"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "dev": "tsup --watch",
24
+ "start": "bun run dist/index.js",
25
+ "typecheck": "tsc --noEmit",
26
+ "test": "bun test",
27
+ "prepublishOnly": "bun run build"
28
+ },
29
+ "dependencies": {
30
+ "@emailens/engine": "^0.5.1",
31
+ "citty": "^0.1.6",
32
+ "cli-table3": "^0.6.5",
33
+ "ora": "^8.2.0",
34
+ "picocolors": "^1.1.1"
35
+ },
36
+ "optionalDependencies": {
37
+ "@anthropic-ai/sdk": "^0.52.0",
38
+ "playwright-core": "^1.52.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/mjml": "^4.7.4",
42
+ "@types/node": "^25.3.0",
43
+ "bun-types": "^1.3.9",
44
+ "tsup": "^8.4.0",
45
+ "typescript": "^5.9.3"
46
+ },
47
+ "keywords": [
48
+ "email",
49
+ "html-email",
50
+ "css",
51
+ "compatibility",
52
+ "cli",
53
+ "gmail",
54
+ "outlook",
55
+ "apple-mail",
56
+ "email-testing",
57
+ "dark-mode"
58
+ ],
59
+ "license": "MIT",
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "git+https://github.com/emailens/cli.git"
63
+ },
64
+ "engines": {
65
+ "node": ">=18"
66
+ },
67
+ "homepage": "https://github.com/emailens/cli#readme",
68
+ "bugs": {
69
+ "url": "https://github.com/emailens/cli/issues"
70
+ }
71
+ }
@@ -1,55 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/compile/maizzle.ts
4
- var MAX_SOURCE_SIZE = 512e3;
5
- var COMPILE_TIMEOUT_MS = 15e3;
6
- async function compileMaizzle(source) {
7
- if (!source || !source.trim()) {
8
- throw new Error("Maizzle source must not be empty.");
9
- }
10
- if (source.length > MAX_SOURCE_SIZE) {
11
- throw new Error(`Maizzle source exceeds ${MAX_SOURCE_SIZE / 1e3}KB limit.`);
12
- }
13
- let maizzleRender;
14
- try {
15
- const maizzle = await import("@maizzle/framework");
16
- maizzleRender = maizzle.render;
17
- } catch {
18
- throw new Error(
19
- 'Maizzle compilation requires "@maizzle/framework". Install it:\n npm install @maizzle/framework'
20
- );
21
- }
22
- const compilePromise = maizzleRender(source, {
23
- css: {
24
- inline: {
25
- removeInlinedSelectors: true,
26
- applyWidthAttributes: true,
27
- applyHeightAttributes: true
28
- },
29
- shorthand: true,
30
- sixHex: true
31
- },
32
- locals: {}
33
- });
34
- const timeoutPromise = new Promise((_, reject) => {
35
- const t = setTimeout(() => {
36
- reject(new Error(`Maizzle compilation timed out after ${COMPILE_TIMEOUT_MS / 1e3}s.`));
37
- }, COMPILE_TIMEOUT_MS);
38
- if (typeof t.unref === "function") t.unref();
39
- });
40
- try {
41
- const { html } = await Promise.race([compilePromise, timeoutPromise]);
42
- if (!html) {
43
- throw new Error("Maizzle compilation produced empty output.");
44
- }
45
- return html;
46
- } catch (err) {
47
- if (err instanceof Error && err.message.startsWith("Maizzle")) throw err;
48
- const message = err instanceof Error ? err.message : "Unknown Maizzle compilation error";
49
- throw new Error(`Maizzle compilation failed: ${message}`);
50
- }
51
- }
52
- export {
53
- compileMaizzle
54
- };
55
- //# sourceMappingURL=maizzle-JGKTYDDO.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/compile/maizzle.ts"],"sourcesContent":["/** Maximum Maizzle source size: 512KB */\r\nconst MAX_SOURCE_SIZE = 512_000;\r\n\r\n/** Compilation timeout: 15 seconds */\r\nconst COMPILE_TIMEOUT_MS = 15_000;\r\n\r\n/**\r\n * Compile a Maizzle template string into an HTML email string.\r\n * Requires: @maizzle/framework (optional peer dependency)\r\n *\r\n * No dangerous-directive check in CLI — runs locally on the user's machine.\r\n */\r\nexport async function compileMaizzle(source: string): Promise<string> {\r\n // ── Validate ──────────────────────────────────────────────────────\r\n if (!source || !source.trim()) {\r\n throw new Error(\"Maizzle source must not be empty.\");\r\n }\r\n\r\n if (source.length > MAX_SOURCE_SIZE) {\r\n throw new Error(`Maizzle source exceeds ${MAX_SOURCE_SIZE / 1000}KB limit.`);\r\n }\r\n\r\n // ── Load optional dependency ──────────────────────────────────────\r\n let maizzleRender: (input: string, options: Record<string, unknown>) => Promise<{ html: string }>;\r\n try {\r\n const maizzle = await import(\"@maizzle/framework\");\r\n maizzleRender = maizzle.render;\r\n } catch {\r\n throw new Error(\r\n 'Maizzle compilation requires \"@maizzle/framework\". Install it:\\n npm install @maizzle/framework'\r\n );\r\n }\r\n\r\n // ── Compile with timeout ──────────────────────────────────────────\r\n const compilePromise = maizzleRender(source, {\r\n css: {\r\n inline: {\r\n removeInlinedSelectors: true,\r\n applyWidthAttributes: true,\r\n applyHeightAttributes: true,\r\n },\r\n shorthand: true,\r\n sixHex: true,\r\n },\r\n locals: {},\r\n });\r\n\r\n const timeoutPromise = new Promise<never>((_, reject) => {\r\n const t = setTimeout(() => {\r\n reject(new Error(`Maizzle compilation timed out after ${COMPILE_TIMEOUT_MS / 1000}s.`));\r\n }, COMPILE_TIMEOUT_MS);\r\n if (typeof t.unref === \"function\") t.unref();\r\n });\r\n\r\n try {\r\n const { html } = await Promise.race([compilePromise, timeoutPromise]);\r\n\r\n if (!html) {\r\n throw new Error(\"Maizzle compilation produced empty output.\");\r\n }\r\n\r\n return html;\r\n } catch (err: unknown) {\r\n if (err instanceof Error && err.message.startsWith(\"Maizzle\")) throw err;\r\n const message = err instanceof Error ? err.message : \"Unknown Maizzle compilation error\";\r\n throw new Error(`Maizzle compilation failed: ${message}`);\r\n }\r\n}\r\n"],"mappings":";;;AACA,IAAM,kBAAkB;AAGxB,IAAM,qBAAqB;AAQ3B,eAAsB,eAAe,QAAiC;AAEpE,MAAI,CAAC,UAAU,CAAC,OAAO,KAAK,GAAG;AAC7B,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAEA,MAAI,OAAO,SAAS,iBAAiB;AACnC,UAAM,IAAI,MAAM,0BAA0B,kBAAkB,GAAI,WAAW;AAAA,EAC7E;AAGA,MAAI;AACJ,MAAI;AACF,UAAM,UAAU,MAAM,OAAO,oBAAoB;AACjD,oBAAgB,QAAQ;AAAA,EAC1B,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,QAAM,iBAAiB,cAAc,QAAQ;AAAA,IAC3C,KAAK;AAAA,MACH,QAAQ;AAAA,QACN,wBAAwB;AAAA,QACxB,sBAAsB;AAAA,QACtB,uBAAuB;AAAA,MACzB;AAAA,MACA,WAAW;AAAA,MACX,QAAQ;AAAA,IACV;AAAA,IACA,QAAQ,CAAC;AAAA,EACX,CAAC;AAED,QAAM,iBAAiB,IAAI,QAAe,CAAC,GAAG,WAAW;AACvD,UAAM,IAAI,WAAW,MAAM;AACzB,aAAO,IAAI,MAAM,uCAAuC,qBAAqB,GAAI,IAAI,CAAC;AAAA,IACxF,GAAG,kBAAkB;AACrB,QAAI,OAAO,EAAE,UAAU,WAAY,GAAE,MAAM;AAAA,EAC7C,CAAC;AAED,MAAI;AACF,UAAM,EAAE,KAAK,IAAI,MAAM,QAAQ,KAAK,CAAC,gBAAgB,cAAc,CAAC;AAEpE,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,WAAO;AAAA,EACT,SAAS,KAAc;AACrB,QAAI,eAAe,SAAS,IAAI,QAAQ,WAAW,SAAS,EAAG,OAAM;AACrE,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,UAAM,IAAI,MAAM,+BAA+B,OAAO,EAAE;AAAA,EAC1D;AACF;","names":[]}
@@ -1,48 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/compile/mjml.ts
4
- var MAX_SOURCE_SIZE = 512e3;
5
- async function compileMjml(source) {
6
- if (!source || !source.trim()) {
7
- throw new Error("MJML source must not be empty.");
8
- }
9
- if (source.length > MAX_SOURCE_SIZE) {
10
- throw new Error(`MJML source exceeds ${MAX_SOURCE_SIZE / 1e3}KB limit.`);
11
- }
12
- if (!/<mjml[\s>]/i.test(source)) {
13
- throw new Error(
14
- "MJML source must contain a root <mjml> element. Example: <mjml><mj-body><mj-section><mj-column><mj-text>Hello</mj-text></mj-column></mj-section></mj-body></mjml>"
15
- );
16
- }
17
- let mjml2html;
18
- try {
19
- const mjmlModule = await import("mjml");
20
- mjml2html = mjmlModule.default ?? mjmlModule;
21
- } catch {
22
- throw new Error(
23
- 'MJML compilation requires "mjml". Install it:\n npm install mjml'
24
- );
25
- }
26
- try {
27
- const result = mjml2html(source, {
28
- validationLevel: "soft",
29
- keepComments: false
30
- });
31
- if (result.errors && result.errors.length > 0 && !result.html) {
32
- const errorMessages = result.errors.map((e) => `Line ${e.line}: ${e.message} (${e.tagName})`).join("; ");
33
- throw new Error(`MJML compilation errors: ${errorMessages}`);
34
- }
35
- if (!result.html) {
36
- throw new Error("MJML compilation produced empty output.");
37
- }
38
- return result.html;
39
- } catch (err) {
40
- if (err instanceof Error && err.message.startsWith("MJML")) throw err;
41
- const message = err instanceof Error ? err.message : "Unknown MJML compilation error";
42
- throw new Error(`MJML compilation failed: ${message}`);
43
- }
44
- }
45
- export {
46
- compileMjml
47
- };
48
- //# sourceMappingURL=mjml-KG66APFB.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/compile/mjml.ts"],"sourcesContent":["/** Maximum MJML source size: 512KB */\r\nconst MAX_SOURCE_SIZE = 512_000;\r\n\r\n/**\r\n * Compile an MJML source string into an HTML email string.\r\n * Requires: mjml (optional peer dependency)\r\n */\r\nexport async function compileMjml(source: string): Promise<string> {\r\n // ── Validate ──────────────────────────────────────────────────────\r\n if (!source || !source.trim()) {\r\n throw new Error(\"MJML source must not be empty.\");\r\n }\r\n\r\n if (source.length > MAX_SOURCE_SIZE) {\r\n throw new Error(`MJML source exceeds ${MAX_SOURCE_SIZE / 1000}KB limit.`);\r\n }\r\n\r\n if (!/<mjml[\\s>]/i.test(source)) {\r\n throw new Error(\r\n \"MJML source must contain a root <mjml> element. \" +\r\n \"Example: <mjml><mj-body><mj-section><mj-column><mj-text>Hello</mj-text></mj-column></mj-section></mj-body></mjml>\"\r\n );\r\n }\r\n\r\n // ── Load optional dependency ──────────────────────────────────────\r\n let mjml2html: (input: string, options?: Record<string, unknown>) => { html: string; errors: Array<{ line: number; message: string; tagName: string; formattedMessage: string }> };\r\n try {\r\n const mjmlModule = await import(\"mjml\");\r\n mjml2html = mjmlModule.default ?? mjmlModule;\r\n } catch {\r\n throw new Error(\r\n 'MJML compilation requires \"mjml\". Install it:\\n npm install mjml'\r\n );\r\n }\r\n\r\n // ── Compile ───────────────────────────────────────────────────────\r\n try {\r\n const result = mjml2html(source, {\r\n validationLevel: \"soft\",\r\n keepComments: false,\r\n });\r\n\r\n if (result.errors && result.errors.length > 0 && !result.html) {\r\n const errorMessages = result.errors\r\n .map((e) => `Line ${e.line}: ${e.message} (${e.tagName})`)\r\n .join(\"; \");\r\n throw new Error(`MJML compilation errors: ${errorMessages}`);\r\n }\r\n\r\n if (!result.html) {\r\n throw new Error(\"MJML compilation produced empty output.\");\r\n }\r\n\r\n return result.html;\r\n } catch (err: unknown) {\r\n if (err instanceof Error && err.message.startsWith(\"MJML\")) throw err;\r\n const message = err instanceof Error ? err.message : \"Unknown MJML compilation error\";\r\n throw new Error(`MJML compilation failed: ${message}`);\r\n }\r\n}\r\n"],"mappings":";;;AACA,IAAM,kBAAkB;AAMxB,eAAsB,YAAY,QAAiC;AAEjE,MAAI,CAAC,UAAU,CAAC,OAAO,KAAK,GAAG;AAC7B,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAEA,MAAI,OAAO,SAAS,iBAAiB;AACnC,UAAM,IAAI,MAAM,uBAAuB,kBAAkB,GAAI,WAAW;AAAA,EAC1E;AAEA,MAAI,CAAC,cAAc,KAAK,MAAM,GAAG;AAC/B,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAGA,MAAI;AACJ,MAAI;AACF,UAAM,aAAa,MAAM,OAAO,MAAM;AACtC,gBAAY,WAAW,WAAW;AAAA,EACpC,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,MAAI;AACF,UAAM,SAAS,UAAU,QAAQ;AAAA,MAC/B,iBAAiB;AAAA,MACjB,cAAc;AAAA,IAChB,CAAC;AAED,QAAI,OAAO,UAAU,OAAO,OAAO,SAAS,KAAK,CAAC,OAAO,MAAM;AAC7D,YAAM,gBAAgB,OAAO,OAC1B,IAAI,CAAC,MAAM,QAAQ,EAAE,IAAI,KAAK,EAAE,OAAO,KAAK,EAAE,OAAO,GAAG,EACxD,KAAK,IAAI;AACZ,YAAM,IAAI,MAAM,4BAA4B,aAAa,EAAE;AAAA,IAC7D;AAEA,QAAI,CAAC,OAAO,MAAM;AAChB,YAAM,IAAI,MAAM,yCAAyC;AAAA,IAC3D;AAEA,WAAO,OAAO;AAAA,EAChB,SAAS,KAAc;AACrB,QAAI,eAAe,SAAS,IAAI,QAAQ,WAAW,MAAM,EAAG,OAAM;AAClE,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,UAAM,IAAI,MAAM,4BAA4B,OAAO,EAAE;AAAA,EACvD;AACF;","names":[]}
@@ -1,164 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/compile/react-email.ts
4
- import { createContext, Script } from "vm";
5
- var MAX_SOURCE_SIZE = 256e3;
6
- var EXECUTION_TIMEOUT_MS = 5e3;
7
- async function compileReactEmail(source) {
8
- if (!source || !source.trim()) {
9
- throw new Error("JSX source must not be empty.");
10
- }
11
- if (source.length > MAX_SOURCE_SIZE) {
12
- throw new Error(`JSX source exceeds ${MAX_SOURCE_SIZE / 1e3}KB limit.`);
13
- }
14
- let transform;
15
- let React;
16
- let ReactEmailComponents;
17
- let render;
18
- try {
19
- ({ transform } = await import("sucrase"));
20
- } catch {
21
- throw new Error(
22
- 'JSX compilation requires "sucrase". Install it:\n npm install sucrase'
23
- );
24
- }
25
- try {
26
- React = await import("react");
27
- } catch {
28
- throw new Error(
29
- 'JSX compilation requires "react". Install it:\n npm install react'
30
- );
31
- }
32
- try {
33
- ReactEmailComponents = await import("@react-email/components");
34
- } catch {
35
- throw new Error(
36
- 'JSX compilation requires "@react-email/components". Install it:\n npm install @react-email/components'
37
- );
38
- }
39
- try {
40
- ({ render } = await import("@react-email/render"));
41
- } catch {
42
- throw new Error(
43
- 'JSX compilation requires "@react-email/render". Install it:\n npm install @react-email/render'
44
- );
45
- }
46
- let transpiledCode;
47
- try {
48
- const result = transform(source, {
49
- transforms: ["typescript", "jsx", "imports"],
50
- jsxRuntime: "classic",
51
- production: true
52
- });
53
- transpiledCode = result.code;
54
- } catch (err) {
55
- const message = err instanceof Error ? err.message : "Unknown transpilation error";
56
- throw new Error(`JSX syntax error: ${message}`);
57
- }
58
- const ALLOWED_MODULES = {
59
- react: React,
60
- "@react-email/components": ReactEmailComponents
61
- };
62
- const moduleExports = {};
63
- const moduleObj = { exports: moduleExports };
64
- const mockRequire = (moduleName) => {
65
- if (moduleName in ALLOWED_MODULES) {
66
- return ALLOWED_MODULES[moduleName];
67
- }
68
- throw new Error(
69
- `Import of "${moduleName}" is not allowed. Only "react" and "@react-email/components" can be imported.`
70
- );
71
- };
72
- const sandbox = {
73
- module: moduleObj,
74
- exports: moduleExports,
75
- require: mockRequire,
76
- React,
77
- Object,
78
- Array,
79
- String,
80
- Number,
81
- Boolean,
82
- Map,
83
- Set,
84
- WeakMap,
85
- WeakSet,
86
- JSON,
87
- Math,
88
- Date,
89
- RegExp,
90
- Error,
91
- TypeError,
92
- RangeError,
93
- ReferenceError,
94
- SyntaxError,
95
- URIError,
96
- Promise,
97
- Symbol,
98
- Proxy,
99
- Reflect,
100
- parseInt,
101
- parseFloat,
102
- isNaN,
103
- isFinite,
104
- encodeURIComponent,
105
- decodeURIComponent,
106
- encodeURI,
107
- decodeURI,
108
- undefined: void 0,
109
- NaN: NaN,
110
- Infinity: Infinity,
111
- console: { log: () => {
112
- }, warn: () => {
113
- }, error: () => {
114
- }, info: () => {
115
- }, debug: () => {
116
- } },
117
- setTimeout: void 0,
118
- setInterval: void 0,
119
- setImmediate: void 0,
120
- queueMicrotask: void 0,
121
- process: void 0,
122
- globalThis: void 0,
123
- global: void 0,
124
- Buffer: void 0,
125
- __dirname: void 0,
126
- __filename: void 0
127
- };
128
- const context = createContext(sandbox, {
129
- codeGeneration: { strings: false, wasm: false }
130
- });
131
- try {
132
- const script = new Script(transpiledCode, { filename: "user-email-component.tsx" });
133
- script.runInContext(context, { timeout: EXECUTION_TIMEOUT_MS, displayErrors: true });
134
- } catch (err) {
135
- const message = err instanceof Error ? err.message : "Unknown execution error";
136
- if (message.includes("Script execution timed out")) {
137
- throw new Error("JSX execution timed out (possible infinite loop).");
138
- }
139
- throw new Error(`JSX execution error: ${message}`);
140
- }
141
- let Component = moduleObj.exports.default ?? moduleObj.exports;
142
- if (typeof Component !== "function" && typeof Component === "object" && Component !== null) {
143
- const values = Object.values(Component);
144
- const fn = values.find((v) => typeof v === "function");
145
- if (fn) Component = fn;
146
- }
147
- if (typeof Component !== "function") {
148
- throw new Error(
149
- 'The JSX source must export a React component function. Use "export default function Email() { ... }" or "export function Email() { ... }".'
150
- );
151
- }
152
- try {
153
- const element = React.createElement(Component);
154
- const html = await render(element);
155
- return html;
156
- } catch (err) {
157
- const message = err instanceof Error ? err.message : "Unknown rendering error";
158
- throw new Error(`React rendering error: ${message}`);
159
- }
160
- }
161
- export {
162
- compileReactEmail
163
- };
164
- //# sourceMappingURL=react-email-ZWLGXROP.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/compile/react-email.ts"],"sourcesContent":["import { createContext, Script } from \"node:vm\";\r\n\r\n/** Maximum source code size: 256KB */\r\nconst MAX_SOURCE_SIZE = 256_000;\r\n\r\n/** Execution timeout: 5 seconds */\r\nconst EXECUTION_TIMEOUT_MS = 5_000;\r\n\r\n/**\r\n * Compile a React Email JSX/TSX source string into an HTML email string.\r\n *\r\n * Ported from the webapp compiler, simplified for CLI use.\r\n * Uses sucrase for JSX transpilation and vm sandbox for safe execution.\r\n * Requires: sucrase, react, @react-email/components, @react-email/render\r\n */\r\nexport async function compileReactEmail(source: string): Promise<string> {\r\n // ── Validate ──────────────────────────────────────────────────────\r\n if (!source || !source.trim()) {\r\n throw new Error(\"JSX source must not be empty.\");\r\n }\r\n\r\n if (source.length > MAX_SOURCE_SIZE) {\r\n throw new Error(`JSX source exceeds ${MAX_SOURCE_SIZE / 1000}KB limit.`);\r\n }\r\n\r\n // ── Load optional dependencies ────────────────────────────────────\r\n let transform: typeof import(\"sucrase\").transform;\r\n let React: typeof import(\"react\");\r\n let ReactEmailComponents: typeof import(\"@react-email/components\");\r\n let render: typeof import(\"@react-email/render\").render;\r\n\r\n try {\r\n ({ transform } = await import(\"sucrase\"));\r\n } catch {\r\n throw new Error(\r\n 'JSX compilation requires \"sucrase\". Install it:\\n npm install sucrase'\r\n );\r\n }\r\n\r\n try {\r\n React = await import(\"react\");\r\n } catch {\r\n throw new Error(\r\n 'JSX compilation requires \"react\". Install it:\\n npm install react'\r\n );\r\n }\r\n\r\n try {\r\n ReactEmailComponents = await import(\"@react-email/components\");\r\n } catch {\r\n throw new Error(\r\n 'JSX compilation requires \"@react-email/components\". Install it:\\n npm install @react-email/components'\r\n );\r\n }\r\n\r\n try {\r\n ({ render } = await import(\"@react-email/render\"));\r\n } catch {\r\n throw new Error(\r\n 'JSX compilation requires \"@react-email/render\". Install it:\\n npm install @react-email/render'\r\n );\r\n }\r\n\r\n // ── Transpile JSX/TSX → CommonJS ──────────────────────────────────\r\n let transpiledCode: string;\r\n try {\r\n const result = transform(source, {\r\n transforms: [\"typescript\", \"jsx\", \"imports\"],\r\n jsxRuntime: \"classic\",\r\n production: true,\r\n });\r\n transpiledCode = result.code;\r\n } catch (err: unknown) {\r\n const message = err instanceof Error ? err.message : \"Unknown transpilation error\";\r\n throw new Error(`JSX syntax error: ${message}`);\r\n }\r\n\r\n // ── Execute in sandbox ────────────────────────────────────────────\r\n const ALLOWED_MODULES: Record<string, unknown> = {\r\n react: React,\r\n \"@react-email/components\": ReactEmailComponents,\r\n };\r\n\r\n const moduleExports: Record<string, unknown> = {};\r\n const moduleObj = { exports: moduleExports };\r\n\r\n const mockRequire = (moduleName: string): unknown => {\r\n if (moduleName in ALLOWED_MODULES) {\r\n return ALLOWED_MODULES[moduleName];\r\n }\r\n throw new Error(\r\n `Import of \"${moduleName}\" is not allowed. ` +\r\n `Only \"react\" and \"@react-email/components\" can be imported.`\r\n );\r\n };\r\n\r\n const sandbox: Record<string, unknown> = {\r\n module: moduleObj,\r\n exports: moduleExports,\r\n require: mockRequire,\r\n React,\r\n Object, Array, String, Number, Boolean,\r\n Map, Set, WeakMap, WeakSet,\r\n JSON, Math, Date, RegExp,\r\n Error, TypeError, RangeError, ReferenceError, SyntaxError, URIError,\r\n Promise, Symbol, Proxy, Reflect,\r\n parseInt, parseFloat, isNaN, isFinite,\r\n encodeURIComponent, decodeURIComponent, encodeURI, decodeURI,\r\n undefined, NaN, Infinity,\r\n console: { log: () => {}, warn: () => {}, error: () => {}, info: () => {}, debug: () => {} },\r\n setTimeout: undefined, setInterval: undefined, setImmediate: undefined, queueMicrotask: undefined,\r\n process: undefined, globalThis: undefined, global: undefined, Buffer: undefined,\r\n __dirname: undefined, __filename: undefined,\r\n };\r\n\r\n const context = createContext(sandbox, {\r\n codeGeneration: { strings: false, wasm: false },\r\n });\r\n\r\n try {\r\n const script = new Script(transpiledCode, { filename: \"user-email-component.tsx\" });\r\n script.runInContext(context, { timeout: EXECUTION_TIMEOUT_MS, displayErrors: true });\r\n } catch (err: unknown) {\r\n const message = err instanceof Error ? err.message : \"Unknown execution error\";\r\n if (message.includes(\"Script execution timed out\")) {\r\n throw new Error(\"JSX execution timed out (possible infinite loop).\");\r\n }\r\n throw new Error(`JSX execution error: ${message}`);\r\n }\r\n\r\n // ── Extract component and render ──────────────────────────────────\r\n let Component: unknown = moduleObj.exports.default ?? moduleObj.exports;\r\n\r\n if (typeof Component !== \"function\" && typeof Component === \"object\" && Component !== null) {\r\n const values = Object.values(Component as Record<string, unknown>);\r\n const fn = values.find((v) => typeof v === \"function\");\r\n if (fn) Component = fn;\r\n }\r\n\r\n if (typeof Component !== \"function\") {\r\n throw new Error(\r\n 'The JSX source must export a React component function. ' +\r\n 'Use \"export default function Email() { ... }\" or ' +\r\n '\"export function Email() { ... }\".'\r\n );\r\n }\r\n\r\n try {\r\n const element = React.createElement(Component as () => unknown);\r\n const html = await render(element);\r\n return html;\r\n } catch (err: unknown) {\r\n const message = err instanceof Error ? err.message : \"Unknown rendering error\";\r\n throw new Error(`React rendering error: ${message}`);\r\n }\r\n}\r\n"],"mappings":"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","names":[]}