@razmatinyan/nuxt-email 0.1.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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +272 -0
  3. package/dist/module.d.mts +7 -0
  4. package/dist/module.json +12 -0
  5. package/dist/module.mjs +190 -0
  6. package/dist/runtime/server/api/config.get.d.ts +5 -0
  7. package/dist/runtime/server/api/config.get.js +10 -0
  8. package/dist/runtime/server/api/devtools.d.ts +2 -0
  9. package/dist/runtime/server/api/devtools.js +265 -0
  10. package/dist/runtime/server/api/log.get.d.ts +2 -0
  11. package/dist/runtime/server/api/log.get.js +5 -0
  12. package/dist/runtime/server/api/preview.d.ts +2 -0
  13. package/dist/runtime/server/api/preview.js +12 -0
  14. package/dist/runtime/server/api/send-test.post.d.ts +2 -0
  15. package/dist/runtime/server/api/send-test.post.js +33 -0
  16. package/dist/runtime/server/api/templates.get.d.ts +5 -0
  17. package/dist/runtime/server/api/templates.get.js +8 -0
  18. package/dist/runtime/server/composables/useEmail.d.ts +9 -0
  19. package/dist/runtime/server/composables/useEmail.js +96 -0
  20. package/dist/runtime/server/utils/dev-log.d.ts +14 -0
  21. package/dist/runtime/server/utils/dev-log.js +8 -0
  22. package/dist/runtime/server/utils/email-utils.d.ts +9 -0
  23. package/dist/runtime/server/utils/email-utils.js +134 -0
  24. package/dist/runtime/server/utils/providers/console.d.ts +6 -0
  25. package/dist/runtime/server/utils/providers/console.js +44 -0
  26. package/dist/runtime/server/utils/providers/fetch.d.ts +1 -0
  27. package/dist/runtime/server/utils/providers/index.d.ts +9 -0
  28. package/dist/runtime/server/utils/providers/index.js +33 -0
  29. package/dist/runtime/server/utils/providers/postmark.d.ts +8 -0
  30. package/dist/runtime/server/utils/providers/postmark.js +94 -0
  31. package/dist/runtime/server/utils/providers/resend.d.ts +8 -0
  32. package/dist/runtime/server/utils/providers/resend.js +73 -0
  33. package/dist/runtime/server/utils/providers/sendgrid.d.ts +8 -0
  34. package/dist/runtime/server/utils/providers/sendgrid.js +99 -0
  35. package/dist/runtime/server/utils/providers/shared.d.ts +7 -0
  36. package/dist/runtime/server/utils/providers/shared.js +29 -0
  37. package/dist/runtime/server/utils/providers/smtp.d.ts +8 -0
  38. package/dist/runtime/server/utils/providers/smtp.js +85 -0
  39. package/dist/runtime/server/utils/template-renderer.d.ts +5 -0
  40. package/dist/runtime/server/utils/template-renderer.js +10 -0
  41. package/dist/runtime/server/utils/templates.d.ts +4 -0
  42. package/dist/runtime/server/utils/templates.js +17 -0
  43. package/dist/runtime/templates.d.ts +6 -0
  44. package/dist/runtime/types/index.d.ts +110 -0
  45. package/dist/runtime/types/index.js +0 -0
  46. package/dist/types.d.mts +9 -0
  47. package/package.json +84 -0
