react-email 4.1.0-canary.4 → 4.1.0-canary.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/dist/cli/index.mjs +261 -187
- package/dist/preview/.next/BUILD_ID +1 -1
- package/dist/preview/.next/app-build-manifest.json +32 -32
- package/dist/preview/.next/build-manifest.json +14 -14
- package/dist/preview/.next/diagnostics/framework.json +1 -1
- package/dist/preview/.next/next-minimal-server.js.nft.json +1 -1
- package/dist/preview/.next/next-server.js.nft.json +1 -1
- package/dist/preview/.next/prerender-manifest.json +3 -3
- package/dist/preview/.next/required-server-files.json +8 -7
- package/dist/preview/.next/server/app/_not-found/page.js +1 -1
- package/dist/preview/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/preview/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/app/favicon.ico/route.js +1 -1
- package/dist/preview/.next/server/app/favicon.ico/route.js.nft.json +1 -1
- package/dist/preview/.next/server/app/page.js +1 -1
- package/dist/preview/.next/server/app/page.js.nft.json +1 -1
- package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/app/preview/[...slug]/page.js +188 -128
- package/dist/preview/.next/server/app/preview/[...slug]/page.js.nft.json +1 -1
- package/dist/preview/.next/server/app/preview/[...slug]/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/chunks/134.js +6 -0
- package/dist/preview/.next/server/chunks/235.js +15 -0
- package/dist/preview/.next/server/chunks/315.js +1 -0
- package/dist/preview/.next/server/chunks/343.js +20 -0
- package/dist/preview/.next/server/chunks/428.js +14 -0
- package/dist/preview/.next/server/chunks/963.js +1 -0
- package/dist/preview/.next/server/middleware-build-manifest.js +1 -1
- package/dist/preview/.next/server/next-font-manifest.js +1 -1
- package/dist/preview/.next/server/next-font-manifest.json +1 -1
- package/dist/preview/.next/server/pages/500.html +1 -1
- package/dist/preview/.next/server/pages/_app.js +1 -1
- package/dist/preview/.next/server/pages/_app.js.nft.json +1 -1
- package/dist/preview/.next/server/pages/_document.js +1 -1
- package/dist/preview/.next/server/pages/_document.js.nft.json +1 -1
- package/dist/preview/.next/server/pages/_error.js +1 -1
- package/dist/preview/.next/server/pages/_error.js.nft.json +1 -1
- package/dist/preview/.next/server/server-reference-manifest.js +1 -1
- package/dist/preview/.next/server/server-reference-manifest.json +1 -1
- package/dist/preview/.next/static/{JZPm9ao1byHQqJdt3oG1X → EYH0WN4--LLC3GZrZIVN8}/_buildManifest.js +1 -1
- package/dist/preview/.next/static/chunks/107-3043079e7cb8bcae.js +1 -0
- package/dist/preview/.next/static/chunks/293-297b1eb2241f9a70.js +1 -0
- package/dist/preview/.next/static/chunks/3bd82e28-cda2c00a924937c5.js +1 -0
- package/dist/preview/.next/static/chunks/45-1021fac82f766268.js +1 -0
- package/dist/preview/.next/static/chunks/484-a7b30a88a7939680.js +1 -0
- package/dist/preview/.next/static/chunks/589-817d8691661d370e.js +1 -0
- package/dist/preview/.next/static/chunks/902-c34acb56733e0ce1.js +1 -0
- package/dist/preview/.next/static/chunks/app/_not-found/page-4cbc7dce3ad33336.js +1 -0
- package/dist/preview/.next/static/chunks/app/layout-46a09d953364e102.js +1 -0
- package/dist/preview/.next/static/chunks/app/page-65fd67d48528e2ba.js +1 -0
- package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-5e69ffe7506383a0.js +1 -0
- package/dist/preview/.next/static/chunks/f33a14d2-ec7c5f0b91818561.js +6 -0
- package/dist/preview/.next/static/chunks/framework-b887e9fc751a9906.js +1 -0
- package/dist/preview/.next/static/chunks/main-9a03e7ba8acb1900.js +1 -0
- package/dist/preview/.next/static/chunks/main-app-dbd8e1ec12eabb66.js +1 -0
- package/dist/preview/.next/static/chunks/pages/_app-542a93a5a214e1c0.js +1 -0
- package/dist/preview/.next/static/chunks/pages/_error-d5fe1b1612642f76.js +1 -0
- package/dist/preview/.next/static/chunks/webpack-31c45daa2bd82a7b.js +1 -0
- package/dist/preview/.next/static/css/6f42d128f111d7fa.css +3 -0
- package/dist/preview/.next/trace +28 -27
- package/package.json +43 -43
- package/src/actions/email-validation/check-compatibility.ts +1 -1
- package/src/actions/email-validation/check-images.spec.tsx +1 -1
- package/src/actions/email-validation/check-links.spec.tsx +1 -1
- package/src/actions/email-validation/quick-fetch.ts +1 -1
- package/src/actions/render-email-by-path.tsx +2 -2
- package/src/app/preview/[...slug]/preview.tsx +1 -1
- package/src/components/sidebar/file-tree-directory-children.tsx +7 -2
- package/src/components/toolbar.tsx +1 -0
- package/src/contexts/emails.tsx +1 -3
- package/src/contexts/fragment-identifier.tsx +3 -1
- package/src/contexts/preview.tsx +1 -3
- package/src/hooks/use-email-rendering-result.ts +1 -1
- package/src/hooks/use-hot-reload.ts +1 -1
- package/src/utils/__snapshots__/get-email-component.spec.ts.snap +1 -1
- package/src/utils/caniemail/ast/get-object-variables.ts +1 -1
- package/src/utils/caniemail/tailwind/generate-tailwind-rules.ts +1 -1
- package/src/utils/caniemail/tailwind/get-tailwind-config.ts +1 -1
- package/src/utils/caniemail/tailwind/get-tailwind-metadata.ts +1 -1
- package/src/utils/get-email-component.ts +1 -1
- package/src/utils/get-emails-directory-metadata.ts +24 -13
- package/src/utils/index.ts +2 -2
- package/src/utils/run-bundled-code.ts +1 -1
- package/tailwind.config.ts +2 -1
- package/tsconfig.json +1 -1
- package/dist/cli/index.d.mts +0 -1
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +0 -1325
- package/dist/preview/.next/server/chunks/362.js +0 -1
- package/dist/preview/.next/server/chunks/395.js +0 -1
- package/dist/preview/.next/server/chunks/574.js +0 -6
- package/dist/preview/.next/server/chunks/735.js +0 -13
- package/dist/preview/.next/server/chunks/840.js +0 -14
- package/dist/preview/.next/server/chunks/886.js +0 -8
- package/dist/preview/.next/static/chunks/246-e7336e2929971f63.js +0 -1
- package/dist/preview/.next/static/chunks/270-688096d43c717256.js +0 -1
- package/dist/preview/.next/static/chunks/539-6e9405ecdc007bb7.js +0 -1
- package/dist/preview/.next/static/chunks/587-11b31fa1b8f77a29.js +0 -1
- package/dist/preview/.next/static/chunks/782947c8-c6cfd05e68542601.js +0 -1
- package/dist/preview/.next/static/chunks/803-db74f262c4755323.js +0 -1
- package/dist/preview/.next/static/chunks/853-a01d49f63a859f3d.js +0 -1
- package/dist/preview/.next/static/chunks/afa401a5-55858bf5265319eb.js +0 -6
- package/dist/preview/.next/static/chunks/app/_not-found/page-85e83b2d4bd569a2.js +0 -1
- package/dist/preview/.next/static/chunks/app/layout-58e02c2c8b197b04.js +0 -1
- package/dist/preview/.next/static/chunks/app/page-dd13899a1b8e35f9.js +0 -1
- package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-94fd27d6538e2c16.js +0 -1
- package/dist/preview/.next/static/chunks/framework-b5f555f62da46ed9.js +0 -1
- package/dist/preview/.next/static/chunks/main-a839e2fbd78a08fa.js +0 -1
- package/dist/preview/.next/static/chunks/main-app-2cfbaf0185a1cd0e.js +0 -1
- package/dist/preview/.next/static/chunks/pages/_app-ee26b5d329c4bb79.js +0 -1
- package/dist/preview/.next/static/chunks/pages/_error-90cb3f6367e28bcd.js +0 -1
- package/dist/preview/.next/static/chunks/webpack-6755bde10ea8daa8.js +0 -1
- package/dist/preview/.next/static/css/67e57230289273a9.css +0 -3
- /package/dist/preview/.next/static/{JZPm9ao1byHQqJdt3oG1X → EYH0WN4--LLC3GZrZIVN8}/_ssgManifest.js +0 -0
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-email",
|
|
3
|
-
"version": "4.1.0-canary.
|
|
3
|
+
"version": "4.1.0-canary.6",
|
|
4
4
|
"description": "A live preview of your emails right in your browser.",
|
|
5
5
|
"bin": {
|
|
6
|
-
"email": "./dist/cli/index.
|
|
6
|
+
"email": "./dist/cli/index.mjs"
|
|
7
7
|
},
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"repository": {
|
|
@@ -19,73 +19,73 @@
|
|
|
19
19
|
"node": ">=18.0.0"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@babel/parser": "^7.
|
|
23
|
-
"@babel/traverse": "^7.
|
|
24
|
-
"chalk": "^
|
|
22
|
+
"@babel/parser": "^7.27.0",
|
|
23
|
+
"@babel/traverse": "^7.27.0",
|
|
24
|
+
"chalk": "^5.0.0",
|
|
25
25
|
"chokidar": "^4.0.3",
|
|
26
|
-
"commander": "^
|
|
26
|
+
"commander": "^13.0.0",
|
|
27
27
|
"debounce": "^2.0.0",
|
|
28
28
|
"esbuild": "^0.25.0",
|
|
29
|
-
"glob": "^
|
|
30
|
-
"log-symbols": "^
|
|
31
|
-
"mime-types": "^
|
|
32
|
-
"next": "^15.
|
|
29
|
+
"glob": "^11.0.0",
|
|
30
|
+
"log-symbols": "^7.0.0",
|
|
31
|
+
"mime-types": "^3.0.0",
|
|
32
|
+
"next": "^15.3.1",
|
|
33
33
|
"normalize-path": "^3.0.0",
|
|
34
|
-
"ora": "^
|
|
35
|
-
"socket.io": "^4.8.1"
|
|
34
|
+
"ora": "^8.0.0",
|
|
35
|
+
"socket.io": "^4.8.1",
|
|
36
|
+
"tsconfig-paths": "4.2.0"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"@babel/core": "7.26.10",
|
|
39
|
-
"@lottiefiles/dotlottie-react": "0.
|
|
40
|
-
"@radix-ui/colors": "
|
|
41
|
-
"@radix-ui/react-collapsible": "1.1.
|
|
42
|
-
"@radix-ui/react-dropdown-menu": "2.1.
|
|
43
|
-
"@radix-ui/react-popover": "1.1.
|
|
44
|
-
"@radix-ui/react-slot": "1.
|
|
45
|
-
"@radix-ui/react-tabs": "1.1.
|
|
46
|
-
"@radix-ui/react-toggle-group": "1.1.
|
|
47
|
-
"@radix-ui/react-tooltip": "1.
|
|
48
|
-
"@swc/core": "1.
|
|
40
|
+
"@lottiefiles/dotlottie-react": "0.13.3",
|
|
41
|
+
"@radix-ui/colors": "3.0.0",
|
|
42
|
+
"@radix-ui/react-collapsible": "1.1.7",
|
|
43
|
+
"@radix-ui/react-dropdown-menu": "2.1.10",
|
|
44
|
+
"@radix-ui/react-popover": "1.1.10",
|
|
45
|
+
"@radix-ui/react-slot": "1.2.0",
|
|
46
|
+
"@radix-ui/react-tabs": "1.1.7",
|
|
47
|
+
"@radix-ui/react-toggle-group": "1.1.6",
|
|
48
|
+
"@radix-ui/react-tooltip": "1.2.3",
|
|
49
|
+
"@swc/core": "1.11.21",
|
|
49
50
|
"@types/babel__core": "7.20.5",
|
|
50
|
-
"@types/babel__traverse": "
|
|
51
|
+
"@types/babel__traverse": "7.20.7",
|
|
51
52
|
"@types/fs-extra": "11.0.1",
|
|
52
53
|
"@types/mime-types": "2.1.4",
|
|
53
|
-
"@types/node": "22.
|
|
54
|
+
"@types/node": "22.14.1",
|
|
54
55
|
"@types/normalize-path": "3.0.2",
|
|
55
56
|
"@types/react": "19.0.10",
|
|
56
57
|
"@types/react-dom": "19.0.4",
|
|
57
58
|
"@types/webpack": "5.28.5",
|
|
58
|
-
"
|
|
59
|
-
"autoprefixer": "10.4.20",
|
|
59
|
+
"autoprefixer": "10.4.21",
|
|
60
60
|
"clsx": "2.1.1",
|
|
61
|
-
"framer-motion": "12.
|
|
61
|
+
"framer-motion": "12.7.5",
|
|
62
62
|
"jiti": "2.4.2",
|
|
63
63
|
"json5": "2.2.3",
|
|
64
64
|
"module-punycode": "npm:punycode@2.3.1",
|
|
65
|
-
"node-html-parser": "
|
|
66
|
-
"postcss": "8.
|
|
67
|
-
"prettier-plugin-tailwindcss": "0.6.6",
|
|
65
|
+
"node-html-parser": "7.0.1",
|
|
66
|
+
"postcss": "8.5.3",
|
|
68
67
|
"pretty-bytes": "6.1.1",
|
|
69
|
-
"prism-react-renderer": "2.1
|
|
68
|
+
"prism-react-renderer": "2.4.1",
|
|
70
69
|
"react": "19.0.0",
|
|
71
70
|
"react-dom": "19.0.0",
|
|
72
|
-
"sharp": "0.
|
|
73
|
-
"socket.io-client": "4.8.
|
|
74
|
-
"sonner": "
|
|
75
|
-
"source-map-js": "1.
|
|
71
|
+
"sharp": "0.34.1",
|
|
72
|
+
"socket.io-client": "4.8.1",
|
|
73
|
+
"sonner": "2.0.3",
|
|
74
|
+
"source-map-js": "1.2.1",
|
|
76
75
|
"spamc": "0.0.5",
|
|
77
|
-
"stacktrace-parser": "0.1.
|
|
78
|
-
"tailwind-merge": "
|
|
76
|
+
"stacktrace-parser": "0.1.11",
|
|
77
|
+
"tailwind-merge": "3.2.0",
|
|
79
78
|
"tailwindcss": "3.4.0",
|
|
80
|
-
"tsup": "
|
|
81
|
-
"tsx": "4.
|
|
82
|
-
"typescript": "5.8.
|
|
79
|
+
"tsup": "8.4.0",
|
|
80
|
+
"tsx": "4.19.3",
|
|
81
|
+
"typescript": "5.8.3",
|
|
83
82
|
"use-debounce": "10.0.4",
|
|
84
|
-
"zod": "3.24.
|
|
85
|
-
"@react-email/components": "0.0
|
|
83
|
+
"zod": "3.24.3",
|
|
84
|
+
"@react-email/components": "0.1.0-canary.3"
|
|
86
85
|
},
|
|
87
86
|
"scripts": {
|
|
88
|
-
"build": "tsup-node && node ./scripts/build-preview-server.mjs
|
|
87
|
+
"build": "tsup-node && node ./scripts/build-preview-server.mjs",
|
|
88
|
+
"postbuild": "pnpm install --frozen-lockfile",
|
|
89
89
|
"caniemail:fetch": "node ./scripts/fill-caniemail-data.mjs",
|
|
90
90
|
"clean": "rm -rf dist",
|
|
91
91
|
"dev": "tsup-node --watch",
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { parse } from '@babel/parser';
|
|
3
3
|
import traverse from '@babel/traverse';
|
|
4
4
|
import {
|
|
5
|
-
type SourceLocation,
|
|
6
5
|
convertLocationIntoObject,
|
|
7
6
|
getObjectVariables,
|
|
7
|
+
type SourceLocation,
|
|
8
8
|
} from '../../utils/caniemail/ast/get-object-variables';
|
|
9
9
|
import type { StylePropertyUsage } from '../../utils/caniemail/ast/get-used-style-properties';
|
|
10
10
|
import {
|
|
@@ -3,7 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import logSymbols from 'log-symbols';
|
|
6
|
-
import ora from 'ora';
|
|
6
|
+
import ora, { type Ora } from 'ora';
|
|
7
7
|
import { isBuilding, isPreviewDevelopment } from '../app/env';
|
|
8
8
|
import { getEmailComponent } from '../utils/get-email-component';
|
|
9
9
|
import { improveErrorWithSourceMap } from '../utils/improve-error-with-sourcemap';
|
|
@@ -35,7 +35,7 @@ export const renderEmailByPath = async (
|
|
|
35
35
|
const timeBeforeEmailRendered = performance.now();
|
|
36
36
|
|
|
37
37
|
const emailFilename = path.basename(emailPath);
|
|
38
|
-
let spinner:
|
|
38
|
+
let spinner: Ora | undefined;
|
|
39
39
|
if (!isBuilding && !isPreviewDevelopment) {
|
|
40
40
|
spinner = ora({
|
|
41
41
|
text: `Rendering email template ${emailFilename}\n`,
|
|
@@ -8,8 +8,8 @@ import { useDebouncedCallback } from 'use-debounce';
|
|
|
8
8
|
import { Topbar } from '../../../components';
|
|
9
9
|
import { CodeContainer } from '../../../components/code-container';
|
|
10
10
|
import {
|
|
11
|
-
ResizableWrapper,
|
|
12
11
|
makeIframeDocumentBubbleEvents,
|
|
12
|
+
ResizableWrapper,
|
|
13
13
|
} from '../../../components/resizable-wrapper';
|
|
14
14
|
import { Send } from '../../../components/send';
|
|
15
15
|
import { useToolbarState } from '../../../components/toolbar';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Collapsible from '@radix-ui/react-collapsible';
|
|
2
2
|
import { AnimatePresence, LayoutGroup, motion } from 'framer-motion';
|
|
3
3
|
import Link from 'next/link';
|
|
4
|
-
import { useSearchParams } from 'next/navigation';
|
|
4
|
+
import { useRouter, useSearchParams } from 'next/navigation';
|
|
5
5
|
import { cn } from '../../utils';
|
|
6
6
|
import type { EmailsDirectory } from '../../utils/get-emails-directory-metadata';
|
|
7
7
|
import { IconFile } from '../icons/icon-file';
|
|
@@ -14,6 +14,7 @@ export const FileTreeDirectoryChildren = (props: {
|
|
|
14
14
|
isRoot?: boolean;
|
|
15
15
|
}) => {
|
|
16
16
|
const searchParams = useSearchParams();
|
|
17
|
+
const router = useRouter();
|
|
17
18
|
|
|
18
19
|
return (
|
|
19
20
|
<AnimatePresence initial={false}>
|
|
@@ -71,7 +72,11 @@ export const FileTreeDirectoryChildren = (props: {
|
|
|
71
72
|
pathname: `/preview/${emailSlug}`,
|
|
72
73
|
search: searchParams.toString(),
|
|
73
74
|
}}
|
|
74
|
-
|
|
75
|
+
onMouseOver={() => {
|
|
76
|
+
router.prefetch(
|
|
77
|
+
`/preview/${emailSlug}?${searchParams.toString()}`,
|
|
78
|
+
);
|
|
79
|
+
}}
|
|
75
80
|
key={emailSlug}
|
|
76
81
|
>
|
|
77
82
|
<motion.span
|
|
@@ -104,6 +104,7 @@ const ToolbarInner = ({
|
|
|
104
104
|
});
|
|
105
105
|
|
|
106
106
|
if (!isBuilding) {
|
|
107
|
+
// biome-ignore lint/correctness/useHookAtTopLevel: This is fine since isBuilding does not change at runtime
|
|
107
108
|
useEffect(() => {
|
|
108
109
|
(async () => {
|
|
109
110
|
const lintingRows = await loadLinting();
|
package/src/contexts/emails.tsx
CHANGED
|
@@ -32,9 +32,7 @@ export const EmailsProvider = (props: {
|
|
|
32
32
|
useState<EmailsDirectory>(props.initialEmailsDirectoryMetadata);
|
|
33
33
|
|
|
34
34
|
if (!isBuilding) {
|
|
35
|
-
// this will not change on runtime so it doesn't violate
|
|
36
|
-
// the rules of hooks
|
|
37
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
35
|
+
// biome-ignore lint/correctness/useHookAtTopLevel: this will not change on runtime so it doesn't violate the rules of hooks
|
|
38
36
|
useHotreload(async () => {
|
|
39
37
|
const metadata = await getEmailsDirectoryMetadataAction(
|
|
40
38
|
props.initialEmailsDirectoryMetadata.absolutePath,
|
|
@@ -18,7 +18,9 @@ export const useFragmentIdentifier = () => {
|
|
|
18
18
|
|
|
19
19
|
export const FragmentIdentifierProvider = ({
|
|
20
20
|
children,
|
|
21
|
-
}: {
|
|
21
|
+
}: {
|
|
22
|
+
children: React.ReactNode;
|
|
23
|
+
}) => {
|
|
22
24
|
const [fragmentIdentifier, setFragmentIdentifier] = useState<string>();
|
|
23
25
|
const pathname = usePathname();
|
|
24
26
|
const searchParams = useSearchParams();
|
package/src/contexts/preview.tsx
CHANGED
|
@@ -50,9 +50,7 @@ export const PreviewProvider = ({
|
|
|
50
50
|
);
|
|
51
51
|
|
|
52
52
|
if (!isBuilding) {
|
|
53
|
-
// this will not change on runtime so it doesn't violate
|
|
54
|
-
// the rules of hooks
|
|
55
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
53
|
+
// biome-ignore lint/correctness/useHookAtTopLevel: this will not change on runtime so it doesn't violate the rules of hooks
|
|
56
54
|
useHotreload((changes) => {
|
|
57
55
|
const changeForThisEmail = changes.find((change) =>
|
|
58
56
|
change.filename.includes(emailSlug),
|
|
@@ -20,7 +20,7 @@ export const useEmailRenderingResult = (
|
|
|
20
20
|
const { emailsDirectoryMetadata } = useEmails();
|
|
21
21
|
|
|
22
22
|
if (!isBuilding) {
|
|
23
|
-
//
|
|
23
|
+
// biome-ignore lint/correctness/useHookAtTopLevel: This is fine since isBuilding does not change at runtime
|
|
24
24
|
useHotreload(async (changes) => {
|
|
25
25
|
for await (const change of changes) {
|
|
26
26
|
const relativePathForChangedFile =
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
2
|
|
|
3
|
-
exports[`getEmailComponent() > with a demo email template 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html dir="ltr" lang="en"><head><link rel="preload" as="image" href="/static/vercel-logo.png"/><link rel="preload" as="image" href="/static/vercel-user.png"/><link rel="preload" as="image" href="/static/vercel-arrow.png"/><link rel="preload" as="image" href="/static/vercel-team.png"/><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/><meta name="x-apple-disable-message-reformatting"/><!--$--></head><body style="margin-left:auto;margin-right:auto;margin-top:auto;margin-bottom:auto;background-color:rgb(255,255,255);padding-left:0.5rem;padding-right:0.5rem;font-family:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji""><div style="display:none;overflow:hidden;line-height:1px;opacity:0;max-height:0;max-width:0">Join Alan on Vercel<div> </div></div><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="margin-left:auto;margin-right:auto;margin-top:40px;margin-bottom:40px;max-width:465px;border-radius:0.25rem;border-width:1px;border-color:rgb(234,234,234);border-style:solid;padding:20px"><tbody><tr style="width:100%"><td><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="margin-top:32px"><tbody><tr><td><img alt="Vercel Logo" height="37" src="/static/vercel-logo.png" style="margin-left:auto;margin-right:auto;margin-top:0px;margin-bottom:0px;display:block;outline:none;border:none;text-decoration:none" width="40"/></td></tr></tbody></table><h1 style="margin-left:0px;margin-right:0px;margin-top:30px;margin-bottom:30px;padding:0px;text-align:center;font-weight:400;font-size:24px;color:rgb(0,0,0)">Join <strong>Enigma</strong> on <strong>Vercel</strong></h1><p style="font-size:14px;color:rgb(0,0,0);line-height:24px;margin-
|
|
3
|
+
exports[`getEmailComponent() > with a demo email template 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html dir="ltr" lang="en"><head><link rel="preload" as="image" href="/static/vercel-logo.png"/><link rel="preload" as="image" href="/static/vercel-user.png"/><link rel="preload" as="image" href="/static/vercel-arrow.png"/><link rel="preload" as="image" href="/static/vercel-team.png"/><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/><meta name="x-apple-disable-message-reformatting"/><!--$--></head><body style="margin-left:auto;margin-right:auto;margin-top:auto;margin-bottom:auto;background-color:rgb(255,255,255);padding-left:0.5rem;padding-right:0.5rem;font-family:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji""><div style="display:none;overflow:hidden;line-height:1px;opacity:0;max-height:0;max-width:0" data-skip-in-text="true">Join Alan on Vercel<div> </div></div><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="margin-left:auto;margin-right:auto;margin-top:40px;margin-bottom:40px;max-width:465px;border-radius:0.25rem;border-width:1px;border-color:rgb(234,234,234);border-style:solid;padding:20px"><tbody><tr style="width:100%"><td><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="margin-top:32px"><tbody><tr><td><img alt="Vercel Logo" height="37" src="/static/vercel-logo.png" style="margin-left:auto;margin-right:auto;margin-top:0px;margin-bottom:0px;display:block;outline:none;border:none;text-decoration:none" width="40"/></td></tr></tbody></table><h1 style="margin-left:0px;margin-right:0px;margin-top:30px;margin-bottom:30px;padding:0px;text-align:center;font-weight:400;font-size:24px;color:rgb(0,0,0)">Join <strong>Enigma</strong> on <strong>Vercel</strong></h1><p style="font-size:14px;color:rgb(0,0,0);line-height:24px;margin-top:16px;margin-bottom:16px">Hello <!-- -->alanturing<!-- -->,</p><p style="font-size:14px;color:rgb(0,0,0);line-height:24px;margin-top:16px;margin-bottom:16px"><strong>Alan</strong> (<a href="mailto:alan.turing@example.com" style="color:rgb(37,99,235);text-decoration-line:none" target="_blank">alan.turing@example.com</a>) has invited you to the <strong>Enigma</strong> team on<!-- --> <strong>Vercel</strong>.</p><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation"><tbody><tr><td><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation"><tbody style="width:100%"><tr style="width:100%"><td align="right" data-id="__react-email-column"><img alt="alanturing's profile picture" height="64" src="/static/vercel-user.png" style="border-radius:9999px;display:block;outline:none;border:none;text-decoration:none" width="64"/></td><td align="center" data-id="__react-email-column"><img alt="Arrow indicating invitation" height="9" src="/static/vercel-arrow.png" style="display:block;outline:none;border:none;text-decoration:none" width="12"/></td><td align="left" data-id="__react-email-column"><img alt="Enigma team logo" height="64" src="/static/vercel-team.png" style="border-radius:9999px;display:block;outline:none;border:none;text-decoration:none" width="64"/></td></tr></tbody></table></td></tr></tbody></table><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="margin-top:32px;margin-bottom:32px;text-align:center"><tbody><tr><td><a href="https://vercel.com" style="border-radius:0.25rem;background-color:rgb(0,0,0);padding-left:20px;padding-right:20px;padding-top:12px;padding-bottom:12px;text-align:center;font-weight:600;font-size:12px;color:rgb(255,255,255);text-decoration-line:none;line-height:100%;text-decoration:none;display:inline-block;max-width:100%;mso-padding-alt:0px" target="_blank"><span><!--[if mso]><i style="mso-font-width:500%;mso-text-raise:18" hidden>  </i><![endif]--></span><span style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:9px">Join the team</span><span><!--[if mso]><i style="mso-font-width:500%" hidden>  ​</i><![endif]--></span></a></td></tr></tbody></table><p style="font-size:14px;color:rgb(0,0,0);line-height:24px;margin-top:16px;margin-bottom:16px">or copy and paste this URL into your browser:<!-- --> <a href="https://vercel.com" style="color:rgb(37,99,235);text-decoration-line:none" target="_blank">https://vercel.com</a></p><hr style="margin-left:0px;margin-right:0px;margin-top:26px;margin-bottom:26px;width:100%;border-width:1px;border-color:rgb(234,234,234);border-style:solid;border:none;border-top:1px solid #eaeaea"/><p style="color:rgb(102,102,102);font-size:12px;line-height:24px;margin-top:16px;margin-bottom:16px">This invitation was intended for<!-- --> <span style="color:rgb(0,0,0)">alanturing</span>. This invite was sent from <span style="color:rgb(0,0,0)">204.13.186.218</span> <!-- -->located in<!-- --> <span style="color:rgb(0,0,0)">São Paulo, Brazil</span>. If you were not expecting this invitation, you can ignore this email. If you are concerned about your account's safety, please reply to this email to get in touch with us.</p></td></tr></tbody></table><!--/$--></body></html>"`;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Root, Rule } from 'postcss';
|
|
2
1
|
import postcss from 'postcss';
|
|
2
|
+
import type { Root, Rule } from 'postcss';
|
|
3
3
|
import evaluateTailwindFunctions from 'tailwindcss/lib/lib/evaluateTailwindFunctions';
|
|
4
4
|
import { generateRules as rawGenerateRules } from 'tailwindcss/lib/lib/generateRules';
|
|
5
5
|
import type { JitContext } from 'tailwindcss/lib/lib/setupContextUtils';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import type { Node } from '@babel/traverse';
|
|
4
3
|
import traverse from '@babel/traverse';
|
|
4
|
+
import type { Node } from '@babel/traverse';
|
|
5
5
|
import * as esbuild from 'esbuild';
|
|
6
6
|
import type { Config as TailwindOriginalConfig } from 'tailwindcss';
|
|
7
7
|
import type { AST } from '../../../actions/email-validation/check-compatibility';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import traverse from '@babel/traverse';
|
|
2
2
|
import type { JitContext } from 'tailwindcss/lib/lib/setupContextUtils';
|
|
3
3
|
import type { AST } from '../../../actions/email-validation/check-compatibility';
|
|
4
|
-
import { type TailwindConfig
|
|
4
|
+
import { getTailwindConfig, type TailwindConfig } from './get-tailwind-config';
|
|
5
5
|
import { setupTailwindContext } from './setup-tailwind-context';
|
|
6
6
|
|
|
7
7
|
export const getTailwindMetadata = async (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import type { render } from '@react-email/components';
|
|
3
|
-
import { type BuildFailure, type OutputFile
|
|
3
|
+
import { type BuildFailure, build, type OutputFile } from 'esbuild';
|
|
4
4
|
import type React from 'react';
|
|
5
5
|
import type { RawSourceMap } from 'source-map-js';
|
|
6
6
|
import { z } from 'zod';
|
|
@@ -2,25 +2,33 @@
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
|
|
5
|
-
const isFileAnEmail = (fullPath: string): boolean => {
|
|
6
|
-
|
|
5
|
+
const isFileAnEmail = async (fullPath: string): Promise<boolean> => {
|
|
6
|
+
let fileHandle: fs.promises.FileHandle;
|
|
7
|
+
try {
|
|
8
|
+
fileHandle = await fs.promises.open(fullPath, 'r');
|
|
9
|
+
} catch (exception) {
|
|
10
|
+
console.warn(exception);
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
const stat = await fileHandle.stat();
|
|
7
14
|
|
|
8
|
-
if (stat.isDirectory())
|
|
15
|
+
if (stat.isDirectory()) {
|
|
16
|
+
await fileHandle.close();
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
9
19
|
|
|
10
20
|
const { ext } = path.parse(fullPath);
|
|
11
21
|
|
|
12
|
-
if (!['.js', '.tsx', '.jsx'].includes(ext))
|
|
13
|
-
|
|
14
|
-
// This is to avoid a possible race condition where the file doesn't exist anymore
|
|
15
|
-
// once we are checking if it is an actual email, this could cause issues that
|
|
16
|
-
// would be very hard to debug and find out the why of it happening.
|
|
17
|
-
if (!fs.existsSync(fullPath)) {
|
|
22
|
+
if (!['.js', '.tsx', '.jsx'].includes(ext)) {
|
|
23
|
+
await fileHandle.close();
|
|
18
24
|
return false;
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
// check with a heuristic to see if the file has at least
|
|
22
28
|
// a default export (ES6) or module.exports (CommonJS) or named exports (MDX)
|
|
23
|
-
const fileContents =
|
|
29
|
+
const fileContents = await fileHandle.readFile('utf8');
|
|
30
|
+
|
|
31
|
+
await fileHandle.close();
|
|
24
32
|
|
|
25
33
|
// Check for ES6 export default syntax
|
|
26
34
|
const hasES6DefaultExport = /\bexport\s+default\b/gm.test(fileContents);
|
|
@@ -80,10 +88,13 @@ export const getEmailsDirectoryMetadata = async (
|
|
|
80
88
|
withFileTypes: true,
|
|
81
89
|
});
|
|
82
90
|
|
|
83
|
-
const
|
|
84
|
-
.
|
|
91
|
+
const isEmailPredicates = await Promise.all(
|
|
92
|
+
dirents.map((dirent) =>
|
|
85
93
|
isFileAnEmail(path.join(absolutePathToEmailsDirectory, dirent.name)),
|
|
86
|
-
)
|
|
94
|
+
),
|
|
95
|
+
);
|
|
96
|
+
const emailFilenames = dirents
|
|
97
|
+
.filter((_, i) => isEmailPredicates[i])
|
|
87
98
|
.map((dirent) =>
|
|
88
99
|
keepFileExtensions
|
|
89
100
|
? dirent.name
|
package/src/utils/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import vm from 'node:vm';
|
|
3
|
-
import {
|
|
3
|
+
import { err, ok, type Result } from './result';
|
|
4
4
|
import { staticNodeModulesForVM } from './static-node-modules-for-vm';
|
|
5
5
|
|
|
6
6
|
export const runBundledCode = (
|
package/tailwind.config.ts
CHANGED
package/tsconfig.json
CHANGED
package/dist/cli/index.d.mts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
package/dist/cli/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|