better-svelte-email 0.0.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Body.svelte +14 -5
- package/dist/components/Body.svelte.d.ts +6 -12
- package/dist/components/Button.svelte +11 -4
- package/dist/components/Button.svelte.d.ts +5 -15
- package/dist/components/Column.svelte +19 -0
- package/dist/components/Column.svelte.d.ts +10 -0
- package/dist/components/Container.svelte +10 -3
- package/dist/components/Container.svelte.d.ts +5 -11
- package/dist/components/Hr.svelte +14 -0
- package/dist/components/Hr.svelte.d.ts +4 -0
- package/dist/components/Html.svelte +3 -3
- package/dist/components/Html.svelte.d.ts +1 -1
- package/dist/components/Link.svelte +26 -0
- package/dist/components/Link.svelte.d.ts +9 -0
- package/dist/components/Row.svelte +30 -0
- package/dist/components/Row.svelte.d.ts +8 -0
- package/dist/components/Section.svelte +14 -5
- package/dist/components/Section.svelte.d.ts +5 -11
- package/dist/components/Text.svelte +13 -3
- package/dist/components/Text.svelte.d.ts +6 -12
- package/dist/components/index.d.ts +7 -3
- package/dist/components/index.js +7 -3
- package/dist/emails/apple-receipt.svelte +260 -0
- package/dist/emails/apple-receipt.svelte.d.ts +18 -0
- package/dist/emails/demo-email.svelte +31 -31
- package/dist/emails/test-email.svelte +7 -3
- package/dist/emails/vercel-invite-user.svelte +133 -0
- package/dist/emails/vercel-invite-user.svelte.d.ts +14 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -2
- package/dist/preprocessor/index.js +27 -15
- package/dist/preprocessor/parser.d.ts +5 -2
- package/dist/preprocessor/parser.js +87 -21
- package/dist/preprocessor/transformer.js +3 -3
- package/dist/preprocessor/types.d.ts +21 -0
- package/dist/preview/Preview.svelte +231 -0
- package/dist/preview/Preview.svelte.d.ts +7 -0
- package/dist/preview/index.d.ts +85 -0
- package/dist/preview/index.js +183 -0
- package/package.json +3 -1
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { Resend } from 'resend';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { render } from 'svelte/server';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import prettier from 'prettier/standalone';
|
|
6
|
+
import parserHtml from 'prettier/parser-html';
|
|
7
|
+
/**
|
|
8
|
+
* Get a list of all email component files in the specified directory.
|
|
9
|
+
*
|
|
10
|
+
* @param options.path - Relative path from root to emails folder (default: '/src/lib/emails')
|
|
11
|
+
* @param options.root - Absolute path to project root (auto-detected if not provided)
|
|
12
|
+
* @returns PreviewData object with list of email files and the path
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* // In a +page.server.ts file
|
|
17
|
+
* import { emailList } from 'better-svelte-email/preview';
|
|
18
|
+
*
|
|
19
|
+
* export function load() {
|
|
20
|
+
* const emails = emailList({
|
|
21
|
+
* root: process.cwd(),
|
|
22
|
+
* path: '/src/lib/emails'
|
|
23
|
+
* });
|
|
24
|
+
* return { emails };
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export const emailList = ({ path: emailPath = '/src/lib/emails', root } = {}) => {
|
|
29
|
+
// If root is not provided, try to use process.cwd()
|
|
30
|
+
if (!root) {
|
|
31
|
+
try {
|
|
32
|
+
root = process.cwd();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw new Error('Could not determine the root path of your project. Please pass in the root param manually using process.cwd() or an absolute path');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const fullPath = path.join(root, emailPath);
|
|
39
|
+
// Check if directory exists
|
|
40
|
+
if (!fs.existsSync(fullPath)) {
|
|
41
|
+
console.warn(`Email directory not found: ${fullPath}`);
|
|
42
|
+
return { files: null, path: emailPath };
|
|
43
|
+
}
|
|
44
|
+
const files = createEmailComponentList(emailPath, getFiles(fullPath));
|
|
45
|
+
if (!files.length) {
|
|
46
|
+
return { files: null, path: emailPath };
|
|
47
|
+
}
|
|
48
|
+
return { files, path: emailPath };
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* SvelteKit form action to render an email component.
|
|
52
|
+
* Use this with the Preview component to render email templates on demand.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* // +page.server.ts
|
|
57
|
+
* import { createEmail } from 'better-svelte-email/preview';
|
|
58
|
+
*
|
|
59
|
+
* export const actions = createEmail;
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export const createEmail = {
|
|
63
|
+
'create-email': async (event) => {
|
|
64
|
+
try {
|
|
65
|
+
const data = await event.request.formData();
|
|
66
|
+
const file = data.get('file');
|
|
67
|
+
const emailPath = data.get('path');
|
|
68
|
+
if (!file || !emailPath) {
|
|
69
|
+
return {
|
|
70
|
+
status: 400,
|
|
71
|
+
body: { error: 'Missing file or path parameter' }
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const getEmailComponent = async () => {
|
|
75
|
+
try {
|
|
76
|
+
// Import the email component dynamically
|
|
77
|
+
return (await import(/* @vite-ignore */ `${emailPath}/${file}.svelte`)).default;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
throw new Error(`Failed to import email component '${file}'. Make sure the file exists and includes the <Head /> component.`);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const emailComponent = await getEmailComponent();
|
|
84
|
+
// Render the component to HTML
|
|
85
|
+
const { body } = render(emailComponent);
|
|
86
|
+
// Remove all HTML comments from the body before formatting
|
|
87
|
+
const bodyWithoutComments = body.replace(/<!--[\s\S]*?-->/g, '');
|
|
88
|
+
return prettier.format(bodyWithoutComments, { parser: 'html', plugins: [parserHtml] });
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.error('Error rendering email:', error);
|
|
92
|
+
return {
|
|
93
|
+
status: 500,
|
|
94
|
+
error: {
|
|
95
|
+
message: error instanceof Error ? error.message : 'Failed to render email'
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const defaultSendEmailFunction = async ({ from, to, subject, html }, resendApiKey) => {
|
|
102
|
+
// stringify api key to comment out temp
|
|
103
|
+
const resend = new Resend(resendApiKey);
|
|
104
|
+
const email = { from, to, subject, html };
|
|
105
|
+
const resendReq = await resend.emails.send(email);
|
|
106
|
+
if (resendReq.error) {
|
|
107
|
+
return { success: false, error: resendReq.error };
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
return { success: true, error: null };
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Sends the email using the submitted form data.
|
|
115
|
+
*/
|
|
116
|
+
export const sendEmail = ({ customSendEmailFunction, resendApiKey }) => {
|
|
117
|
+
return {
|
|
118
|
+
'send-email': async (event) => {
|
|
119
|
+
const data = await event.request.formData();
|
|
120
|
+
const email = {
|
|
121
|
+
from: 'svelte-email-tailwind <onboarding@resend.dev>',
|
|
122
|
+
to: `${data.get('to')}`,
|
|
123
|
+
subject: `${data.get('component')} ${data.get('note') ? '| ' + data.get('note') : ''}`,
|
|
124
|
+
html: `${data.get('html')}`
|
|
125
|
+
};
|
|
126
|
+
let sent = { success: false, error: null };
|
|
127
|
+
if (!customSendEmailFunction && resendApiKey) {
|
|
128
|
+
sent = await defaultSendEmailFunction(email, resendApiKey);
|
|
129
|
+
}
|
|
130
|
+
else if (customSendEmailFunction) {
|
|
131
|
+
sent = await customSendEmailFunction(email);
|
|
132
|
+
}
|
|
133
|
+
else if (!customSendEmailFunction && !resendApiKey) {
|
|
134
|
+
const error = {
|
|
135
|
+
message: 'Please pass your Resend API key into the "sendEmail" form action, or provide a custom function.'
|
|
136
|
+
};
|
|
137
|
+
return { success: false, error };
|
|
138
|
+
}
|
|
139
|
+
if (sent && sent.error) {
|
|
140
|
+
console.log('Error:', sent.error);
|
|
141
|
+
return { success: false, error: sent.error };
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
console.log('Email was sent successfully.');
|
|
145
|
+
return { success: true, error: null };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
// Recursive function to get files
|
|
151
|
+
function getFiles(dir, files = []) {
|
|
152
|
+
// Get an array of all files and directories in the passed directory using fs.readdirSync
|
|
153
|
+
const fileList = fs.readdirSync(dir);
|
|
154
|
+
// Create the full path of the file/directory by concatenating the passed directory and file/directory name
|
|
155
|
+
for (const file of fileList) {
|
|
156
|
+
const name = `${dir}/${file}`;
|
|
157
|
+
// Check if the current file/directory is a directory using fs.statSync
|
|
158
|
+
if (fs.statSync(name).isDirectory()) {
|
|
159
|
+
// If it is a directory, recursively call the getFiles function with the directory path and the files array
|
|
160
|
+
getFiles(name, files);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
// If it is a file, push the full path to the files array
|
|
164
|
+
files.push(name);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return files;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Creates an array of names from the record of svelte email component file paths
|
|
171
|
+
*/
|
|
172
|
+
function createEmailComponentList(root, paths) {
|
|
173
|
+
const emailComponentList = [];
|
|
174
|
+
paths.forEach((filePath) => {
|
|
175
|
+
if (filePath.includes(`.svelte`)) {
|
|
176
|
+
const fileName = filePath.substring(filePath.indexOf(root) + root.length + 1, filePath.indexOf('.svelte'));
|
|
177
|
+
emailComponentList.push(fileName);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
return emailComponentList;
|
|
181
|
+
}
|
|
182
|
+
// Export the Preview component
|
|
183
|
+
export { default as Preview } from './Preview.svelte';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "better-svelte-email",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"author": "Anatole",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"magic-string": "^0.30.19",
|
|
14
|
+
"svelte-highlight": "^7.8.4",
|
|
14
15
|
"tw-to-css": "^0.0.12"
|
|
15
16
|
},
|
|
16
17
|
"devDependencies": {
|
|
@@ -83,6 +84,7 @@
|
|
|
83
84
|
"dev": "vite dev",
|
|
84
85
|
"build": "vite build && npm run prepack",
|
|
85
86
|
"preview": "vite preview",
|
|
87
|
+
"package": "svelte-package",
|
|
86
88
|
"prepare": "svelte-kit sync || echo ''",
|
|
87
89
|
"prepack": "svelte-kit sync && svelte-package && publint",
|
|
88
90
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|