@@ -0,0 +1 @@
1
+ declare const $fetch: typeof import('ofetch').$fetch
@@ -0,0 +1,9 @@
1
+ import type { EmailProvider, EmailRuntimeConfig } from '../../../types/index.js.js';
2
+ type ProviderName = 'console' | 'resend' | 'sendgrid' | 'postmark' | 'smtp';
3
+ export declare const VALID_PROVIDERS: ProviderName[];
4
+ export declare function createProvider(name: string, config: EmailRuntimeConfig): EmailProvider;
5
+ export { ConsoleProvider } from './console.js.js';
6
+ export { ResendProvider } from './resend.js.js';
7
+ export { SendGridProvider } from './sendgrid.js.js';
8
+ export { PostmarkProvider } from './postmark.js.js';
9
+ export { SmtpProvider } from './smtp.js.js';
@@ -0,0 +1,33 @@
1
+ import { ConsoleProvider } from "./console.js";
2
+ import { ResendProvider } from "./resend.js";
3
+ import { SendGridProvider } from "./sendgrid.js";
4
+ import { PostmarkProvider } from "./postmark.js";
5
+ import { SmtpProvider } from "./smtp.js";
6
+ export const VALID_PROVIDERS = [
7
+ "console",
8
+ "resend",
9
+ "sendgrid",
10
+ "postmark",
11
+ "smtp"
12
+ ];
13
+ const factories = {
14
+ console: () => new ConsoleProvider(),
15
+ resend: (config) => new ResendProvider(config),
16
+ sendgrid: (config) => new SendGridProvider(config),
17
+ postmark: (config) => new PostmarkProvider(config),
18
+ smtp: (config) => new SmtpProvider(config)
19
+ };
20
+ export function createProvider(name, config) {
21
+ const factory = factories[name];
22
+ if (!factory) {
23
+ throw new Error(
24
+ `[nuxt-email] Unknown provider "${name}". Valid providers: ${VALID_PROVIDERS.join(", ")}`
25
+ );
26
+ }
27
+ return factory(config);
28
+ }
29
+ export { ConsoleProvider } from "./console.js";
30
+ export { ResendProvider } from "./resend.js";
31
+ export { SendGridProvider } from "./sendgrid.js";
32
+ export { PostmarkProvider } from "./postmark.js";
33
+ export { SmtpProvider } from "./smtp.js";
@@ -0,0 +1,8 @@
1
+ import type { EmailProvider, EmailRuntimeConfig, NormalizedPayload, EmailResponse } from '../../../types/index.js.js';
2
+ export declare class PostmarkProvider implements EmailProvider {
3
+ name: string;
4
+ private readonly apiKey;
5
+ constructor(config: EmailRuntimeConfig);
6
+ send(payload: NormalizedPayload): Promise<EmailResponse>;
7
+ verify(): Promise<boolean>;
8
+ }
@@ -0,0 +1,94 @@
1
+ import { toBase64, fetchErrorMessage, omitUndefined } from "./shared.js";
2
+ export class PostmarkProvider {
3
+ name = "postmark";
4
+ apiKey;
5
+ constructor(config) {
6
+ if (!config.apiKey) {
7
+ throw new Error("[nuxt-email] PostmarkProvider requires `apiKey`.");
8
+ }
9
+ this.apiKey = config.apiKey;
10
+ }
11
+ async send(payload) {
12
+ const start = Date.now();
13
+ try {
14
+ const headers = payload.headers ? Object.entries(payload.headers).map(([Name, Value]) => ({
15
+ Name,
16
+ Value
17
+ })) : void 0;
18
+ const attachments = payload.attachments?.map(
19
+ (a) => omitUndefined({
20
+ Name: a.filename,
21
+ Content: toBase64(a.content),
22
+ ContentType: a.contentType ?? "application/octet-stream",
23
+ ContentID: a.cid
24
+ })
25
+ );
26
+ const body = omitUndefined({
27
+ From: payload.from,
28
+ To: payload.to.join(","),
29
+ Cc: payload.cc?.join(","),
30
+ Bcc: payload.bcc?.join(","),
31
+ ReplyTo: payload.replyTo,
32
+ Subject: payload.subject,
33
+ HtmlBody: payload.html,
34
+ TextBody: payload.text,
35
+ Headers: headers,
36
+ Attachments: attachments,
37
+ Metadata: payload.tags,
38
+ MessageStream: "outbound"
39
+ });
40
+ const res = await $fetch("https://api.postmarkapp.com/email", {
41
+ method: "POST",
42
+ headers: {
43
+ "X-Postmark-Server-Token": this.apiKey,
44
+ Accept: "application/json",
45
+ "Content-Type": "application/json"
46
+ },
47
+ body
48
+ });
49
+ if (res.ErrorCode !== 0) {
50
+ return {
51
+ success: false,
52
+ error: `[nuxt-email] Postmark error: ${res.Message}`,
53
+ provider: this.name,
54
+ duration: Date.now() - start
55
+ };
56
+ }
57
+ return {
58
+ success: true,
59
+ messageId: res.MessageID,
60
+ provider: this.name,
61
+ duration: Date.now() - start
62
+ };
63
+ } catch (error) {
64
+ const data = error?.data;
65
+ if (data?.ErrorCode !== void 0 && data.ErrorCode !== 0) {
66
+ return {
67
+ success: false,
68
+ error: `[nuxt-email] Postmark error: ${data.Message ?? "Unknown error"}`,
69
+ provider: this.name,
70
+ duration: Date.now() - start
71
+ };
72
+ }
73
+ return {
74
+ success: false,
75
+ error: fetchErrorMessage("Postmark", error),
76
+ provider: this.name,
77
+ duration: Date.now() - start
78
+ };
79
+ }
80
+ }
81
+ async verify() {
82
+ try {
83
+ await $fetch("https://api.postmarkapp.com/server", {
84
+ headers: {
85
+ "X-Postmark-Server-Token": this.apiKey,
86
+ Accept: "application/json"
87
+ }
88
+ });
89
+ return true;
90
+ } catch {
91
+ return false;
92
+ }
93
+ }
94
+ }
@@ -0,0 +1,8 @@
1
+ import type { EmailProvider, EmailRuntimeConfig, NormalizedPayload, EmailResponse } from '../../../types/index.js.js';
2
+ export declare class ResendProvider implements EmailProvider {
3
+ name: string;
4
+ private readonly apiKey;
5
+ constructor(config: EmailRuntimeConfig);
6
+ send(payload: NormalizedPayload): Promise<EmailResponse>;
7
+ verify(): Promise<boolean>;
8
+ }
@@ -0,0 +1,73 @@
1
+ import { toBase64, fetchErrorMessage, omitUndefined } from "./shared.js";
2
+ export class ResendProvider {
3
+ name = "resend";
4
+ apiKey;
5
+ constructor(config) {
6
+ if (!config.apiKey) {
7
+ throw new Error("[nuxt-email] ResendProvider requires `apiKey`.");
8
+ }
9
+ this.apiKey = config.apiKey;
10
+ }
11
+ async send(payload) {
12
+ const start = Date.now();
13
+ try {
14
+ const attachments = payload.attachments?.map(
15
+ (a) => omitUndefined({
16
+ filename: a.filename,
17
+ content: toBase64(a.content),
18
+ content_type: a.contentType,
19
+ content_id: a.cid
20
+ })
21
+ );
22
+ const tags = payload.tags ? Object.entries(payload.tags).map(([name, value]) => ({
23
+ name,
24
+ value
25
+ })) : void 0;
26
+ const body = omitUndefined({
27
+ from: payload.from,
28
+ to: payload.to,
29
+ cc: payload.cc,
30
+ bcc: payload.bcc,
31
+ reply_to: payload.replyTo,
32
+ subject: payload.subject,
33
+ html: payload.html,
34
+ text: payload.text,
35
+ headers: payload.headers,
36
+ attachments,
37
+ tags,
38
+ scheduled_at: payload.scheduledAt?.toISOString()
39
+ });
40
+ const res = await $fetch(
41
+ "https://api.resend.com/emails",
42
+ {
43
+ method: "POST",
44
+ headers: { Authorization: `Bearer ${this.apiKey}` },
45
+ body
46
+ }
47
+ );
48
+ return {
49
+ success: true,
50
+ messageId: res.id,
51
+ provider: this.name,
52
+ duration: Date.now() - start
53
+ };
54
+ } catch (error) {
55
+ return {
56
+ success: false,
57
+ error: fetchErrorMessage("Resend", error),
58
+ provider: this.name,
59
+ duration: Date.now() - start
60
+ };
61
+ }
62
+ }
63
+ async verify() {
64
+ try {
65
+ await $fetch("https://api.resend.com/domains", {
66
+ headers: { Authorization: `Bearer ${this.apiKey}` }
67
+ });
68
+ return true;
69
+ } catch {
70
+ return false;
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,8 @@
1
+ import type { EmailProvider, EmailRuntimeConfig, NormalizedPayload, EmailResponse } from '../../../types/index.js.js';
2
+ export declare class SendGridProvider implements EmailProvider {
3
+ name: string;
4
+ private readonly apiKey;
5
+ constructor(config: EmailRuntimeConfig);
6
+ send(payload: NormalizedPayload): Promise<EmailResponse>;
7
+ verify(): Promise<boolean>;
8
+ }
@@ -0,0 +1,99 @@
1
+ import {
2
+ toBase64,
3
+ parseAddress,
4
+ fetchErrorMessage,
5
+ omitUndefined
6
+ } from "./shared.js";
7
+ export class SendGridProvider {
8
+ name = "sendgrid";
9
+ apiKey;
10
+ constructor(config) {
11
+ if (!config.apiKey) {
12
+ throw new Error("[nuxt-email] SendGridProvider requires `apiKey`.");
13
+ }
14
+ this.apiKey = config.apiKey;
15
+ }
16
+ async send(payload) {
17
+ const start = Date.now();
18
+ try {
19
+ const personalization = {
20
+ to: payload.to.map((e) => ({ email: e }))
21
+ };
22
+ if (payload.cc?.length)
23
+ personalization.cc = payload.cc.map((e) => ({ email: e }));
24
+ if (payload.bcc?.length)
25
+ personalization.bcc = payload.bcc.map((e) => ({ email: e }));
26
+ if (payload.scheduledAt) {
27
+ personalization.send_at = Math.floor(
28
+ payload.scheduledAt.getTime() / 1e3
29
+ );
30
+ }
31
+ const content = [];
32
+ if (payload.text)
33
+ content.push({ type: "text/plain", value: payload.text });
34
+ content.push({ type: "text/html", value: payload.html });
35
+ const attachments = payload.attachments?.map(
36
+ (a) => omitUndefined({
37
+ filename: a.filename,
38
+ content: toBase64(a.content),
39
+ type: a.contentType,
40
+ disposition: a.disposition,
41
+ content_id: a.cid
42
+ })
43
+ );
44
+ const body = omitUndefined({
45
+ personalizations: [personalization],
46
+ from: parseAddress(payload.from),
47
+ reply_to: payload.replyTo ? parseAddress(payload.replyTo) : void 0,
48
+ subject: payload.subject,
49
+ content,
50
+ attachments,
51
+ headers: payload.headers,
52
+ custom_args: payload.tags
53
+ });
54
+ const res = await $fetch.raw(
55
+ "https://api.sendgrid.com/v3/mail/send",
56
+ {
57
+ method: "POST",
58
+ headers: {
59
+ Authorization: `Bearer ${this.apiKey}`,
60
+ "Content-Type": "application/json"
61
+ },
62
+ body
63
+ }
64
+ );
65
+ if (res.status !== 202) {
66
+ return {
67
+ success: false,
68
+ error: `[nuxt-email] SendGrid API error (${res.status}): unexpected status`,
69
+ provider: this.name,
70
+ duration: Date.now() - start
71
+ };
72
+ }
73
+ const messageId = res.headers.get("x-message-id") ?? void 0;
74
+ return {
75
+ success: true,
76
+ messageId,
77
+ provider: this.name,
78
+ duration: Date.now() - start
79
+ };
80
+ } catch (error) {
81
+ return {
82
+ success: false,
83
+ error: fetchErrorMessage("SendGrid", error),
84
+ provider: this.name,
85
+ duration: Date.now() - start
86
+ };
87
+ }
88
+ }
89
+ async verify() {
90
+ try {
91
+ await $fetch("https://api.sendgrid.com/v3/scopes", {
92
+ headers: { Authorization: `Bearer ${this.apiKey}` }
93
+ });
94
+ return true;
95
+ } catch {
96
+ return false;
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,7 @@
1
+ export declare function toBase64(content: string | Buffer): string;
2
+ export declare function parseAddress(addr: string): {
3
+ email: string;
4
+ name?: string;
5
+ };
6
+ export declare function fetchErrorMessage(provider: string, error: unknown): string;
7
+ export declare function omitUndefined<T extends Record<string, unknown>>(obj: T): Partial<T>;
@@ -0,0 +1,29 @@
1
+ export function toBase64(content) {
2
+ if (Buffer.isBuffer(content)) return content.toString("base64");
3
+ return Buffer.from(content).toString("base64");
4
+ }
5
+ export function parseAddress(addr) {
6
+ const match = addr.match(/^(.+?)\s*<([^>]+)>$/);
7
+ if (match) return { name: match[1].trim(), email: match[2].trim() };
8
+ return { email: addr.trim() };
9
+ }
10
+ export function fetchErrorMessage(provider, error) {
11
+ if (error && typeof error === "object") {
12
+ const e = error;
13
+ const status = typeof e.status === "number" ? e.status : void 0;
14
+ const data = e.data;
15
+ const message = typeof data?.message === "string" && data.message || typeof data?.Message === "string" && data.Message || typeof e.message === "string" && e.message || "Unknown error";
16
+ if (status !== void 0) {
17
+ return `[nuxt-email] ${provider} API error (${status}): ${message}`;
18
+ }
19
+ return `[nuxt-email] ${provider} error: ${message}`;
20
+ }
21
+ return `[nuxt-email] ${provider} error: ${String(error)}`;
22
+ }
23
+ export function omitUndefined(obj) {
24
+ const result = {};
25
+ for (const key of Object.keys(obj)) {
26
+ if (obj[key] !== void 0) result[key] = obj[key];
27
+ }
28
+ return result;
29
+ }
@@ -0,0 +1,8 @@
1
+ import type { EmailProvider, EmailRuntimeConfig, NormalizedPayload, EmailResponse } from '../../../types/index.js.js';
2
+ export declare class SmtpProvider implements EmailProvider {
3
+ name: string;
4
+ private readonly config;
5
+ constructor(config: EmailRuntimeConfig);
6
+ send(payload: NormalizedPayload): Promise<EmailResponse>;
7
+ verify(): Promise<boolean>;
8
+ }
@@ -0,0 +1,85 @@
1
+ export class SmtpProvider {
2
+ name = "smtp";
3
+ config;
4
+ constructor(config) {
5
+ if (!config.smtpHost) {
6
+ throw new Error("[nuxt-email] SmtpProvider requires `smtp.host`.");
7
+ }
8
+ this.config = config;
9
+ }
10
+ async send(payload) {
11
+ const start = Date.now();
12
+ try {
13
+ let nodemailer;
14
+ try {
15
+ nodemailer = await import("nodemailer");
16
+ } catch {
17
+ return {
18
+ success: false,
19
+ error: "[nuxt-email] SMTP requires the optional peer dep `nodemailer`. Run `npm i nodemailer`.",
20
+ provider: this.name,
21
+ duration: Date.now() - start
22
+ };
23
+ }
24
+ const { smtpHost, smtpPort, smtpSecure, smtpUser, smtpPass } = this.config;
25
+ const transporter = nodemailer.createTransport({
26
+ host: smtpHost,
27
+ port: smtpPort,
28
+ secure: smtpSecure || smtpPort === 465,
29
+ auth: smtpUser ? { user: smtpUser, pass: smtpPass } : void 0
30
+ });
31
+ const attachments = payload.attachments?.map((a) => ({
32
+ filename: a.filename,
33
+ content: a.content,
34
+ contentType: a.contentType,
35
+ cid: a.cid
36
+ }));
37
+ const info = await transporter.sendMail({
38
+ from: payload.from,
39
+ to: payload.to,
40
+ cc: payload.cc,
41
+ bcc: payload.bcc,
42
+ replyTo: payload.replyTo,
43
+ subject: payload.subject,
44
+ html: payload.html,
45
+ text: payload.text,
46
+ headers: payload.headers,
47
+ attachments
48
+ });
49
+ return {
50
+ success: true,
51
+ messageId: info.messageId,
52
+ provider: this.name,
53
+ duration: Date.now() - start
54
+ };
55
+ } catch (error) {
56
+ return {
57
+ success: false,
58
+ error: `[nuxt-email] SMTP error: ${error instanceof Error ? error.message : String(error)}`,
59
+ provider: this.name,
60
+ duration: Date.now() - start
61
+ };
62
+ }
63
+ }
64
+ async verify() {
65
+ try {
66
+ let nodemailer;
67
+ try {
68
+ nodemailer = await import("nodemailer");
69
+ } catch {
70
+ return false;
71
+ }
72
+ const { smtpHost, smtpPort, smtpSecure, smtpUser, smtpPass } = this.config;
73
+ const transporter = nodemailer.createTransport({
74
+ host: smtpHost,
75
+ port: smtpPort,
76
+ secure: smtpSecure || smtpPort === 465,
77
+ auth: smtpUser ? { user: smtpUser, pass: smtpPass } : void 0
78
+ });
79
+ await transporter.verify();
80
+ return true;
81
+ } catch {
82
+ return false;
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,5 @@
1
+ import type { Component } from 'vue';
2
+ export declare function renderEmailTemplate(component: Component, props?: Record<string, unknown>): Promise<{
3
+ html: string;
4
+ text: string;
5
+ }>;
@@ -0,0 +1,10 @@
1
+ import { createSSRApp } from "@vue/runtime-dom";
2
+ import { renderToString } from "@vue/server-renderer";
3
+ import juice from "juice";
4
+ export async function renderEmailTemplate(component, props = {}) {
5
+ const app = createSSRApp(component, props);
6
+ const rendered = await renderToString(app);
7
+ const html = juice(rendered);
8
+ const text = rendered.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
9
+ return { html, text };
10
+ }
@@ -0,0 +1,4 @@
1
+ import type { Component } from 'vue';
2
+ export declare function getEmailTemplate(name: string): Component;
3
+ export declare function getPreviewProps(name: string): Record<string, unknown>;
4
+ export declare function listTemplates(): string[];
@@ -0,0 +1,17 @@
1
+ import { templates, previewProps } from "#nuxt-email/templates";
2
+ export function getEmailTemplate(name) {
3
+ const component = templates[name];
4
+ if (!component) {
5
+ const available = Object.keys(templates).join(", ") || "none";
6
+ throw new Error(
7
+ `[nuxt-email] Template "${name}" not found. Available: ${available}`
8
+ );
9
+ }
10
+ return component;
11
+ }
12
+ export function getPreviewProps(name) {
13
+ return previewProps[name] ?? {};
14
+ }
15
+ export function listTemplates() {
16
+ return Object.keys(templates);
17
+ }
@@ -0,0 +1,6 @@
1
+ declare module '#nuxt-email/templates' {
2
+ import type { Component } from 'vue'
3
+
4
+ export const templates: Record<string, Component>
5
+ export const previewProps: Record<string, Record<string, unknown>>
6
+ }
@@ -0,0 +1,110 @@
1
+ export interface EmailModuleOptions {
2
+ /** Email provider. Default: 'console' (logs to terminal) */
3
+ provider: 'resend' | 'sendgrid' | 'postmark' | 'smtp' | 'console';
4
+ /** Default sender address: "Name <email>" or "email" */
5
+ from?: string;
6
+ /** Provider API key (prefer env vars via runtimeConfig) */
7
+ apiKey?: string;
8
+ smtp?: SmtpConfig;
9
+ /** Per-provider credentials. Each entry overrides the top-level `apiKey`/`smtp`/`from` for that provider. */
10
+ providers?: Partial<Record<EmailModuleOptions['provider'], ProviderOptions>>;
11
+ /** Directory for Vue email templates relative to project root. Default: 'server/emails' */
12
+ templateDir?: string;
13
+ /** Enable preview route in dev mode. Default: true */
14
+ preview?: boolean;
15
+ /** Number of retry attempts on transient failures. Default: 2 */
16
+ retries?: number;
17
+ /** Delay between retries in ms. Default: 1000 */
18
+ retryDelay?: number;
19
+ }
20
+ export interface SmtpConfig {
21
+ host: string;
22
+ port?: number;
23
+ user?: string;
24
+ pass?: string;
25
+ secure?: boolean;
26
+ }
27
+ /** Credentials for a single provider, overriding the top-level defaults. */
28
+ export interface ProviderOptions {
29
+ apiKey?: string;
30
+ from?: string;
31
+ smtp?: SmtpConfig;
32
+ }
33
+ /** Flat per-provider overrides stored in runtime config. */
34
+ export interface ProviderRuntimeOptions {
35
+ apiKey?: string;
36
+ from?: string;
37
+ smtpHost?: string;
38
+ smtpPort?: number;
39
+ smtpUser?: string;
40
+ smtpPass?: string;
41
+ smtpSecure?: boolean;
42
+ }
43
+ /** Stored in runtimeConfig._email. Private, never sent to the client. */
44
+ export interface EmailRuntimeConfig {
45
+ provider: string;
46
+ apiKey: string;
47
+ from: string;
48
+ smtpHost: string;
49
+ smtpPort: number;
50
+ smtpUser: string;
51
+ smtpPass: string;
52
+ smtpSecure: boolean;
53
+ retries: number;
54
+ retryDelay: number;
55
+ providers?: Record<string, ProviderRuntimeOptions>;
56
+ }
57
+ export interface EmailPayload {
58
+ to: string | string[];
59
+ subject: string;
60
+ /** Mutually exclusive with `template` */
61
+ html?: string;
62
+ text?: string;
63
+ template?: string;
64
+ props?: Record<string, unknown>;
65
+ from?: string;
66
+ cc?: string | string[];
67
+ bcc?: string | string[];
68
+ replyTo?: string;
69
+ attachments?: EmailAttachment[];
70
+ headers?: Record<string, string>;
71
+ /** Provider must support scheduled sends */
72
+ scheduledAt?: Date;
73
+ /** Provider-dependent */
74
+ tags?: Record<string, string>;
75
+ }
76
+ export interface EmailAttachment {
77
+ filename: string;
78
+ content: string | Buffer;
79
+ contentType?: string;
80
+ /** 'attachment' | 'inline' */
81
+ disposition?: string;
82
+ /** Content-ID for inline images */
83
+ cid?: string;
84
+ }
85
+ export interface EmailResponse {
86
+ success: boolean;
87
+ messageId?: string;
88
+ error?: string;
89
+ provider: string;
90
+ duration: number;
91
+ }
92
+ export interface EmailProvider {
93
+ name: string;
94
+ send(payload: NormalizedPayload): Promise<EmailResponse>;
95
+ verify?(): Promise<boolean>;
96
+ }
97
+ export interface NormalizedPayload {
98
+ from: string;
99
+ to: string[];
100
+ subject: string;
101
+ html: string;
102
+ text?: string;
103
+ cc?: string[];
104
+ bcc?: string[];
105
+ replyTo?: string;
106
+ attachments?: EmailAttachment[];
107
+ headers?: Record<string, string>;
108
+ scheduledAt?: Date;
109
+ tags?: Record<string, string>;
110
+ }
File without changes
@@ -0,0 +1,9 @@
1
+ import type { NuxtModule } from '@nuxt/schema'
2
+
3
+ import type { default as Module } from './module.mjs'
4
+
5
+ export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<O> : Record<string, any>
6
+
7
+ export { type EmailAttachment, type EmailModuleOptions, type EmailPayload, type EmailProvider, type EmailResponse, type NormalizedPayload } from '../dist/runtime/types/index.js'
8
+
9
+ export { default } from './module.mjs'