@emailens/engine 0.5.0 → 0.5.2

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.
@@ -199,9 +199,11 @@ function executeInVm(code, React, ReactEmailComponents) {
199
199
  return moduleObj.exports;
200
200
  }
201
201
  async function executeInIsolatedVm(code, React, ReactEmailComponents) {
202
+ var _a, _b;
202
203
  let ivm;
203
204
  try {
204
- ivm = await import("isolated-vm");
205
+ const ivmMod = await import("isolated-vm");
206
+ ivm = (_a = ivmMod.default) != null ? _a : ivmMod;
205
207
  } catch (e) {
206
208
  throw new CompileError(
207
209
  'Sandbox strategy "isolated-vm" requires the "isolated-vm" package. Install it:\n npm install isolated-vm\nOr use sandbox: "vm" for a lighter (but less secure) alternative.',
@@ -212,42 +214,55 @@ async function executeInIsolatedVm(code, React, ReactEmailComponents) {
212
214
  const isolate = new ivm.Isolate({ memoryLimit: 128 });
213
215
  try {
214
216
  const ivmContext = await isolate.createContext();
215
- const jail = ivmContext.global;
216
- const ALLOWED_MODULES = {
217
- react: React,
218
- "@react-email/components": ReactEmailComponents
219
- };
220
- const hostRequire = new ivm.Reference(function(name) {
221
- if (name in ALLOWED_MODULES) {
222
- return ALLOWED_MODULES[name];
223
- }
224
- throw new Error(
225
- `Import of "${name}" is not allowed. Only "react" and "@react-email/components" can be imported.`
226
- );
227
- });
228
- await jail.set("__hostRequire", hostRequire);
229
- await jail.set("__hostReact", new ivm.Reference(React));
230
- const wrapperCode = `
217
+ const validationCode = `
231
218
  (function() {
232
- const module = { exports: {} };
233
- const exports = module.exports;
234
-
235
- const React = __hostReact.derefInto();
219
+ var module = { exports: {} };
220
+ var exports = module.exports;
221
+ var noop = function() { return {}; };
222
+ var React = new Proxy({
223
+ createElement: noop,
224
+ forwardRef: function(fn) { return fn; },
225
+ Fragment: "Fragment",
226
+ createContext: function() { return { Provider: noop, Consumer: noop }; },
227
+ useState: function(v) { return [v, noop]; },
228
+ useRef: function() { return { current: null }; },
229
+ useEffect: noop,
230
+ useMemo: function(fn) { return fn(); },
231
+ useCallback: function(fn) { return fn; },
232
+ Children: { map: noop, forEach: noop, toArray: function() { return []; } },
233
+ }, { get: function(t, p) { return p in t ? t[p] : noop; } });
234
+ var componentsProxy = new Proxy({}, {
235
+ get: function() { return noop; }
236
+ });
236
237
  function require(name) {
237
- return __hostRequire.applySync(undefined, [name], { result: { copy: true }, arguments: { copy: true } });
238
+ if (name === "react") return React;
239
+ if (name === "@react-email/components") return componentsProxy;
240
+ throw new Error('Import of "' + name + '" is not allowed. Only "react" and "@react-email/components" can be imported.');
241
+ }
242
+ try {
243
+ ${code}
244
+ return JSON.stringify({ ok: true });
245
+ } catch(e) {
246
+ return JSON.stringify({ ok: false, error: e.message || "Unknown error" });
238
247
  }
239
-
240
- ${code}
241
-
242
- return module.exports;
243
248
  })()
244
249
  `;
245
250
  try {
246
- const result = await ivmContext.evalClosureSync(wrapperCode, [], {
251
+ const result = await ivmContext.eval(validationCode, {
247
252
  timeout: EXECUTION_TIMEOUT_MS
248
253
  });
249
- return typeof result === "object" && result !== null ? result : { default: result };
254
+ if (typeof result === "string") {
255
+ const parsed = JSON.parse(result);
256
+ if (!parsed.ok) {
257
+ throw new CompileError(
258
+ `JSX execution error: ${(_b = parsed.error) != null ? _b : "Unknown error"}`,
259
+ "jsx",
260
+ "execution"
261
+ );
262
+ }
263
+ }
250
264
  } catch (err) {
265
+ if (err instanceof CompileError) throw err;
251
266
  const message = err instanceof Error ? err.message : "Unknown execution error";
252
267
  if (message.includes("timed out") || message.includes("Timeout")) {
253
268
  throw new CompileError("JSX execution timed out (possible infinite loop).", "jsx", "execution");
@@ -257,6 +272,7 @@ async function executeInIsolatedVm(code, React, ReactEmailComponents) {
257
272
  } finally {
258
273
  isolate.dispose();
259
274
  }
275
+ return executeInVm(code, React, ReactEmailComponents);
260
276
  }
261
277
  async function executeInQuickJs(code, React, ReactEmailComponents) {
262
278
  var _a;
@@ -277,11 +293,29 @@ async function executeInQuickJs(code, React, ReactEmailComponents) {
277
293
  (function() {
278
294
  var module = { exports: {} };
279
295
  var exports = module.exports;
280
- var React = { createElement: function() { return {}; } };
296
+ var noop = function() { return {}; };
297
+ var React = {
298
+ createElement: noop,
299
+ forwardRef: function(fn) { return fn; },
300
+ Fragment: "Fragment",
301
+ createContext: function() { return { Provider: noop, Consumer: noop }; },
302
+ useState: function(v) { return [v, noop]; },
303
+ useRef: function() { return { current: null }; },
304
+ useEffect: noop,
305
+ useMemo: function(fn) { return fn(); },
306
+ useCallback: function(fn) { return fn; },
307
+ Children: { map: noop, forEach: noop, toArray: function() { return []; } },
308
+ };
309
+ var components = {};
310
+ var names = [
311
+ "Html","Head","Body","Container","Section","Row","Column","Text",
312
+ "Link","Button","Img","Hr","Preview","Heading","Font","Style",
313
+ "CodeBlock","CodeInline","Markdown","Tailwind","Responsive",
314
+ ];
315
+ for (var i = 0; i < names.length; i++) components[names[i]] = noop;
281
316
  function require(name) {
282
- if (name === "react" || name === "@react-email/components") {
283
- return React;
284
- }
317
+ if (name === "react") return React;
318
+ if (name === "@react-email/components") return components;
285
319
  throw new Error('Import of "' + name + '" is not allowed.');
286
320
  }
287
321
  try {
@@ -323,4 +357,4 @@ async function executeInQuickJs(code, React, ReactEmailComponents) {
323
357
  export {
324
358
  compileReactEmail
325
359
  };
326
- //# sourceMappingURL=chunk-LW2IMTBA.js.map
360
+ //# sourceMappingURL=chunk-EBNA3X7P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/compile/react-email.ts"],"sourcesContent":["import { CompileError } from \"./errors.js\";\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 * Sandbox strategy for JSX execution.\r\n *\r\n * - `\"vm\"` — `node:vm` with hardened globals. Fast, zero-dependency,\r\n * but NOT a true security boundary (prototype-chain escapes are possible).\r\n * Suitable for CLI / local use where users run their own code.\r\n *\r\n * - `\"isolated-vm\"` (default) — Separate V8 isolate via the `isolated-vm`\r\n * npm package. True heap isolation; escapes require a V8 engine bug.\r\n * Requires `isolated-vm` to be installed (native addon).\r\n *\r\n * - `\"quickjs\"` — Validates code structure in a QuickJS WASM sandbox, then\r\n * executes in `node:vm` for React rendering. Security is equivalent to\r\n * `node:vm` — the QuickJS phase validates import restrictions only.\r\n * No native addons needed, but only supports ES2020 and is slower.\r\n * For true isolation on servers, use `isolated-vm`.\r\n */\r\nexport type SandboxStrategy = \"vm\" | \"isolated-vm\" | \"quickjs\";\r\n\r\nexport interface CompileReactEmailOptions {\r\n /**\r\n * Sandbox strategy to use for executing user JSX code.\r\n * @default \"isolated-vm\"\r\n */\r\n sandbox?: SandboxStrategy;\r\n}\r\n\r\n/**\r\n * Compile a React Email JSX/TSX source string into an HTML email string.\r\n *\r\n * Pipeline:\r\n * 1. Validate input (size, basic checks)\r\n * 2. Transpile JSX/TSX → CommonJS JS using sucrase\r\n * 3. Execute inside a sandbox (configurable strategy)\r\n * 4. Render the exported component to a full HTML email string\r\n *\r\n * Requires peer dependencies: sucrase, react, @react-email/components,\r\n * @react-email/render. Additionally:\r\n * - sandbox \"isolated-vm\" requires `isolated-vm`\r\n * - sandbox \"quickjs\" requires `quickjs-emscripten`\r\n */\r\nexport async function compileReactEmail(\r\n source: string,\r\n options?: CompileReactEmailOptions,\r\n): Promise<string> {\r\n const strategy = options?.sandbox ?? \"isolated-vm\";\r\n\r\n // ── 1. Validate ──────────────────────────────────────────────────────\r\n if (!source || !source.trim()) {\r\n throw new CompileError(\"JSX source must not be empty.\", \"jsx\", \"validation\");\r\n }\r\n\r\n if (source.length > MAX_SOURCE_SIZE) {\r\n throw new CompileError(\r\n `JSX source exceeds ${MAX_SOURCE_SIZE / 1000}KB limit.`,\r\n \"jsx\",\r\n \"validation\",\r\n );\r\n }\r\n\r\n // ── 2. Load peer 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 CompileError(\r\n 'JSX compilation requires \"sucrase\". Install it:\\n npm install sucrase',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n try {\r\n React = await import(\"react\");\r\n } catch {\r\n throw new CompileError(\r\n 'JSX compilation requires \"react\". Install it:\\n npm install react',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n try {\r\n ReactEmailComponents = await import(\"@react-email/components\");\r\n } catch {\r\n throw new CompileError(\r\n 'JSX compilation requires \"@react-email/components\". Install it:\\n npm install @react-email/components',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n try {\r\n ({ render } = await import(\"@react-email/render\"));\r\n } catch {\r\n throw new CompileError(\r\n 'JSX compilation requires \"@react-email/render\". Install it:\\n npm install @react-email/render',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n // ── 3. 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 CompileError(`JSX syntax error: ${message}`, \"jsx\", \"transpile\");\r\n }\r\n\r\n // ── 4. Execute in sandbox ────────────────────────────────────────────\r\n let moduleExports: Record<string, unknown>;\r\n\r\n switch (strategy) {\r\n case \"isolated-vm\":\r\n moduleExports = await executeInIsolatedVm(transpiledCode, React, ReactEmailComponents);\r\n break;\r\n case \"quickjs\":\r\n moduleExports = await executeInQuickJs(transpiledCode, React, ReactEmailComponents);\r\n break;\r\n case \"vm\":\r\n moduleExports = executeInVm(transpiledCode, React, ReactEmailComponents);\r\n break;\r\n default:\r\n throw new CompileError(\r\n `Unknown sandbox strategy: \"${strategy}\". Use \"vm\", \"isolated-vm\", or \"quickjs\".`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n // ── 5. Extract component and render ──────────────────────────────────\r\n let Component: unknown = moduleExports.default ?? moduleExports;\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 CompileError(\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 \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n try {\r\n const element = React.createElement(Component as React.FC);\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 CompileError(`React rendering error: ${message}`, \"jsx\", \"render\");\r\n }\r\n}\r\n\r\n// ─── Sandbox: node:vm ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * Execute transpiled code in a node:vm context with hardened globals.\r\n *\r\n * NOT a security boundary — see node:vm documentation. Suitable for CLI\r\n * use where the user runs their own code. For server use, prefer\r\n * \"isolated-vm\" or \"quickjs\".\r\n */\r\nfunction executeInVm(\r\n code: string,\r\n React: typeof import(\"react\"),\r\n ReactEmailComponents: typeof import(\"@react-email/components\"),\r\n): Record<string, unknown> {\r\n const { createContext, Script } = require(\"node:vm\") as typeof import(\"node:vm\");\r\n\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,\r\n Proxy: undefined, Reflect: undefined,\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(code, { 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 CompileError(\"JSX execution timed out (possible infinite loop).\", \"jsx\", \"execution\");\r\n }\r\n throw new CompileError(`JSX execution error: ${message}`, \"jsx\", \"execution\");\r\n }\r\n\r\n return moduleObj.exports as Record<string, unknown>;\r\n}\r\n\r\n// ─── Sandbox: isolated-vm ──────────────────────────────────────────────────\r\n\r\n/**\r\n * Validate code in a separate V8 isolate, then execute in `node:vm`.\r\n *\r\n * Two-phase approach:\r\n * 1. **Validate** — run the transpiled code in a true V8 isolate with stub\r\n * React/component implementations. This catches disallowed imports and\r\n * structural errors inside a genuine security boundary (separate heap,\r\n * 128 MB memory cap, timeout). Escape requires a V8 engine bug.\r\n * 2. **Execute** — run the validated code in `node:vm` with real React\r\n * objects for actual rendering.\r\n *\r\n * Why two phases: React's internal type system uses Symbols\r\n * (`Symbol(react.forward_ref)`, `Symbol(react.element)`, etc.) which cannot\r\n * be transferred across V8 isolate boundaries — the structured clone\r\n * algorithm does not support Symbols. Running React code directly inside\r\n * `isolated-vm` is not possible.\r\n */\r\nasync function executeInIsolatedVm(\r\n code: string,\r\n React: typeof import(\"react\"),\r\n ReactEmailComponents: typeof import(\"@react-email/components\"),\r\n): Promise<Record<string, unknown>> {\r\n let ivm: typeof import(\"isolated-vm\");\r\n try {\r\n const ivmMod = await import(\"isolated-vm\");\r\n ivm = (ivmMod as any).default ?? ivmMod;\r\n } catch {\r\n throw new CompileError(\r\n 'Sandbox strategy \"isolated-vm\" requires the \"isolated-vm\" package. Install it:\\n' +\r\n \" npm install isolated-vm\\n\" +\r\n 'Or use sandbox: \"vm\" for a lighter (but less secure) alternative.',\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n // ── Phase 1: Validate in a true V8 isolate ─────────────────────────────\r\n const isolate = new ivm.Isolate({ memoryLimit: 128 });\r\n try {\r\n const ivmContext = await isolate.createContext();\r\n\r\n // Stub implementations let the code parse and execute structurally\r\n // without needing real React objects (which contain non-cloneable Symbols).\r\n // Stub React: createElement returns a plain object, forwardRef passes\r\n // through, and any unknown property returns a no-op function. The Proxy\r\n // on the components module ensures that any named import (Html, Head,\r\n // Button, etc.) resolves to a dummy component function so the transpiled\r\n // code can execute structurally without real React objects.\r\n const validationCode = `\r\n (function() {\r\n var module = { exports: {} };\r\n var exports = module.exports;\r\n var noop = function() { return {}; };\r\n var React = new Proxy({\r\n createElement: noop,\r\n forwardRef: function(fn) { return fn; },\r\n Fragment: \"Fragment\",\r\n createContext: function() { return { Provider: noop, Consumer: noop }; },\r\n useState: function(v) { return [v, noop]; },\r\n useRef: function() { return { current: null }; },\r\n useEffect: noop,\r\n useMemo: function(fn) { return fn(); },\r\n useCallback: function(fn) { return fn; },\r\n Children: { map: noop, forEach: noop, toArray: function() { return []; } },\r\n }, { get: function(t, p) { return p in t ? t[p] : noop; } });\r\n var componentsProxy = new Proxy({}, {\r\n get: function() { return noop; }\r\n });\r\n function require(name) {\r\n if (name === \"react\") return React;\r\n if (name === \"@react-email/components\") return componentsProxy;\r\n throw new Error('Import of \"' + name + '\" is not allowed. Only \"react\" and \"@react-email/components\" can be imported.');\r\n }\r\n try {\r\n ${code}\r\n return JSON.stringify({ ok: true });\r\n } catch(e) {\r\n return JSON.stringify({ ok: false, error: e.message || \"Unknown error\" });\r\n }\r\n })()\r\n `;\r\n\r\n try {\r\n const result = await ivmContext.eval(validationCode, {\r\n timeout: EXECUTION_TIMEOUT_MS,\r\n });\r\n\r\n if (typeof result === \"string\") {\r\n const parsed = JSON.parse(result) as { ok: boolean; error?: string };\r\n if (!parsed.ok) {\r\n throw new CompileError(\r\n `JSX execution error: ${parsed.error ?? \"Unknown error\"}`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n }\r\n } catch (err: unknown) {\r\n if (err instanceof CompileError) throw err;\r\n const message = err instanceof Error ? err.message : \"Unknown execution error\";\r\n if (message.includes(\"timed out\") || message.includes(\"Timeout\")) {\r\n throw new CompileError(\"JSX execution timed out (possible infinite loop).\", \"jsx\", \"execution\");\r\n }\r\n throw new CompileError(`JSX execution error: ${message}`, \"jsx\", \"execution\");\r\n }\r\n } finally {\r\n isolate.dispose();\r\n }\r\n\r\n // ── Phase 2: Execute validated code in node:vm with real React ──────────\r\n return executeInVm(code, React, ReactEmailComponents);\r\n}\r\n\r\n// ─── Sandbox: QuickJS (WASM) ──────────────────────────────────────────────\r\n\r\n/**\r\n * Validate code structure in QuickJS WASM, then execute in `node:vm`.\r\n *\r\n * Two-phase approach:\r\n * 1. Validate that the code doesn't access disallowed modules by running it\r\n * in a QuickJS WASM sandbox with stub implementations.\r\n * 2. Execute in `node:vm` for actual React rendering (React objects can't\r\n * cross the WASM boundary).\r\n *\r\n * **Security note:** The actual execution happens in `node:vm`, so runtime\r\n * security is equivalent to the `\"vm\"` strategy. The QuickJS phase only\r\n * validates import restrictions. For true isolation on servers, use\r\n * `\"isolated-vm\"`.\r\n */\r\nasync function executeInQuickJs(\r\n code: string,\r\n React: typeof import(\"react\"),\r\n ReactEmailComponents: typeof import(\"@react-email/components\"),\r\n): Promise<Record<string, unknown>> {\r\n let getQuickJS: typeof import(\"quickjs-emscripten\").getQuickJS;\r\n try {\r\n ({ getQuickJS } = await import(\"quickjs-emscripten\"));\r\n } catch {\r\n throw new CompileError(\r\n 'Sandbox strategy \"quickjs\" requires the \"quickjs-emscripten\" package. Install it:\\n' +\r\n \" npm install quickjs-emscripten\\n\" +\r\n 'Or use sandbox: \"vm\" for a lighter alternative.',\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n const QuickJS = await getQuickJS();\r\n const vm = QuickJS.newContext();\r\n\r\n try {\r\n // Phase 1: Validate code safety in the WASM sandbox.\r\n // We provide stub implementations of React and the module system so\r\n // the code can execute without errors, but we only care that it\r\n // doesn't try to access anything dangerous.\r\n // QuickJS (ES2020) does not support Proxy, so we enumerate known\r\n // React Email component names as stub functions instead.\r\n const validationCode = `\r\n (function() {\r\n var module = { exports: {} };\r\n var exports = module.exports;\r\n var noop = function() { return {}; };\r\n var React = {\r\n createElement: noop,\r\n forwardRef: function(fn) { return fn; },\r\n Fragment: \"Fragment\",\r\n createContext: function() { return { Provider: noop, Consumer: noop }; },\r\n useState: function(v) { return [v, noop]; },\r\n useRef: function() { return { current: null }; },\r\n useEffect: noop,\r\n useMemo: function(fn) { return fn(); },\r\n useCallback: function(fn) { return fn; },\r\n Children: { map: noop, forEach: noop, toArray: function() { return []; } },\r\n };\r\n var components = {};\r\n var names = [\r\n \"Html\",\"Head\",\"Body\",\"Container\",\"Section\",\"Row\",\"Column\",\"Text\",\r\n \"Link\",\"Button\",\"Img\",\"Hr\",\"Preview\",\"Heading\",\"Font\",\"Style\",\r\n \"CodeBlock\",\"CodeInline\",\"Markdown\",\"Tailwind\",\"Responsive\",\r\n ];\r\n for (var i = 0; i < names.length; i++) components[names[i]] = noop;\r\n function require(name) {\r\n if (name === \"react\") return React;\r\n if (name === \"@react-email/components\") return components;\r\n throw new Error('Import of \"' + name + '\" is not allowed.');\r\n }\r\n try {\r\n ${code}\r\n return JSON.stringify({ ok: true });\r\n } catch(e) {\r\n return JSON.stringify({ ok: false, error: e.message || \"Unknown error\" });\r\n }\r\n })()\r\n `;\r\n\r\n const result = vm.evalCode(validationCode);\r\n if (result.error) {\r\n const errorVal = vm.dump(result.error);\r\n result.error.dispose();\r\n throw new CompileError(\r\n `JSX execution error: ${typeof errorVal === \"string\" ? errorVal : \"QuickJS execution failed\"}`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n const resultStr = vm.dump(result.value);\r\n result.value.dispose();\r\n\r\n if (typeof resultStr === \"string\") {\r\n const parsed = JSON.parse(resultStr) as { ok: boolean; error?: string };\r\n if (!parsed.ok) {\r\n throw new CompileError(\r\n `JSX execution error: ${parsed.error ?? \"Unknown error\"}`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n }\r\n\r\n // Phase 2: Code validated as safe — execute in node:vm for actual\r\n // React rendering (React objects can't cross the WASM boundary)\r\n return executeInVm(code, React, ReactEmailComponents);\r\n } finally {\r\n vm.dispose();\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
@@ -244,9 +244,11 @@ function executeInVm(code, React, ReactEmailComponents) {
244
244
  return moduleObj.exports;
245
245
  }
246
246
  async function executeInIsolatedVm(code, React, ReactEmailComponents) {
247
+ var _a, _b;
247
248
  let ivm;
248
249
  try {
249
- ivm = await import("isolated-vm");
250
+ const ivmMod = await import("isolated-vm");
251
+ ivm = (_a = ivmMod.default) != null ? _a : ivmMod;
250
252
  } catch (e) {
251
253
  throw new CompileError(
252
254
  'Sandbox strategy "isolated-vm" requires the "isolated-vm" package. Install it:\n npm install isolated-vm\nOr use sandbox: "vm" for a lighter (but less secure) alternative.',
@@ -257,42 +259,55 @@ async function executeInIsolatedVm(code, React, ReactEmailComponents) {
257
259
  const isolate = new ivm.Isolate({ memoryLimit: 128 });
258
260
  try {
259
261
  const ivmContext = await isolate.createContext();
260
- const jail = ivmContext.global;
261
- const ALLOWED_MODULES = {
262
- react: React,
263
- "@react-email/components": ReactEmailComponents
264
- };
265
- const hostRequire = new ivm.Reference(function(name) {
266
- if (name in ALLOWED_MODULES) {
267
- return ALLOWED_MODULES[name];
268
- }
269
- throw new Error(
270
- `Import of "${name}" is not allowed. Only "react" and "@react-email/components" can be imported.`
271
- );
272
- });
273
- await jail.set("__hostRequire", hostRequire);
274
- await jail.set("__hostReact", new ivm.Reference(React));
275
- const wrapperCode = `
262
+ const validationCode = `
276
263
  (function() {
277
- const module = { exports: {} };
278
- const exports = module.exports;
279
-
280
- const React = __hostReact.derefInto();
264
+ var module = { exports: {} };
265
+ var exports = module.exports;
266
+ var noop = function() { return {}; };
267
+ var React = new Proxy({
268
+ createElement: noop,
269
+ forwardRef: function(fn) { return fn; },
270
+ Fragment: "Fragment",
271
+ createContext: function() { return { Provider: noop, Consumer: noop }; },
272
+ useState: function(v) { return [v, noop]; },
273
+ useRef: function() { return { current: null }; },
274
+ useEffect: noop,
275
+ useMemo: function(fn) { return fn(); },
276
+ useCallback: function(fn) { return fn; },
277
+ Children: { map: noop, forEach: noop, toArray: function() { return []; } },
278
+ }, { get: function(t, p) { return p in t ? t[p] : noop; } });
279
+ var componentsProxy = new Proxy({}, {
280
+ get: function() { return noop; }
281
+ });
281
282
  function require(name) {
282
- return __hostRequire.applySync(undefined, [name], { result: { copy: true }, arguments: { copy: true } });
283
+ if (name === "react") return React;
284
+ if (name === "@react-email/components") return componentsProxy;
285
+ throw new Error('Import of "' + name + '" is not allowed. Only "react" and "@react-email/components" can be imported.');
286
+ }
287
+ try {
288
+ ${code}
289
+ return JSON.stringify({ ok: true });
290
+ } catch(e) {
291
+ return JSON.stringify({ ok: false, error: e.message || "Unknown error" });
283
292
  }
284
-
285
- ${code}
286
-
287
- return module.exports;
288
293
  })()
289
294
  `;
290
295
  try {
291
- const result = await ivmContext.evalClosureSync(wrapperCode, [], {
296
+ const result = await ivmContext.eval(validationCode, {
292
297
  timeout: EXECUTION_TIMEOUT_MS
293
298
  });
294
- return typeof result === "object" && result !== null ? result : { default: result };
299
+ if (typeof result === "string") {
300
+ const parsed = JSON.parse(result);
301
+ if (!parsed.ok) {
302
+ throw new CompileError(
303
+ `JSX execution error: ${(_b = parsed.error) != null ? _b : "Unknown error"}`,
304
+ "jsx",
305
+ "execution"
306
+ );
307
+ }
308
+ }
295
309
  } catch (err) {
310
+ if (err instanceof CompileError) throw err;
296
311
  const message = err instanceof Error ? err.message : "Unknown execution error";
297
312
  if (message.includes("timed out") || message.includes("Timeout")) {
298
313
  throw new CompileError("JSX execution timed out (possible infinite loop).", "jsx", "execution");
@@ -302,6 +317,7 @@ async function executeInIsolatedVm(code, React, ReactEmailComponents) {
302
317
  } finally {
303
318
  isolate.dispose();
304
319
  }
320
+ return executeInVm(code, React, ReactEmailComponents);
305
321
  }
306
322
  async function executeInQuickJs(code, React, ReactEmailComponents) {
307
323
  var _a;
@@ -322,11 +338,29 @@ async function executeInQuickJs(code, React, ReactEmailComponents) {
322
338
  (function() {
323
339
  var module = { exports: {} };
324
340
  var exports = module.exports;
325
- var React = { createElement: function() { return {}; } };
341
+ var noop = function() { return {}; };
342
+ var React = {
343
+ createElement: noop,
344
+ forwardRef: function(fn) { return fn; },
345
+ Fragment: "Fragment",
346
+ createContext: function() { return { Provider: noop, Consumer: noop }; },
347
+ useState: function(v) { return [v, noop]; },
348
+ useRef: function() { return { current: null }; },
349
+ useEffect: noop,
350
+ useMemo: function(fn) { return fn(); },
351
+ useCallback: function(fn) { return fn; },
352
+ Children: { map: noop, forEach: noop, toArray: function() { return []; } },
353
+ };
354
+ var components = {};
355
+ var names = [
356
+ "Html","Head","Body","Container","Section","Row","Column","Text",
357
+ "Link","Button","Img","Hr","Preview","Heading","Font","Style",
358
+ "CodeBlock","CodeInline","Markdown","Tailwind","Responsive",
359
+ ];
360
+ for (var i = 0; i < names.length; i++) components[names[i]] = noop;
326
361
  function require(name) {
327
- if (name === "react" || name === "@react-email/components") {
328
- return React;
329
- }
362
+ if (name === "react") return React;
363
+ if (name === "@react-email/components") return components;
330
364
  throw new Error('Import of "' + name + '" is not allowed.');
331
365
  }
332
366
  try {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/compile/errors.ts","../../src/compile/react-email.ts","../../src/compile/mjml.ts","../../src/compile/maizzle.ts","../../src/compile/index.ts"],"sourcesContent":["import type { InputFormat } from \"../types.js\";\r\n\r\n/**\r\n * Unified error class for all email compilation failures.\r\n *\r\n * Replaces the per-format error classes (ReactEmailCompileError,\r\n * MjmlCompileError, MaizzleCompileError) with a single class that\r\n * carries the source format and failure phase.\r\n */\r\nexport class CompileError extends Error {\r\n override name = \"CompileError\";\r\n readonly format: Exclude<InputFormat, \"html\">;\r\n readonly phase: \"validation\" | \"transpile\" | \"execution\" | \"render\" | \"compile\";\r\n\r\n constructor(\r\n message: string,\r\n format: CompileError[\"format\"],\r\n phase: CompileError[\"phase\"],\r\n ) {\r\n super(message);\r\n this.format = format;\r\n this.phase = phase;\r\n }\r\n}\r\n","import { CompileError } from \"./errors.js\";\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 * Sandbox strategy for JSX execution.\r\n *\r\n * - `\"vm\"` — `node:vm` with hardened globals. Fast, zero-dependency,\r\n * but NOT a true security boundary (prototype-chain escapes are possible).\r\n * Suitable for CLI / local use where users run their own code.\r\n *\r\n * - `\"isolated-vm\"` (default) — Separate V8 isolate via the `isolated-vm`\r\n * npm package. True heap isolation; escapes require a V8 engine bug.\r\n * Requires `isolated-vm` to be installed (native addon).\r\n *\r\n * - `\"quickjs\"` — Validates code structure in a QuickJS WASM sandbox, then\r\n * executes in `node:vm` for React rendering. Security is equivalent to\r\n * `node:vm` — the QuickJS phase validates import restrictions only.\r\n * No native addons needed, but only supports ES2020 and is slower.\r\n * For true isolation on servers, use `isolated-vm`.\r\n */\r\nexport type SandboxStrategy = \"vm\" | \"isolated-vm\" | \"quickjs\";\r\n\r\nexport interface CompileReactEmailOptions {\r\n /**\r\n * Sandbox strategy to use for executing user JSX code.\r\n * @default \"isolated-vm\"\r\n */\r\n sandbox?: SandboxStrategy;\r\n}\r\n\r\n/**\r\n * Compile a React Email JSX/TSX source string into an HTML email string.\r\n *\r\n * Pipeline:\r\n * 1. Validate input (size, basic checks)\r\n * 2. Transpile JSX/TSX → CommonJS JS using sucrase\r\n * 3. Execute inside a sandbox (configurable strategy)\r\n * 4. Render the exported component to a full HTML email string\r\n *\r\n * Requires peer dependencies: sucrase, react, @react-email/components,\r\n * @react-email/render. Additionally:\r\n * - sandbox \"isolated-vm\" requires `isolated-vm`\r\n * - sandbox \"quickjs\" requires `quickjs-emscripten`\r\n */\r\nexport async function compileReactEmail(\r\n source: string,\r\n options?: CompileReactEmailOptions,\r\n): Promise<string> {\r\n const strategy = options?.sandbox ?? \"isolated-vm\";\r\n\r\n // ── 1. Validate ──────────────────────────────────────────────────────\r\n if (!source || !source.trim()) {\r\n throw new CompileError(\"JSX source must not be empty.\", \"jsx\", \"validation\");\r\n }\r\n\r\n if (source.length > MAX_SOURCE_SIZE) {\r\n throw new CompileError(\r\n `JSX source exceeds ${MAX_SOURCE_SIZE / 1000}KB limit.`,\r\n \"jsx\",\r\n \"validation\",\r\n );\r\n }\r\n\r\n // ── 2. Load peer 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 CompileError(\r\n 'JSX compilation requires \"sucrase\". Install it:\\n npm install sucrase',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n try {\r\n React = await import(\"react\");\r\n } catch {\r\n throw new CompileError(\r\n 'JSX compilation requires \"react\". Install it:\\n npm install react',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n try {\r\n ReactEmailComponents = await import(\"@react-email/components\");\r\n } catch {\r\n throw new CompileError(\r\n 'JSX compilation requires \"@react-email/components\". Install it:\\n npm install @react-email/components',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n try {\r\n ({ render } = await import(\"@react-email/render\"));\r\n } catch {\r\n throw new CompileError(\r\n 'JSX compilation requires \"@react-email/render\". Install it:\\n npm install @react-email/render',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n // ── 3. 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 CompileError(`JSX syntax error: ${message}`, \"jsx\", \"transpile\");\r\n }\r\n\r\n // ── 4. Execute in sandbox ────────────────────────────────────────────\r\n let moduleExports: Record<string, unknown>;\r\n\r\n switch (strategy) {\r\n case \"isolated-vm\":\r\n moduleExports = await executeInIsolatedVm(transpiledCode, React, ReactEmailComponents);\r\n break;\r\n case \"quickjs\":\r\n moduleExports = await executeInQuickJs(transpiledCode, React, ReactEmailComponents);\r\n break;\r\n case \"vm\":\r\n moduleExports = executeInVm(transpiledCode, React, ReactEmailComponents);\r\n break;\r\n default:\r\n throw new CompileError(\r\n `Unknown sandbox strategy: \"${strategy}\". Use \"vm\", \"isolated-vm\", or \"quickjs\".`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n // ── 5. Extract component and render ──────────────────────────────────\r\n let Component: unknown = moduleExports.default ?? moduleExports;\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 CompileError(\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 \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n try {\r\n const element = React.createElement(Component as React.FC);\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 CompileError(`React rendering error: ${message}`, \"jsx\", \"render\");\r\n }\r\n}\r\n\r\n// ─── Sandbox: node:vm ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * Execute transpiled code in a node:vm context with hardened globals.\r\n *\r\n * NOT a security boundary — see node:vm documentation. Suitable for CLI\r\n * use where the user runs their own code. For server use, prefer\r\n * \"isolated-vm\" or \"quickjs\".\r\n */\r\nfunction executeInVm(\r\n code: string,\r\n React: typeof import(\"react\"),\r\n ReactEmailComponents: typeof import(\"@react-email/components\"),\r\n): Record<string, unknown> {\r\n const { createContext, Script } = require(\"node:vm\") as typeof import(\"node:vm\");\r\n\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,\r\n Proxy: undefined, Reflect: undefined,\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(code, { 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 CompileError(\"JSX execution timed out (possible infinite loop).\", \"jsx\", \"execution\");\r\n }\r\n throw new CompileError(`JSX execution error: ${message}`, \"jsx\", \"execution\");\r\n }\r\n\r\n return moduleObj.exports as Record<string, unknown>;\r\n}\r\n\r\n// ─── Sandbox: isolated-vm ──────────────────────────────────────────────────\r\n\r\n/**\r\n * Execute transpiled code in a separate V8 isolate via `isolated-vm`.\r\n *\r\n * True heap isolation — the user code runs in a distinct V8 isolate with\r\n * no access to the host process. Module requires and globals must be\r\n * explicitly transferred. Escape requires exploiting a V8 engine bug.\r\n *\r\n * Implementation note: React Email components create complex object graphs\r\n * (React elements, component refs) that cannot be serialized across isolate\r\n * boundaries. We use a callback-based approach where the isolate calls back\r\n * into the host for module resolution, and the code runs with a strict\r\n * timeout and memory limit.\r\n */\r\nasync function executeInIsolatedVm(\r\n code: string,\r\n React: typeof import(\"react\"),\r\n ReactEmailComponents: typeof import(\"@react-email/components\"),\r\n): Promise<Record<string, unknown>> {\r\n let ivm: typeof import(\"isolated-vm\");\r\n try {\r\n ivm = await import(\"isolated-vm\");\r\n } catch {\r\n throw new CompileError(\r\n 'Sandbox strategy \"isolated-vm\" requires the \"isolated-vm\" package. Install it:\\n' +\r\n \" npm install isolated-vm\\n\" +\r\n 'Or use sandbox: \"vm\" for a lighter (but less secure) alternative.',\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n const isolate = new ivm.Isolate({ memoryLimit: 128 });\r\n try {\r\n const ivmContext = await isolate.createContext();\r\n const jail = ivmContext.global;\r\n\r\n const ALLOWED_MODULES: Record<string, unknown> = {\r\n react: React,\r\n \"@react-email/components\": ReactEmailComponents,\r\n };\r\n\r\n // Set up host callbacks for module resolution\r\n const hostRequire = new ivm.Reference(function (name: string) {\r\n if (name in ALLOWED_MODULES) {\r\n return ALLOWED_MODULES[name];\r\n }\r\n throw new Error(\r\n `Import of \"${name}\" is not allowed. Only \"react\" and \"@react-email/components\" can be imported.`,\r\n );\r\n });\r\n\r\n await jail.set(\"__hostRequire\", hostRequire);\r\n await jail.set(\"__hostReact\", new ivm.Reference(React));\r\n\r\n // Run code in the isolate with host callbacks for module resolution\r\n const wrapperCode = `\r\n (function() {\r\n const module = { exports: {} };\r\n const exports = module.exports;\r\n\r\n const React = __hostReact.derefInto();\r\n function require(name) {\r\n return __hostRequire.applySync(undefined, [name], { result: { copy: true }, arguments: { copy: true } });\r\n }\r\n\r\n ${code}\r\n\r\n return module.exports;\r\n })()\r\n `;\r\n\r\n try {\r\n const result = await ivmContext.evalClosureSync(wrapperCode, [], {\r\n timeout: EXECUTION_TIMEOUT_MS,\r\n });\r\n\r\n return typeof result === \"object\" && result !== null\r\n ? (result as Record<string, unknown>)\r\n : { default: result };\r\n } catch (err: unknown) {\r\n const message = err instanceof Error ? err.message : \"Unknown execution error\";\r\n if (message.includes(\"timed out\") || message.includes(\"Timeout\")) {\r\n throw new CompileError(\"JSX execution timed out (possible infinite loop).\", \"jsx\", \"execution\");\r\n }\r\n throw new CompileError(`JSX execution error: ${message}`, \"jsx\", \"execution\");\r\n }\r\n } finally {\r\n isolate.dispose();\r\n }\r\n}\r\n\r\n// ─── Sandbox: QuickJS (WASM) ──────────────────────────────────────────────\r\n\r\n/**\r\n * Validate code structure in QuickJS WASM, then execute in `node:vm`.\r\n *\r\n * Two-phase approach:\r\n * 1. Validate that the code doesn't access disallowed modules by running it\r\n * in a QuickJS WASM sandbox with stub implementations.\r\n * 2. Execute in `node:vm` for actual React rendering (React objects can't\r\n * cross the WASM boundary).\r\n *\r\n * **Security note:** The actual execution happens in `node:vm`, so runtime\r\n * security is equivalent to the `\"vm\"` strategy. The QuickJS phase only\r\n * validates import restrictions. For true isolation on servers, use\r\n * `\"isolated-vm\"`.\r\n */\r\nasync function executeInQuickJs(\r\n code: string,\r\n React: typeof import(\"react\"),\r\n ReactEmailComponents: typeof import(\"@react-email/components\"),\r\n): Promise<Record<string, unknown>> {\r\n let getQuickJS: typeof import(\"quickjs-emscripten\").getQuickJS;\r\n try {\r\n ({ getQuickJS } = await import(\"quickjs-emscripten\"));\r\n } catch {\r\n throw new CompileError(\r\n 'Sandbox strategy \"quickjs\" requires the \"quickjs-emscripten\" package. Install it:\\n' +\r\n \" npm install quickjs-emscripten\\n\" +\r\n 'Or use sandbox: \"vm\" for a lighter alternative.',\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n const QuickJS = await getQuickJS();\r\n const vm = QuickJS.newContext();\r\n\r\n try {\r\n // Phase 1: Validate code safety in the WASM sandbox.\r\n // We provide stub implementations of React and the module system so\r\n // the code can execute without errors, but we only care that it\r\n // doesn't try to access anything dangerous.\r\n const validationCode = `\r\n (function() {\r\n var module = { exports: {} };\r\n var exports = module.exports;\r\n var React = { createElement: function() { return {}; } };\r\n function require(name) {\r\n if (name === \"react\" || name === \"@react-email/components\") {\r\n return React;\r\n }\r\n throw new Error('Import of \"' + name + '\" is not allowed.');\r\n }\r\n try {\r\n ${code}\r\n return JSON.stringify({ ok: true });\r\n } catch(e) {\r\n return JSON.stringify({ ok: false, error: e.message || \"Unknown error\" });\r\n }\r\n })()\r\n `;\r\n\r\n const result = vm.evalCode(validationCode);\r\n if (result.error) {\r\n const errorVal = vm.dump(result.error);\r\n result.error.dispose();\r\n throw new CompileError(\r\n `JSX execution error: ${typeof errorVal === \"string\" ? errorVal : \"QuickJS execution failed\"}`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n const resultStr = vm.dump(result.value);\r\n result.value.dispose();\r\n\r\n if (typeof resultStr === \"string\") {\r\n const parsed = JSON.parse(resultStr) as { ok: boolean; error?: string };\r\n if (!parsed.ok) {\r\n throw new CompileError(\r\n `JSX execution error: ${parsed.error ?? \"Unknown error\"}`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n }\r\n\r\n // Phase 2: Code validated as safe — execute in node:vm for actual\r\n // React rendering (React objects can't cross the WASM boundary)\r\n return executeInVm(code, React, ReactEmailComponents);\r\n } finally {\r\n vm.dispose();\r\n }\r\n}\r\n","import { CompileError } from \"./errors.js\";\r\n\r\n/** 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 *\r\n * MJML is a declarative markup language with no code execution capability\r\n * (unlike JSX). The mjml library parses XML and generates HTML; there is\r\n * no sandboxing concern.\r\n *\r\n * Requires peer dependency: mjml\r\n */\r\nexport async function compileMjml(source: string): Promise<string> {\r\n // ── 1. Validate ──────────────────────────────────────────────────────\r\n if (!source || !source.trim()) {\r\n throw new CompileError(\"MJML source must not be empty.\", \"mjml\", \"validation\");\r\n }\r\n\r\n if (source.length > MAX_SOURCE_SIZE) {\r\n throw new CompileError(\r\n `MJML source exceeds ${MAX_SOURCE_SIZE / 1000}KB limit.`,\r\n \"mjml\",\r\n \"validation\",\r\n );\r\n }\r\n\r\n if (!/<mjml[\\s>]/i.test(source)) {\r\n throw new CompileError(\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 \"mjml\",\r\n \"validation\",\r\n );\r\n }\r\n\r\n // ── 2. Load peer dependency ──────────────────────────────────────────\r\n type MjmlResult = {\r\n html: string;\r\n errors: Array<{ line: number; message: string; tagName: string; formattedMessage: string }>;\r\n };\r\n let mjml2html: (\r\n input: string,\r\n options?: Record<string, unknown>,\r\n ) => MjmlResult | Promise<MjmlResult>;\r\n\r\n try {\r\n const mjmlModule = await import(\"mjml\");\r\n mjml2html = mjmlModule.default ?? mjmlModule;\r\n } catch {\r\n throw new CompileError(\r\n 'MJML compilation requires \"mjml\". Install it:\\n npm install mjml',\r\n \"mjml\",\r\n \"compile\",\r\n );\r\n }\r\n\r\n // ── 3. Compile ───────────────────────────────────────────────────────\r\n try {\r\n // mjml v5+ returns a Promise; v4 returns synchronously.\r\n // Await handles both cases.\r\n const result = await 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 CompileError(\r\n `MJML compilation errors: ${errorMessages}`,\r\n \"mjml\",\r\n \"compile\",\r\n );\r\n }\r\n\r\n if (!result.html) {\r\n throw new CompileError(\"MJML compilation produced empty output.\", \"mjml\", \"compile\");\r\n }\r\n\r\n return result.html;\r\n } catch (err: unknown) {\r\n if (err instanceof CompileError) throw err;\r\n const message = err instanceof Error ? err.message : \"Unknown MJML compilation error\";\r\n throw new CompileError(`MJML compilation failed: ${message}`, \"mjml\", \"compile\");\r\n }\r\n}\r\n","import { CompileError } from \"./errors.js\";\r\n\r\n/** 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 * PostHTML directives that perform file-system reads or network fetches.\r\n *\r\n * Maizzle's PostHTML pipeline resolves these at compile time: a template\r\n * like `<extends src=\"/etc/passwd\">` causes the server to read that path\r\n * and include the content in rendered output (server-side file read). We\r\n * reject any input containing these directives rather than stripping them,\r\n * because stripping is error-prone with nested or malformed markup.\r\n *\r\n * Affected plugins: posthtml-extend, posthtml-fetch, posthtml-components,\r\n * posthtml-include, posthtml-modules.\r\n */\r\nconst DANGEROUS_DIRECTIVE_RE =\r\n /<\\s*(?:extends|component|fetch|include|module|slot|fill|raw|block|yield)\\b/i;\r\n\r\n/**\r\n * Compile a Maizzle template string into an HTML email string.\r\n *\r\n * Pipeline:\r\n * 1. Validate input (size, basic structure check)\r\n * 2. Reject inputs containing PostHTML file-access directives\r\n * 3. Compile using @maizzle/framework\r\n *\r\n * Security:\r\n * - PostHTML file-system directives are rejected at validation time\r\n * to prevent server-side file reads and SSRF.\r\n * - Template expressions ({{ expr }}) are evaluated by posthtml-expressions\r\n * with empty `locals`, so unknown identifiers like `process` or `require`\r\n * return the literal string '{local}' rather than accessing Node.js globals.\r\n * - A hard timeout prevents pathological PostCSS/Tailwind inputs from\r\n * hanging indefinitely.\r\n *\r\n * Requires peer dependency: @maizzle/framework\r\n */\r\nexport async function compileMaizzle(source: string): Promise<string> {\r\n // ── 1. Validate ──────────────────────────────────────────────────────\r\n if (!source || !source.trim()) {\r\n throw new CompileError(\"Maizzle source must not be empty.\", \"maizzle\", \"validation\");\r\n }\r\n\r\n if (source.length > MAX_SOURCE_SIZE) {\r\n throw new CompileError(\r\n `Maizzle source exceeds ${MAX_SOURCE_SIZE / 1000}KB limit.`,\r\n \"maizzle\",\r\n \"validation\",\r\n );\r\n }\r\n\r\n // ── 2. Block file-system and network PostHTML directives ─────────────\r\n if (DANGEROUS_DIRECTIVE_RE.test(source)) {\r\n throw new CompileError(\r\n \"Maizzle templates may not use <extends>, <component>, <fetch>, <include>, \" +\r\n \"<module>, <slot>, <fill>, <raw>, <block>, or <yield> directives. These directives \" +\r\n \"access the server file system at compile time. Use inline HTML and Tailwind utility classes instead.\",\r\n \"maizzle\",\r\n \"validation\",\r\n );\r\n }\r\n\r\n // ── 3. Load peer dependency ──────────────────────────────────────────\r\n let maizzleRender: (\r\n input: string,\r\n options: Record<string, unknown>,\r\n ) => Promise<{ html: string }>;\r\n\r\n try {\r\n const maizzle = await import(\"@maizzle/framework\");\r\n maizzleRender = maizzle.render;\r\n } catch {\r\n throw new CompileError(\r\n 'Maizzle compilation requires \"@maizzle/framework\". Install it:\\n npm install @maizzle/framework',\r\n \"maizzle\",\r\n \"compile\",\r\n );\r\n }\r\n\r\n // ── 4. 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(\r\n new CompileError(\r\n `Maizzle compilation timed out after ${COMPILE_TIMEOUT_MS / 1000}s.`,\r\n \"maizzle\",\r\n \"compile\",\r\n ),\r\n );\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 CompileError(\"Maizzle compilation produced empty output.\", \"maizzle\", \"compile\");\r\n }\r\n\r\n return html;\r\n } catch (err: unknown) {\r\n if (err instanceof CompileError) throw err;\r\n const message = err instanceof Error ? err.message : \"Unknown Maizzle compilation error\";\r\n throw new CompileError(`Maizzle compilation failed: ${message}`, \"maizzle\", \"compile\");\r\n }\r\n}\r\n","import { extname } from \"node:path\";\r\nimport type { InputFormat } from \"../types.js\";\r\n\r\nexport { CompileError } from \"./errors.js\";\r\nexport { compileReactEmail } from \"./react-email.js\";\r\nexport type { SandboxStrategy, CompileReactEmailOptions } from \"./react-email.js\";\r\nexport { compileMjml } from \"./mjml.js\";\r\nexport { compileMaizzle } from \"./maizzle.js\";\r\n\r\n/**\r\n * Compile source to HTML based on format.\r\n * Returns the HTML unchanged if format is \"html\".\r\n * Lazily imports per-format compilers to avoid loading unnecessary deps.\r\n */\r\nexport async function compile(\r\n source: string,\r\n format: InputFormat,\r\n filePath?: string,\r\n): Promise<string> {\r\n switch (format) {\r\n case \"html\":\r\n return source;\r\n\r\n case \"jsx\": {\r\n const { compileReactEmail } = await import(\"./react-email.js\");\r\n return compileReactEmail(source);\r\n }\r\n\r\n case \"mjml\": {\r\n const { compileMjml } = await import(\"./mjml.js\");\r\n return compileMjml(source);\r\n }\r\n\r\n case \"maizzle\": {\r\n const { compileMaizzle } = await import(\"./maizzle.js\");\r\n return compileMaizzle(source);\r\n }\r\n\r\n default:\r\n throw new Error(`Unknown format: \"${format}\". Use html, jsx, mjml, or maizzle.`);\r\n }\r\n}\r\n\r\n/**\r\n * Auto-detect input format from file extension.\r\n */\r\nexport function detectFormat(filePath: string): InputFormat {\r\n const ext = extname(filePath).toLowerCase();\r\n\r\n switch (ext) {\r\n case \".tsx\":\r\n case \".jsx\":\r\n return \"jsx\";\r\n case \".mjml\":\r\n return \"mjml\";\r\n case \".html\":\r\n case \".htm\":\r\n return \"html\";\r\n default:\r\n return \"html\";\r\n }\r\n}\r\n"],"mappings":"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","names":["MAX_SOURCE_SIZE","MAX_SOURCE_SIZE","compileReactEmail","compileMjml","compileMaizzle"]}
1
+ {"version":3,"sources":["../../src/compile/errors.ts","../../src/compile/react-email.ts","../../src/compile/mjml.ts","../../src/compile/maizzle.ts","../../src/compile/index.ts"],"sourcesContent":["import type { InputFormat } from \"../types.js\";\r\n\r\n/**\r\n * Unified error class for all email compilation failures.\r\n *\r\n * Replaces the per-format error classes (ReactEmailCompileError,\r\n * MjmlCompileError, MaizzleCompileError) with a single class that\r\n * carries the source format and failure phase.\r\n */\r\nexport class CompileError extends Error {\r\n override name = \"CompileError\";\r\n readonly format: Exclude<InputFormat, \"html\">;\r\n readonly phase: \"validation\" | \"transpile\" | \"execution\" | \"render\" | \"compile\";\r\n\r\n constructor(\r\n message: string,\r\n format: CompileError[\"format\"],\r\n phase: CompileError[\"phase\"],\r\n ) {\r\n super(message);\r\n this.format = format;\r\n this.phase = phase;\r\n }\r\n}\r\n","import { CompileError } from \"./errors.js\";\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 * Sandbox strategy for JSX execution.\r\n *\r\n * - `\"vm\"` — `node:vm` with hardened globals. Fast, zero-dependency,\r\n * but NOT a true security boundary (prototype-chain escapes are possible).\r\n * Suitable for CLI / local use where users run their own code.\r\n *\r\n * - `\"isolated-vm\"` (default) — Separate V8 isolate via the `isolated-vm`\r\n * npm package. True heap isolation; escapes require a V8 engine bug.\r\n * Requires `isolated-vm` to be installed (native addon).\r\n *\r\n * - `\"quickjs\"` — Validates code structure in a QuickJS WASM sandbox, then\r\n * executes in `node:vm` for React rendering. Security is equivalent to\r\n * `node:vm` — the QuickJS phase validates import restrictions only.\r\n * No native addons needed, but only supports ES2020 and is slower.\r\n * For true isolation on servers, use `isolated-vm`.\r\n */\r\nexport type SandboxStrategy = \"vm\" | \"isolated-vm\" | \"quickjs\";\r\n\r\nexport interface CompileReactEmailOptions {\r\n /**\r\n * Sandbox strategy to use for executing user JSX code.\r\n * @default \"isolated-vm\"\r\n */\r\n sandbox?: SandboxStrategy;\r\n}\r\n\r\n/**\r\n * Compile a React Email JSX/TSX source string into an HTML email string.\r\n *\r\n * Pipeline:\r\n * 1. Validate input (size, basic checks)\r\n * 2. Transpile JSX/TSX → CommonJS JS using sucrase\r\n * 3. Execute inside a sandbox (configurable strategy)\r\n * 4. Render the exported component to a full HTML email string\r\n *\r\n * Requires peer dependencies: sucrase, react, @react-email/components,\r\n * @react-email/render. Additionally:\r\n * - sandbox \"isolated-vm\" requires `isolated-vm`\r\n * - sandbox \"quickjs\" requires `quickjs-emscripten`\r\n */\r\nexport async function compileReactEmail(\r\n source: string,\r\n options?: CompileReactEmailOptions,\r\n): Promise<string> {\r\n const strategy = options?.sandbox ?? \"isolated-vm\";\r\n\r\n // ── 1. Validate ──────────────────────────────────────────────────────\r\n if (!source || !source.trim()) {\r\n throw new CompileError(\"JSX source must not be empty.\", \"jsx\", \"validation\");\r\n }\r\n\r\n if (source.length > MAX_SOURCE_SIZE) {\r\n throw new CompileError(\r\n `JSX source exceeds ${MAX_SOURCE_SIZE / 1000}KB limit.`,\r\n \"jsx\",\r\n \"validation\",\r\n );\r\n }\r\n\r\n // ── 2. Load peer 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 CompileError(\r\n 'JSX compilation requires \"sucrase\". Install it:\\n npm install sucrase',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n try {\r\n React = await import(\"react\");\r\n } catch {\r\n throw new CompileError(\r\n 'JSX compilation requires \"react\". Install it:\\n npm install react',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n try {\r\n ReactEmailComponents = await import(\"@react-email/components\");\r\n } catch {\r\n throw new CompileError(\r\n 'JSX compilation requires \"@react-email/components\". Install it:\\n npm install @react-email/components',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n try {\r\n ({ render } = await import(\"@react-email/render\"));\r\n } catch {\r\n throw new CompileError(\r\n 'JSX compilation requires \"@react-email/render\". Install it:\\n npm install @react-email/render',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n // ── 3. 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 CompileError(`JSX syntax error: ${message}`, \"jsx\", \"transpile\");\r\n }\r\n\r\n // ── 4. Execute in sandbox ────────────────────────────────────────────\r\n let moduleExports: Record<string, unknown>;\r\n\r\n switch (strategy) {\r\n case \"isolated-vm\":\r\n moduleExports = await executeInIsolatedVm(transpiledCode, React, ReactEmailComponents);\r\n break;\r\n case \"quickjs\":\r\n moduleExports = await executeInQuickJs(transpiledCode, React, ReactEmailComponents);\r\n break;\r\n case \"vm\":\r\n moduleExports = executeInVm(transpiledCode, React, ReactEmailComponents);\r\n break;\r\n default:\r\n throw new CompileError(\r\n `Unknown sandbox strategy: \"${strategy}\". Use \"vm\", \"isolated-vm\", or \"quickjs\".`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n // ── 5. Extract component and render ──────────────────────────────────\r\n let Component: unknown = moduleExports.default ?? moduleExports;\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 CompileError(\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 \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n try {\r\n const element = React.createElement(Component as React.FC);\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 CompileError(`React rendering error: ${message}`, \"jsx\", \"render\");\r\n }\r\n}\r\n\r\n// ─── Sandbox: node:vm ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * Execute transpiled code in a node:vm context with hardened globals.\r\n *\r\n * NOT a security boundary — see node:vm documentation. Suitable for CLI\r\n * use where the user runs their own code. For server use, prefer\r\n * \"isolated-vm\" or \"quickjs\".\r\n */\r\nfunction executeInVm(\r\n code: string,\r\n React: typeof import(\"react\"),\r\n ReactEmailComponents: typeof import(\"@react-email/components\"),\r\n): Record<string, unknown> {\r\n const { createContext, Script } = require(\"node:vm\") as typeof import(\"node:vm\");\r\n\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,\r\n Proxy: undefined, Reflect: undefined,\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(code, { 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 CompileError(\"JSX execution timed out (possible infinite loop).\", \"jsx\", \"execution\");\r\n }\r\n throw new CompileError(`JSX execution error: ${message}`, \"jsx\", \"execution\");\r\n }\r\n\r\n return moduleObj.exports as Record<string, unknown>;\r\n}\r\n\r\n// ─── Sandbox: isolated-vm ──────────────────────────────────────────────────\r\n\r\n/**\r\n * Validate code in a separate V8 isolate, then execute in `node:vm`.\r\n *\r\n * Two-phase approach:\r\n * 1. **Validate** — run the transpiled code in a true V8 isolate with stub\r\n * React/component implementations. This catches disallowed imports and\r\n * structural errors inside a genuine security boundary (separate heap,\r\n * 128 MB memory cap, timeout). Escape requires a V8 engine bug.\r\n * 2. **Execute** — run the validated code in `node:vm` with real React\r\n * objects for actual rendering.\r\n *\r\n * Why two phases: React's internal type system uses Symbols\r\n * (`Symbol(react.forward_ref)`, `Symbol(react.element)`, etc.) which cannot\r\n * be transferred across V8 isolate boundaries — the structured clone\r\n * algorithm does not support Symbols. Running React code directly inside\r\n * `isolated-vm` is not possible.\r\n */\r\nasync function executeInIsolatedVm(\r\n code: string,\r\n React: typeof import(\"react\"),\r\n ReactEmailComponents: typeof import(\"@react-email/components\"),\r\n): Promise<Record<string, unknown>> {\r\n let ivm: typeof import(\"isolated-vm\");\r\n try {\r\n const ivmMod = await import(\"isolated-vm\");\r\n ivm = (ivmMod as any).default ?? ivmMod;\r\n } catch {\r\n throw new CompileError(\r\n 'Sandbox strategy \"isolated-vm\" requires the \"isolated-vm\" package. Install it:\\n' +\r\n \" npm install isolated-vm\\n\" +\r\n 'Or use sandbox: \"vm\" for a lighter (but less secure) alternative.',\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n // ── Phase 1: Validate in a true V8 isolate ─────────────────────────────\r\n const isolate = new ivm.Isolate({ memoryLimit: 128 });\r\n try {\r\n const ivmContext = await isolate.createContext();\r\n\r\n // Stub implementations let the code parse and execute structurally\r\n // without needing real React objects (which contain non-cloneable Symbols).\r\n // Stub React: createElement returns a plain object, forwardRef passes\r\n // through, and any unknown property returns a no-op function. The Proxy\r\n // on the components module ensures that any named import (Html, Head,\r\n // Button, etc.) resolves to a dummy component function so the transpiled\r\n // code can execute structurally without real React objects.\r\n const validationCode = `\r\n (function() {\r\n var module = { exports: {} };\r\n var exports = module.exports;\r\n var noop = function() { return {}; };\r\n var React = new Proxy({\r\n createElement: noop,\r\n forwardRef: function(fn) { return fn; },\r\n Fragment: \"Fragment\",\r\n createContext: function() { return { Provider: noop, Consumer: noop }; },\r\n useState: function(v) { return [v, noop]; },\r\n useRef: function() { return { current: null }; },\r\n useEffect: noop,\r\n useMemo: function(fn) { return fn(); },\r\n useCallback: function(fn) { return fn; },\r\n Children: { map: noop, forEach: noop, toArray: function() { return []; } },\r\n }, { get: function(t, p) { return p in t ? t[p] : noop; } });\r\n var componentsProxy = new Proxy({}, {\r\n get: function() { return noop; }\r\n });\r\n function require(name) {\r\n if (name === \"react\") return React;\r\n if (name === \"@react-email/components\") return componentsProxy;\r\n throw new Error('Import of \"' + name + '\" is not allowed. Only \"react\" and \"@react-email/components\" can be imported.');\r\n }\r\n try {\r\n ${code}\r\n return JSON.stringify({ ok: true });\r\n } catch(e) {\r\n return JSON.stringify({ ok: false, error: e.message || \"Unknown error\" });\r\n }\r\n })()\r\n `;\r\n\r\n try {\r\n const result = await ivmContext.eval(validationCode, {\r\n timeout: EXECUTION_TIMEOUT_MS,\r\n });\r\n\r\n if (typeof result === \"string\") {\r\n const parsed = JSON.parse(result) as { ok: boolean; error?: string };\r\n if (!parsed.ok) {\r\n throw new CompileError(\r\n `JSX execution error: ${parsed.error ?? \"Unknown error\"}`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n }\r\n } catch (err: unknown) {\r\n if (err instanceof CompileError) throw err;\r\n const message = err instanceof Error ? err.message : \"Unknown execution error\";\r\n if (message.includes(\"timed out\") || message.includes(\"Timeout\")) {\r\n throw new CompileError(\"JSX execution timed out (possible infinite loop).\", \"jsx\", \"execution\");\r\n }\r\n throw new CompileError(`JSX execution error: ${message}`, \"jsx\", \"execution\");\r\n }\r\n } finally {\r\n isolate.dispose();\r\n }\r\n\r\n // ── Phase 2: Execute validated code in node:vm with real React ──────────\r\n return executeInVm(code, React, ReactEmailComponents);\r\n}\r\n\r\n// ─── Sandbox: QuickJS (WASM) ──────────────────────────────────────────────\r\n\r\n/**\r\n * Validate code structure in QuickJS WASM, then execute in `node:vm`.\r\n *\r\n * Two-phase approach:\r\n * 1. Validate that the code doesn't access disallowed modules by running it\r\n * in a QuickJS WASM sandbox with stub implementations.\r\n * 2. Execute in `node:vm` for actual React rendering (React objects can't\r\n * cross the WASM boundary).\r\n *\r\n * **Security note:** The actual execution happens in `node:vm`, so runtime\r\n * security is equivalent to the `\"vm\"` strategy. The QuickJS phase only\r\n * validates import restrictions. For true isolation on servers, use\r\n * `\"isolated-vm\"`.\r\n */\r\nasync function executeInQuickJs(\r\n code: string,\r\n React: typeof import(\"react\"),\r\n ReactEmailComponents: typeof import(\"@react-email/components\"),\r\n): Promise<Record<string, unknown>> {\r\n let getQuickJS: typeof import(\"quickjs-emscripten\").getQuickJS;\r\n try {\r\n ({ getQuickJS } = await import(\"quickjs-emscripten\"));\r\n } catch {\r\n throw new CompileError(\r\n 'Sandbox strategy \"quickjs\" requires the \"quickjs-emscripten\" package. Install it:\\n' +\r\n \" npm install quickjs-emscripten\\n\" +\r\n 'Or use sandbox: \"vm\" for a lighter alternative.',\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n const QuickJS = await getQuickJS();\r\n const vm = QuickJS.newContext();\r\n\r\n try {\r\n // Phase 1: Validate code safety in the WASM sandbox.\r\n // We provide stub implementations of React and the module system so\r\n // the code can execute without errors, but we only care that it\r\n // doesn't try to access anything dangerous.\r\n // QuickJS (ES2020) does not support Proxy, so we enumerate known\r\n // React Email component names as stub functions instead.\r\n const validationCode = `\r\n (function() {\r\n var module = { exports: {} };\r\n var exports = module.exports;\r\n var noop = function() { return {}; };\r\n var React = {\r\n createElement: noop,\r\n forwardRef: function(fn) { return fn; },\r\n Fragment: \"Fragment\",\r\n createContext: function() { return { Provider: noop, Consumer: noop }; },\r\n useState: function(v) { return [v, noop]; },\r\n useRef: function() { return { current: null }; },\r\n useEffect: noop,\r\n useMemo: function(fn) { return fn(); },\r\n useCallback: function(fn) { return fn; },\r\n Children: { map: noop, forEach: noop, toArray: function() { return []; } },\r\n };\r\n var components = {};\r\n var names = [\r\n \"Html\",\"Head\",\"Body\",\"Container\",\"Section\",\"Row\",\"Column\",\"Text\",\r\n \"Link\",\"Button\",\"Img\",\"Hr\",\"Preview\",\"Heading\",\"Font\",\"Style\",\r\n \"CodeBlock\",\"CodeInline\",\"Markdown\",\"Tailwind\",\"Responsive\",\r\n ];\r\n for (var i = 0; i < names.length; i++) components[names[i]] = noop;\r\n function require(name) {\r\n if (name === \"react\") return React;\r\n if (name === \"@react-email/components\") return components;\r\n throw new Error('Import of \"' + name + '\" is not allowed.');\r\n }\r\n try {\r\n ${code}\r\n return JSON.stringify({ ok: true });\r\n } catch(e) {\r\n return JSON.stringify({ ok: false, error: e.message || \"Unknown error\" });\r\n }\r\n })()\r\n `;\r\n\r\n const result = vm.evalCode(validationCode);\r\n if (result.error) {\r\n const errorVal = vm.dump(result.error);\r\n result.error.dispose();\r\n throw new CompileError(\r\n `JSX execution error: ${typeof errorVal === \"string\" ? errorVal : \"QuickJS execution failed\"}`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n const resultStr = vm.dump(result.value);\r\n result.value.dispose();\r\n\r\n if (typeof resultStr === \"string\") {\r\n const parsed = JSON.parse(resultStr) as { ok: boolean; error?: string };\r\n if (!parsed.ok) {\r\n throw new CompileError(\r\n `JSX execution error: ${parsed.error ?? \"Unknown error\"}`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n }\r\n\r\n // Phase 2: Code validated as safe — execute in node:vm for actual\r\n // React rendering (React objects can't cross the WASM boundary)\r\n return executeInVm(code, React, ReactEmailComponents);\r\n } finally {\r\n vm.dispose();\r\n }\r\n}\r\n","import { CompileError } from \"./errors.js\";\r\n\r\n/** 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 *\r\n * MJML is a declarative markup language with no code execution capability\r\n * (unlike JSX). The mjml library parses XML and generates HTML; there is\r\n * no sandboxing concern.\r\n *\r\n * Requires peer dependency: mjml\r\n */\r\nexport async function compileMjml(source: string): Promise<string> {\r\n // ── 1. Validate ──────────────────────────────────────────────────────\r\n if (!source || !source.trim()) {\r\n throw new CompileError(\"MJML source must not be empty.\", \"mjml\", \"validation\");\r\n }\r\n\r\n if (source.length > MAX_SOURCE_SIZE) {\r\n throw new CompileError(\r\n `MJML source exceeds ${MAX_SOURCE_SIZE / 1000}KB limit.`,\r\n \"mjml\",\r\n \"validation\",\r\n );\r\n }\r\n\r\n if (!/<mjml[\\s>]/i.test(source)) {\r\n throw new CompileError(\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 \"mjml\",\r\n \"validation\",\r\n );\r\n }\r\n\r\n // ── 2. Load peer dependency ──────────────────────────────────────────\r\n type MjmlResult = {\r\n html: string;\r\n errors: Array<{ line: number; message: string; tagName: string; formattedMessage: string }>;\r\n };\r\n let mjml2html: (\r\n input: string,\r\n options?: Record<string, unknown>,\r\n ) => MjmlResult | Promise<MjmlResult>;\r\n\r\n try {\r\n const mjmlModule = await import(\"mjml\");\r\n mjml2html = mjmlModule.default ?? mjmlModule;\r\n } catch {\r\n throw new CompileError(\r\n 'MJML compilation requires \"mjml\". Install it:\\n npm install mjml',\r\n \"mjml\",\r\n \"compile\",\r\n );\r\n }\r\n\r\n // ── 3. Compile ───────────────────────────────────────────────────────\r\n try {\r\n // mjml v5+ returns a Promise; v4 returns synchronously.\r\n // Await handles both cases.\r\n const result = await 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 CompileError(\r\n `MJML compilation errors: ${errorMessages}`,\r\n \"mjml\",\r\n \"compile\",\r\n );\r\n }\r\n\r\n if (!result.html) {\r\n throw new CompileError(\"MJML compilation produced empty output.\", \"mjml\", \"compile\");\r\n }\r\n\r\n return result.html;\r\n } catch (err: unknown) {\r\n if (err instanceof CompileError) throw err;\r\n const message = err instanceof Error ? err.message : \"Unknown MJML compilation error\";\r\n throw new CompileError(`MJML compilation failed: ${message}`, \"mjml\", \"compile\");\r\n }\r\n}\r\n","import { CompileError } from \"./errors.js\";\r\n\r\n/** 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 * PostHTML directives that perform file-system reads or network fetches.\r\n *\r\n * Maizzle's PostHTML pipeline resolves these at compile time: a template\r\n * like `<extends src=\"/etc/passwd\">` causes the server to read that path\r\n * and include the content in rendered output (server-side file read). We\r\n * reject any input containing these directives rather than stripping them,\r\n * because stripping is error-prone with nested or malformed markup.\r\n *\r\n * Affected plugins: posthtml-extend, posthtml-fetch, posthtml-components,\r\n * posthtml-include, posthtml-modules.\r\n */\r\nconst DANGEROUS_DIRECTIVE_RE =\r\n /<\\s*(?:extends|component|fetch|include|module|slot|fill|raw|block|yield)\\b/i;\r\n\r\n/**\r\n * Compile a Maizzle template string into an HTML email string.\r\n *\r\n * Pipeline:\r\n * 1. Validate input (size, basic structure check)\r\n * 2. Reject inputs containing PostHTML file-access directives\r\n * 3. Compile using @maizzle/framework\r\n *\r\n * Security:\r\n * - PostHTML file-system directives are rejected at validation time\r\n * to prevent server-side file reads and SSRF.\r\n * - Template expressions ({{ expr }}) are evaluated by posthtml-expressions\r\n * with empty `locals`, so unknown identifiers like `process` or `require`\r\n * return the literal string '{local}' rather than accessing Node.js globals.\r\n * - A hard timeout prevents pathological PostCSS/Tailwind inputs from\r\n * hanging indefinitely.\r\n *\r\n * Requires peer dependency: @maizzle/framework\r\n */\r\nexport async function compileMaizzle(source: string): Promise<string> {\r\n // ── 1. Validate ──────────────────────────────────────────────────────\r\n if (!source || !source.trim()) {\r\n throw new CompileError(\"Maizzle source must not be empty.\", \"maizzle\", \"validation\");\r\n }\r\n\r\n if (source.length > MAX_SOURCE_SIZE) {\r\n throw new CompileError(\r\n `Maizzle source exceeds ${MAX_SOURCE_SIZE / 1000}KB limit.`,\r\n \"maizzle\",\r\n \"validation\",\r\n );\r\n }\r\n\r\n // ── 2. Block file-system and network PostHTML directives ─────────────\r\n if (DANGEROUS_DIRECTIVE_RE.test(source)) {\r\n throw new CompileError(\r\n \"Maizzle templates may not use <extends>, <component>, <fetch>, <include>, \" +\r\n \"<module>, <slot>, <fill>, <raw>, <block>, or <yield> directives. These directives \" +\r\n \"access the server file system at compile time. Use inline HTML and Tailwind utility classes instead.\",\r\n \"maizzle\",\r\n \"validation\",\r\n );\r\n }\r\n\r\n // ── 3. Load peer dependency ──────────────────────────────────────────\r\n let maizzleRender: (\r\n input: string,\r\n options: Record<string, unknown>,\r\n ) => Promise<{ html: string }>;\r\n\r\n try {\r\n const maizzle = await import(\"@maizzle/framework\");\r\n maizzleRender = maizzle.render;\r\n } catch {\r\n throw new CompileError(\r\n 'Maizzle compilation requires \"@maizzle/framework\". Install it:\\n npm install @maizzle/framework',\r\n \"maizzle\",\r\n \"compile\",\r\n );\r\n }\r\n\r\n // ── 4. 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(\r\n new CompileError(\r\n `Maizzle compilation timed out after ${COMPILE_TIMEOUT_MS / 1000}s.`,\r\n \"maizzle\",\r\n \"compile\",\r\n ),\r\n );\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 CompileError(\"Maizzle compilation produced empty output.\", \"maizzle\", \"compile\");\r\n }\r\n\r\n return html;\r\n } catch (err: unknown) {\r\n if (err instanceof CompileError) throw err;\r\n const message = err instanceof Error ? err.message : \"Unknown Maizzle compilation error\";\r\n throw new CompileError(`Maizzle compilation failed: ${message}`, \"maizzle\", \"compile\");\r\n }\r\n}\r\n","import { extname } from \"node:path\";\r\nimport type { InputFormat } from \"../types.js\";\r\n\r\nexport { CompileError } from \"./errors.js\";\r\nexport { compileReactEmail } from \"./react-email.js\";\r\nexport type { SandboxStrategy, CompileReactEmailOptions } from \"./react-email.js\";\r\nexport { compileMjml } from \"./mjml.js\";\r\nexport { compileMaizzle } from \"./maizzle.js\";\r\n\r\n/**\r\n * Compile source to HTML based on format.\r\n * Returns the HTML unchanged if format is \"html\".\r\n * Lazily imports per-format compilers to avoid loading unnecessary deps.\r\n */\r\nexport async function compile(\r\n source: string,\r\n format: InputFormat,\r\n filePath?: string,\r\n): Promise<string> {\r\n switch (format) {\r\n case \"html\":\r\n return source;\r\n\r\n case \"jsx\": {\r\n const { compileReactEmail } = await import(\"./react-email.js\");\r\n return compileReactEmail(source);\r\n }\r\n\r\n case \"mjml\": {\r\n const { compileMjml } = await import(\"./mjml.js\");\r\n return compileMjml(source);\r\n }\r\n\r\n case \"maizzle\": {\r\n const { compileMaizzle } = await import(\"./maizzle.js\");\r\n return compileMaizzle(source);\r\n }\r\n\r\n default:\r\n throw new Error(`Unknown format: \"${format}\". Use html, jsx, mjml, or maizzle.`);\r\n }\r\n}\r\n\r\n/**\r\n * Auto-detect input format from file extension.\r\n */\r\nexport function detectFormat(filePath: string): InputFormat {\r\n const ext = extname(filePath).toLowerCase();\r\n\r\n switch (ext) {\r\n case \".tsx\":\r\n case \".jsx\":\r\n return \"jsx\";\r\n case \".mjml\":\r\n return \"mjml\";\r\n case \".html\":\r\n case \".htm\":\r\n return \"html\";\r\n default:\r\n return \"html\";\r\n }\r\n}\r\n"],"mappings":"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","names":["MAX_SOURCE_SIZE","MAX_SOURCE_SIZE","compileReactEmail","compileMjml","compileMaizzle"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  compileReactEmail
3
- } from "../chunk-LW2IMTBA.js";
3
+ } from "../chunk-EBNA3X7P.js";
4
4
  import {
5
5
  compileMjml
6
6
  } from "../chunk-W4SPWESS.js";
@@ -18,7 +18,7 @@ async function compile(source, format, filePath) {
18
18
  case "html":
19
19
  return source;
20
20
  case "jsx": {
21
- const { compileReactEmail: compileReactEmail2 } = await import("../react-email-AN62KVVF.js");
21
+ const { compileReactEmail: compileReactEmail2 } = await import("../react-email-ZSQKM36O.js");
22
22
  return compileReactEmail2(source);
23
23
  }
24
24
  case "mjml": {
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  compileReactEmail
3
- } from "./chunk-LW2IMTBA.js";
3
+ } from "./chunk-EBNA3X7P.js";
4
4
  import "./chunk-PFONR3YC.js";
5
5
  export {
6
6
  compileReactEmail
7
7
  };
8
- //# sourceMappingURL=react-email-AN62KVVF.js.map
8
+ //# sourceMappingURL=react-email-ZSQKM36O.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emailens/engine",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Email compatibility engine — transforms CSS per email client, scores compatibility, simulates dark mode, suggests fixes, and runs spam, accessibility, link, and image quality analysis.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -46,14 +46,30 @@
46
46
  "quickjs-emscripten": ">=0.29.0"
47
47
  },
48
48
  "peerDependenciesMeta": {
49
- "sucrase": { "optional": true },
50
- "react": { "optional": true },
51
- "@react-email/components": { "optional": true },
52
- "@react-email/render": { "optional": true },
53
- "mjml": { "optional": true },
54
- "@maizzle/framework": { "optional": true },
55
- "isolated-vm": { "optional": true },
56
- "quickjs-emscripten": { "optional": true }
49
+ "sucrase": {
50
+ "optional": true
51
+ },
52
+ "react": {
53
+ "optional": true
54
+ },
55
+ "@react-email/components": {
56
+ "optional": true
57
+ },
58
+ "@react-email/render": {
59
+ "optional": true
60
+ },
61
+ "mjml": {
62
+ "optional": true
63
+ },
64
+ "@maizzle/framework": {
65
+ "optional": true
66
+ },
67
+ "isolated-vm": {
68
+ "optional": true
69
+ },
70
+ "quickjs-emscripten": {
71
+ "optional": true
72
+ }
57
73
  },
58
74
  "devDependencies": {
59
75
  "@maizzle/framework": "^5.0.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/compile/react-email.ts"],"sourcesContent":["import { CompileError } from \"./errors.js\";\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 * Sandbox strategy for JSX execution.\r\n *\r\n * - `\"vm\"` — `node:vm` with hardened globals. Fast, zero-dependency,\r\n * but NOT a true security boundary (prototype-chain escapes are possible).\r\n * Suitable for CLI / local use where users run their own code.\r\n *\r\n * - `\"isolated-vm\"` (default) — Separate V8 isolate via the `isolated-vm`\r\n * npm package. True heap isolation; escapes require a V8 engine bug.\r\n * Requires `isolated-vm` to be installed (native addon).\r\n *\r\n * - `\"quickjs\"` — Validates code structure in a QuickJS WASM sandbox, then\r\n * executes in `node:vm` for React rendering. Security is equivalent to\r\n * `node:vm` — the QuickJS phase validates import restrictions only.\r\n * No native addons needed, but only supports ES2020 and is slower.\r\n * For true isolation on servers, use `isolated-vm`.\r\n */\r\nexport type SandboxStrategy = \"vm\" | \"isolated-vm\" | \"quickjs\";\r\n\r\nexport interface CompileReactEmailOptions {\r\n /**\r\n * Sandbox strategy to use for executing user JSX code.\r\n * @default \"isolated-vm\"\r\n */\r\n sandbox?: SandboxStrategy;\r\n}\r\n\r\n/**\r\n * Compile a React Email JSX/TSX source string into an HTML email string.\r\n *\r\n * Pipeline:\r\n * 1. Validate input (size, basic checks)\r\n * 2. Transpile JSX/TSX → CommonJS JS using sucrase\r\n * 3. Execute inside a sandbox (configurable strategy)\r\n * 4. Render the exported component to a full HTML email string\r\n *\r\n * Requires peer dependencies: sucrase, react, @react-email/components,\r\n * @react-email/render. Additionally:\r\n * - sandbox \"isolated-vm\" requires `isolated-vm`\r\n * - sandbox \"quickjs\" requires `quickjs-emscripten`\r\n */\r\nexport async function compileReactEmail(\r\n source: string,\r\n options?: CompileReactEmailOptions,\r\n): Promise<string> {\r\n const strategy = options?.sandbox ?? \"isolated-vm\";\r\n\r\n // ── 1. Validate ──────────────────────────────────────────────────────\r\n if (!source || !source.trim()) {\r\n throw new CompileError(\"JSX source must not be empty.\", \"jsx\", \"validation\");\r\n }\r\n\r\n if (source.length > MAX_SOURCE_SIZE) {\r\n throw new CompileError(\r\n `JSX source exceeds ${MAX_SOURCE_SIZE / 1000}KB limit.`,\r\n \"jsx\",\r\n \"validation\",\r\n );\r\n }\r\n\r\n // ── 2. Load peer 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 CompileError(\r\n 'JSX compilation requires \"sucrase\". Install it:\\n npm install sucrase',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n try {\r\n React = await import(\"react\");\r\n } catch {\r\n throw new CompileError(\r\n 'JSX compilation requires \"react\". Install it:\\n npm install react',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n try {\r\n ReactEmailComponents = await import(\"@react-email/components\");\r\n } catch {\r\n throw new CompileError(\r\n 'JSX compilation requires \"@react-email/components\". Install it:\\n npm install @react-email/components',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n try {\r\n ({ render } = await import(\"@react-email/render\"));\r\n } catch {\r\n throw new CompileError(\r\n 'JSX compilation requires \"@react-email/render\". Install it:\\n npm install @react-email/render',\r\n \"jsx\",\r\n \"transpile\",\r\n );\r\n }\r\n\r\n // ── 3. 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 CompileError(`JSX syntax error: ${message}`, \"jsx\", \"transpile\");\r\n }\r\n\r\n // ── 4. Execute in sandbox ────────────────────────────────────────────\r\n let moduleExports: Record<string, unknown>;\r\n\r\n switch (strategy) {\r\n case \"isolated-vm\":\r\n moduleExports = await executeInIsolatedVm(transpiledCode, React, ReactEmailComponents);\r\n break;\r\n case \"quickjs\":\r\n moduleExports = await executeInQuickJs(transpiledCode, React, ReactEmailComponents);\r\n break;\r\n case \"vm\":\r\n moduleExports = executeInVm(transpiledCode, React, ReactEmailComponents);\r\n break;\r\n default:\r\n throw new CompileError(\r\n `Unknown sandbox strategy: \"${strategy}\". Use \"vm\", \"isolated-vm\", or \"quickjs\".`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n // ── 5. Extract component and render ──────────────────────────────────\r\n let Component: unknown = moduleExports.default ?? moduleExports;\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 CompileError(\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 \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n try {\r\n const element = React.createElement(Component as React.FC);\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 CompileError(`React rendering error: ${message}`, \"jsx\", \"render\");\r\n }\r\n}\r\n\r\n// ─── Sandbox: node:vm ──────────────────────────────────────────────────────\r\n\r\n/**\r\n * Execute transpiled code in a node:vm context with hardened globals.\r\n *\r\n * NOT a security boundary — see node:vm documentation. Suitable for CLI\r\n * use where the user runs their own code. For server use, prefer\r\n * \"isolated-vm\" or \"quickjs\".\r\n */\r\nfunction executeInVm(\r\n code: string,\r\n React: typeof import(\"react\"),\r\n ReactEmailComponents: typeof import(\"@react-email/components\"),\r\n): Record<string, unknown> {\r\n const { createContext, Script } = require(\"node:vm\") as typeof import(\"node:vm\");\r\n\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,\r\n Proxy: undefined, Reflect: undefined,\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(code, { 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 CompileError(\"JSX execution timed out (possible infinite loop).\", \"jsx\", \"execution\");\r\n }\r\n throw new CompileError(`JSX execution error: ${message}`, \"jsx\", \"execution\");\r\n }\r\n\r\n return moduleObj.exports as Record<string, unknown>;\r\n}\r\n\r\n// ─── Sandbox: isolated-vm ──────────────────────────────────────────────────\r\n\r\n/**\r\n * Execute transpiled code in a separate V8 isolate via `isolated-vm`.\r\n *\r\n * True heap isolation — the user code runs in a distinct V8 isolate with\r\n * no access to the host process. Module requires and globals must be\r\n * explicitly transferred. Escape requires exploiting a V8 engine bug.\r\n *\r\n * Implementation note: React Email components create complex object graphs\r\n * (React elements, component refs) that cannot be serialized across isolate\r\n * boundaries. We use a callback-based approach where the isolate calls back\r\n * into the host for module resolution, and the code runs with a strict\r\n * timeout and memory limit.\r\n */\r\nasync function executeInIsolatedVm(\r\n code: string,\r\n React: typeof import(\"react\"),\r\n ReactEmailComponents: typeof import(\"@react-email/components\"),\r\n): Promise<Record<string, unknown>> {\r\n let ivm: typeof import(\"isolated-vm\");\r\n try {\r\n ivm = await import(\"isolated-vm\");\r\n } catch {\r\n throw new CompileError(\r\n 'Sandbox strategy \"isolated-vm\" requires the \"isolated-vm\" package. Install it:\\n' +\r\n \" npm install isolated-vm\\n\" +\r\n 'Or use sandbox: \"vm\" for a lighter (but less secure) alternative.',\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n const isolate = new ivm.Isolate({ memoryLimit: 128 });\r\n try {\r\n const ivmContext = await isolate.createContext();\r\n const jail = ivmContext.global;\r\n\r\n const ALLOWED_MODULES: Record<string, unknown> = {\r\n react: React,\r\n \"@react-email/components\": ReactEmailComponents,\r\n };\r\n\r\n // Set up host callbacks for module resolution\r\n const hostRequire = new ivm.Reference(function (name: string) {\r\n if (name in ALLOWED_MODULES) {\r\n return ALLOWED_MODULES[name];\r\n }\r\n throw new Error(\r\n `Import of \"${name}\" is not allowed. Only \"react\" and \"@react-email/components\" can be imported.`,\r\n );\r\n });\r\n\r\n await jail.set(\"__hostRequire\", hostRequire);\r\n await jail.set(\"__hostReact\", new ivm.Reference(React));\r\n\r\n // Run code in the isolate with host callbacks for module resolution\r\n const wrapperCode = `\r\n (function() {\r\n const module = { exports: {} };\r\n const exports = module.exports;\r\n\r\n const React = __hostReact.derefInto();\r\n function require(name) {\r\n return __hostRequire.applySync(undefined, [name], { result: { copy: true }, arguments: { copy: true } });\r\n }\r\n\r\n ${code}\r\n\r\n return module.exports;\r\n })()\r\n `;\r\n\r\n try {\r\n const result = await ivmContext.evalClosureSync(wrapperCode, [], {\r\n timeout: EXECUTION_TIMEOUT_MS,\r\n });\r\n\r\n return typeof result === \"object\" && result !== null\r\n ? (result as Record<string, unknown>)\r\n : { default: result };\r\n } catch (err: unknown) {\r\n const message = err instanceof Error ? err.message : \"Unknown execution error\";\r\n if (message.includes(\"timed out\") || message.includes(\"Timeout\")) {\r\n throw new CompileError(\"JSX execution timed out (possible infinite loop).\", \"jsx\", \"execution\");\r\n }\r\n throw new CompileError(`JSX execution error: ${message}`, \"jsx\", \"execution\");\r\n }\r\n } finally {\r\n isolate.dispose();\r\n }\r\n}\r\n\r\n// ─── Sandbox: QuickJS (WASM) ──────────────────────────────────────────────\r\n\r\n/**\r\n * Validate code structure in QuickJS WASM, then execute in `node:vm`.\r\n *\r\n * Two-phase approach:\r\n * 1. Validate that the code doesn't access disallowed modules by running it\r\n * in a QuickJS WASM sandbox with stub implementations.\r\n * 2. Execute in `node:vm` for actual React rendering (React objects can't\r\n * cross the WASM boundary).\r\n *\r\n * **Security note:** The actual execution happens in `node:vm`, so runtime\r\n * security is equivalent to the `\"vm\"` strategy. The QuickJS phase only\r\n * validates import restrictions. For true isolation on servers, use\r\n * `\"isolated-vm\"`.\r\n */\r\nasync function executeInQuickJs(\r\n code: string,\r\n React: typeof import(\"react\"),\r\n ReactEmailComponents: typeof import(\"@react-email/components\"),\r\n): Promise<Record<string, unknown>> {\r\n let getQuickJS: typeof import(\"quickjs-emscripten\").getQuickJS;\r\n try {\r\n ({ getQuickJS } = await import(\"quickjs-emscripten\"));\r\n } catch {\r\n throw new CompileError(\r\n 'Sandbox strategy \"quickjs\" requires the \"quickjs-emscripten\" package. Install it:\\n' +\r\n \" npm install quickjs-emscripten\\n\" +\r\n 'Or use sandbox: \"vm\" for a lighter alternative.',\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n const QuickJS = await getQuickJS();\r\n const vm = QuickJS.newContext();\r\n\r\n try {\r\n // Phase 1: Validate code safety in the WASM sandbox.\r\n // We provide stub implementations of React and the module system so\r\n // the code can execute without errors, but we only care that it\r\n // doesn't try to access anything dangerous.\r\n const validationCode = `\r\n (function() {\r\n var module = { exports: {} };\r\n var exports = module.exports;\r\n var React = { createElement: function() { return {}; } };\r\n function require(name) {\r\n if (name === \"react\" || name === \"@react-email/components\") {\r\n return React;\r\n }\r\n throw new Error('Import of \"' + name + '\" is not allowed.');\r\n }\r\n try {\r\n ${code}\r\n return JSON.stringify({ ok: true });\r\n } catch(e) {\r\n return JSON.stringify({ ok: false, error: e.message || \"Unknown error\" });\r\n }\r\n })()\r\n `;\r\n\r\n const result = vm.evalCode(validationCode);\r\n if (result.error) {\r\n const errorVal = vm.dump(result.error);\r\n result.error.dispose();\r\n throw new CompileError(\r\n `JSX execution error: ${typeof errorVal === \"string\" ? errorVal : \"QuickJS execution failed\"}`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n\r\n const resultStr = vm.dump(result.value);\r\n result.value.dispose();\r\n\r\n if (typeof resultStr === \"string\") {\r\n const parsed = JSON.parse(resultStr) as { ok: boolean; error?: string };\r\n if (!parsed.ok) {\r\n throw new CompileError(\r\n `JSX execution error: ${parsed.error ?? \"Unknown error\"}`,\r\n \"jsx\",\r\n \"execution\",\r\n );\r\n }\r\n }\r\n\r\n // Phase 2: Code validated as safe — execute in node:vm for actual\r\n // React rendering (React objects can't cross the WASM boundary)\r\n return executeInVm(code, React, ReactEmailComponents);\r\n } finally {\r\n vm.dispose();\r\n }\r\n}\r\n"],"mappings":"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","names":[]}