sently 0.4.6 → 0.4.7
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 +35 -0
- package/README.md +94 -41
- package/dist/adapters/bun.js +2 -183
- package/dist/adapters/bun.js.map +2 -2
- package/dist/adapters/cf.js +2 -77
- package/dist/adapters/cf.js.map +2 -2
- package/dist/adapters/deno.js +2 -72
- package/dist/adapters/deno.js.map +2 -2
- package/dist/adapters/node.js +2 -180
- package/dist/adapters/node.js.map +2 -2
- package/dist/auth/oauth2.js +2 -13
- package/dist/auth/oauth2.js.map +1 -1
- package/dist/chunk-2kcwa9gt.js +4 -0
- package/dist/chunk-2kcwa9gt.js.map +11 -0
- package/dist/chunk-2t6hjer3.js +5 -0
- package/dist/chunk-2t6hjer3.js.map +10 -0
- package/dist/chunk-6yggz45h.js +5 -0
- package/dist/{chunk-794hc3m4.js.map → chunk-6yggz45h.js.map} +2 -2
- package/dist/chunk-dgkh77yp.js +4 -0
- package/dist/{chunk-ym3zzv8b.js.map → chunk-dgkh77yp.js.map} +2 -2
- package/dist/chunk-jfs80vhp.js +3 -0
- package/dist/{chunk-7fqv71z1.js.map → chunk-jfs80vhp.js.map} +2 -2
- package/dist/chunk-sqn04kae.js +4 -0
- package/dist/{chunk-v0bahtg2.js.map → chunk-sqn04kae.js.map} +1 -1
- package/dist/chunk-va2awz12.js +4 -0
- package/dist/{chunk-f4c9ttmr.js.map → chunk-va2awz12.js.map} +2 -2
- package/dist/chunk-wgtbr6ge.js +13 -0
- package/dist/{chunk-tymfm441.js.map → chunk-wgtbr6ge.js.map} +2 -2
- package/dist/core/smtp.js +2 -31
- package/dist/core/smtp.js.map +1 -1
- package/dist/core/types.d.ts +7 -0
- package/dist/detect.d.ts +2 -0
- package/dist/detect.js +2 -180
- package/dist/detect.js.map +4 -5
- package/dist/dkim.d.ts +21 -0
- package/dist/dkim.js +9 -0
- package/dist/dkim.js.map +10 -0
- package/dist/index.d.ts +74 -16
- package/dist/index.js +85 -14
- package/dist/mailer.d.ts +16 -0
- package/dist/mailer.js +3 -0
- package/dist/mailer.js.map +9 -0
- package/dist/plugins/template.js +2 -28
- package/dist/plugins/template.js.map +2 -2
- package/dist/pool/pool.js +2 -16
- package/dist/pool/pool.js.map +5 -3
- package/dist/transports/brevo.js +2 -115
- package/dist/transports/brevo.js.map +2 -2
- package/dist/transports/mailgun.js +2 -119
- package/dist/transports/mailgun.js.map +2 -2
- package/dist/transports/postmark.js +2 -113
- package/dist/transports/postmark.js.map +2 -2
- package/dist/transports/preview.js +2 -72
- package/dist/transports/preview.js.map +2 -2
- package/dist/transports/resend.js +2 -109
- package/dist/transports/resend.js.map +2 -2
- package/dist/transports/retry.js +2 -78
- package/dist/transports/retry.js.map +2 -2
- package/dist/transports/sendgrid.js +2 -132
- package/dist/transports/sendgrid.js.map +2 -2
- package/dist/transports/ses.js +5 -251
- package/dist/transports/ses.js.map +2 -2
- package/dist/transports/smtp.js +2 -26
- package/dist/transports/smtp.js.map +1 -1
- package/package.json +17 -6
- package/dist/chunk-794hc3m4.js +0 -105
- package/dist/chunk-7fqv71z1.js +0 -251
- package/dist/chunk-f4c9ttmr.js +0 -154
- package/dist/chunk-mp5c9bfd.js +0 -270
- package/dist/chunk-mp5c9bfd.js.map +0 -11
- package/dist/chunk-tymfm441.js +0 -405
- package/dist/chunk-v0bahtg2.js +0 -6
- package/dist/chunk-x3szga4k.js +0 -367
- package/dist/chunk-x3szga4k.js.map +0 -11
- package/dist/chunk-ym3zzv8b.js +0 -74
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * @module\n * Brevo (formerly Sendinblue) HTTP transport for sently.\n *\n * @example\n * ```ts\n * import { BrevoTransport } from \"sently/transports/brevo\";\n * import { createMailer } from \"sently\";\n *\n * const mailer = await createMailer({\n * transport: new BrevoTransport({ apiKey: \"xkeysib-...\" }),\n * });\n * ```\n */\nimport { extractEmails, parseAddresses } from \"../core/address.js\";\nimport { encodeBase64 } from \"../core/base64.js\";\nimport type {\n BrevoConfig,\n MailOptions,\n SendResult,\n Transport,\n VerifyResult,\n} from \"../core/types.js\";\nimport { resolveAttachments } from \"./resolve-attachments.js\";\n\n/** Error thrown when the Brevo API returns a non-success response. */\nexport class BrevoError extends Error {\n /** Creates a Brevo API error with status code and error code. */\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly code: string,\n ) {\n super(message);\n this.name = \"BrevoError\";\n }\n}\n\nfunction toAddressObjects(input: MailOptions[\"to\"]): Array<{ email: string; name?: string }> {\n return parseAddresses(input).map((addr) => ({\n email: addr.address,\n ...(addr.name ? { name: addr.name } : {}),\n }));\n}\n\n/**\n * Brevo HTTP API transport.\n */\nexport class BrevoTransport implements Transport {\n /** Brevo API key used for Authorization. */\n private readonly apiKey: string;\n\n /** Creates a Brevo transport with the given API key. */\n constructor(config: BrevoConfig) {\n this.apiKey = config.apiKey;\n }\n\n /** Sends an email via the Brevo HTTP API. */\n async send(options: MailOptions): Promise<SendResult> {\n const attachments = await resolveAttachments(options.attachments);\n const from = parseAddresses(options.from)[0];\n\n const body: Record<string, unknown> = {\n sender: from\n ? { email: from.address, ...(from.name ? { name: from.name } : {}) }\n : { email: \"\" },\n to: toAddressObjects(options.to),\n subject: options.subject,\n ...(options.cc ? { cc: toAddressObjects(options.cc) } : {}),\n ...(options.bcc ? { bcc: toAddressObjects(options.bcc) } : {}),\n ...(options.replyTo\n ? {\n replyTo: (() => {\n const reply = parseAddresses(options.replyTo as MailOptions[\"to\"])[0];\n return reply\n ? { email: reply.address, ...(reply.name ? { name: reply.name } : {}) }\n : undefined;\n })(),\n }\n : {}),\n ...(options.html ? { htmlContent: options.html } : {}),\n ...(options.text ? { textContent: options.text } : {}),\n ...(attachments.length > 0\n ? {\n attachment: attachments.map((att) => ({\n name: att.filename,\n content:\n att.content instanceof Uint8Array\n ? encodeBase64(att.content).replace(/\\r\\n/g, \"\")\n : att.content,\n })),\n }\n : {}),\n };\n\n const response = await fetch(\"https://api.brevo.com/v3/smtp/email\", {\n method: \"POST\",\n headers: {\n \"api-key\": this.apiKey,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n const payload = (await response.json()) as {\n messageId?: string;\n message?: string;\n code?: string;\n };\n\n if (!response.ok) {\n throw new BrevoError(\n payload.message ?? \"Brevo API error\",\n response.status,\n payload.code ?? \"\",\n );\n }\n\n const toEmails = extractEmails(options.to);\n return {\n messageId: payload.messageId ?? \"\",\n accepted: toEmails,\n rejected: [],\n response: payload.messageId ?? \"sent\",\n envelope: {\n from: from?.address ?? \"\",\n to: toEmails,\n },\n };\n }\n\n /** Verifies the Brevo API key by fetching account info. */\n async verify(): Promise<VerifyResult> {\n try {\n const response = await fetch(\"https://api.brevo.com/v3/account\", {\n headers: {\n \"api-key\": this.apiKey,\n },\n });\n\n const payload = (await response.json()) as { companyName?: string; message?: string };\n\n if (!response.ok) {\n return {\n ok: false,\n provider: \"brevo\",\n message: payload.message ?? `HTTP ${response.status}`,\n };\n }\n\n return {\n ok: true,\n provider: \"brevo\",\n ...(payload.companyName ? { message: payload.companyName } : {}),\n };\n } catch (err) {\n return {\n ok: false,\n provider: \"brevo\",\n message: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "uIA0BO,CAAM,KAAmB,KAAM,CAIlB,WACA,KAHlB,WAAW,CACT,EACgB,EACA,EAChB,CACA,MAAM,CAAO,EAHG,kBACA,YAGhB,KAAK,KAAO,aAEhB,CAEA,SAAS,CAAgB,CAAC,EAAmE,CAC3F,OAAO,EAAe,CAAK,EAAE,IAAI,CAAC,KAAU,CAC1C,MAAO,EAAK,WACR,EAAK,KAAO,CAAE,KAAM,EAAK,IAAK,EAAI,CAAC,CACzC,EAAE,EAMG,MAAM,CAAoC,CAE9B,OAGjB,WAAW,CAAC,EAAqB,CAC/B,KAAK,OAAS,EAAO,YAIjB,KAAI,CAAC,EAA2C,CACpD,IAAM,EAAc,MAAM,EAAmB,EAAQ,WAAW,EAC1D,EAAO,EAAe,EAAQ,IAAI,EAAE,GAEpC,EAAgC,CACpC,OAAQ,EACJ,CAAE,MAAO,EAAK,WAAa,EAAK,KAAO,CAAE,KAAM,EAAK,IAAK,EAAI,CAAC,CAAG,EACjE,CAAE,MAAO,EAAG,EAChB,GAAI,EAAiB,EAAQ,EAAE,EAC/B,QAAS,EAAQ,WACb,EAAQ,GAAK,CAAE,GAAI,EAAiB,EAAQ,EAAE,CAAE,EAAI,CAAC,KACrD,EAAQ,IAAM,CAAE,IAAK,EAAiB,EAAQ,GAAG,CAAE,EAAI,CAAC,KACxD,EAAQ,QACR,CACE,SAAU,IAAM,CACd,IAAM,EAAQ,EAAe,EAAQ,OAA4B,EAAE,GACnE,OAAO,EACH,CAAE,MAAO,EAAM,WAAa,EAAM,KAAO,CAAE,KAAM,EAAM,IAAK,EAAI,CAAC,CAAG,EACpE,SACH,CACL,EACA,CAAC,KACD,EAAQ,KAAO,CAAE,YAAa,EAAQ,IAAK,EAAI,CAAC,KAChD,EAAQ,KAAO,CAAE,YAAa,EAAQ,IAAK,EAAI,CAAC,KAChD,EAAY,OAAS,EACrB,CACE,WAAY,EAAY,IAAI,CAAC,KAAS,CACpC,KAAM,EAAI,SACV,QACE,EAAI,mBAAmB,WACnB,EAAa,EAAI,OAAO,EAAE,QAAQ,QAAS,EAAE,EAC7C,EAAI,OACZ,EAAE,CACJ,EACA,CAAC,CACP,EAEM,EAAW,MAAM,MAAM,sCAAuC,CAClE,OAAQ,OACR,QAAS,CACP,UAAW,KAAK,OAChB,eAAgB,kBAClB,EACA,KAAM,KAAK,UAAU,CAAI,CAC3B,CAAC,EAEK,EAAW,MAAM,EAAS,KAAK,EAMrC,GAAI,CAAC,EAAS,GACZ,MAAM,IAAI,EACR,EAAQ,SAAW,kBACnB,EAAS,OACT,EAAQ,MAAQ,EAClB,EAGF,IAAM,EAAW,EAAc,EAAQ,EAAE,EACzC,MAAO,CACL,UAAW,EAAQ,WAAa,GAChC,SAAU,EACV,SAAU,CAAC,EACX,SAAU,EAAQ,WAAa,OAC/B,SAAU,CACR,KAAM,GAAM,SAAW,GACvB,GAAI,CACN,CACF,OAII,OAAM,EAA0B,CACpC,GAAI,CACF,IAAM,EAAW,MAAM,MAAM,mCAAoC,CAC/D,QAAS,CACP,UAAW,KAAK,MAClB,CACF,CAAC,EAEK,EAAW,MAAM,EAAS,KAAK,EAErC,GAAI,CAAC,EAAS,GACZ,MAAO,CACL,GAAI,GACJ,SAAU,QACV,QAAS,EAAQ,SAAW,QAAQ,EAAS,QAC/C,EAGF,MAAO,CACL,GAAI,GACJ,SAAU,WACN,EAAQ,YAAc,CAAE,QAAS,EAAQ,WAAY,EAAI,CAAC,CAChE,EACA,MAAO,EAAK,CACZ,MAAO,CACL,GAAI,GACJ,SAAU,QACV,QAAS,aAAe,MAAQ,EAAI,QAAU,OAAO,CAAG,CAC1D,GAGN",
|
|
8
|
+
"debugId": "57FBF679971DFBE964756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -1,120 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
extractEmails,
|
|
3
|
-
parseAddresses,
|
|
4
|
-
resolveAttachments,
|
|
5
|
-
toMIMEHeader
|
|
6
|
-
} from "../chunk-f4c9ttmr.js";
|
|
7
|
-
import {
|
|
8
|
-
encodeBase64
|
|
9
|
-
} from "../chunk-794hc3m4.js";
|
|
10
|
-
import"../chunk-v0bahtg2.js";
|
|
1
|
+
import{l as D,m as F,n as O,p as Q}from"../chunk-va2awz12.js";import{E as L}from"../chunk-6yggz45h.js";import"../chunk-sqn04kae.js";class R extends Error{statusCode;apiError;constructor(q,C,G){super(q);this.statusCode=C;this.apiError=G;this.name="MailgunError"}}class X{apiKey;domain;baseUrl;constructor(q){this.apiKey=q.apiKey,this.domain=q.domain,this.baseUrl=q.region==="eu"?"https://api.eu.mailgun.net":"https://api.mailgun.net"}async send(q){let C=await Q(q.attachments),G=D(q.from)[0],w=new FormData;if(w.append("from",G?F(G):""),w.append("to",D(q.to).map(F).join(", ")),q.cc)w.append("cc",D(q.cc).map(F).join(", "));if(q.bcc)w.append("bcc",D(q.bcc).map(F).join(", "));if(w.append("subject",q.subject),q.text)w.append("text",q.text);if(q.html)w.append("html",q.html);if(q.replyTo){let z=D(q.replyTo)[0];if(z)w.append("h:Reply-To",F(z))}for(let z of C){let U=z.content instanceof Uint8Array?z.content:new TextEncoder().encode(String(z.content??"")),W=new Blob([new Uint8Array(U)],{type:z.contentType??"application/octet-stream"});w.append("attachment",W,z.filename)}let S=L(`api:${this.apiKey}`).replace(/\r\n/g,""),K=await fetch(`${this.baseUrl}/v3/${this.domain}/messages`,{method:"POST",headers:{Authorization:`Basic ${S}`},body:w}),J=await K.json();if(!K.ok)throw new R(J.message??"Mailgun API error",K.status,J);let N=O(q.to);return{messageId:J.id??"",accepted:N,rejected:[],response:J.message??"queued",envelope:{from:G?.address??"",to:N}}}async verify(){try{let q=L(`api:${this.apiKey}`).replace(/\r\n/g,""),C=await fetch(`${this.baseUrl}/v3/domains`,{headers:{Authorization:`Basic ${q}`}});if(!C.ok)return{ok:!1,provider:"mailgun",message:(await C.json().catch(()=>({}))).message??`HTTP ${C.status}`};return{ok:!0,provider:"mailgun",message:"API key is valid"}}catch(q){return{ok:!1,provider:"mailgun",message:q instanceof Error?q.message:String(q)}}}}export{X as MailgunTransport,R as MailgunError};
|
|
11
2
|
|
|
12
|
-
|
|
13
|
-
class MailgunError extends Error {
|
|
14
|
-
statusCode;
|
|
15
|
-
apiError;
|
|
16
|
-
constructor(message, statusCode, apiError) {
|
|
17
|
-
super(message);
|
|
18
|
-
this.statusCode = statusCode;
|
|
19
|
-
this.apiError = apiError;
|
|
20
|
-
this.name = "MailgunError";
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
class MailgunTransport {
|
|
25
|
-
apiKey;
|
|
26
|
-
domain;
|
|
27
|
-
baseUrl;
|
|
28
|
-
constructor(config) {
|
|
29
|
-
this.apiKey = config.apiKey;
|
|
30
|
-
this.domain = config.domain;
|
|
31
|
-
this.baseUrl = config.region === "eu" ? "https://api.eu.mailgun.net" : "https://api.mailgun.net";
|
|
32
|
-
}
|
|
33
|
-
async send(options) {
|
|
34
|
-
const attachments = await resolveAttachments(options.attachments);
|
|
35
|
-
const from = parseAddresses(options.from)[0];
|
|
36
|
-
const form = new FormData;
|
|
37
|
-
form.append("from", from ? toMIMEHeader(from) : "");
|
|
38
|
-
form.append("to", parseAddresses(options.to).map(toMIMEHeader).join(", "));
|
|
39
|
-
if (options.cc) {
|
|
40
|
-
form.append("cc", parseAddresses(options.cc).map(toMIMEHeader).join(", "));
|
|
41
|
-
}
|
|
42
|
-
if (options.bcc) {
|
|
43
|
-
form.append("bcc", parseAddresses(options.bcc).map(toMIMEHeader).join(", "));
|
|
44
|
-
}
|
|
45
|
-
form.append("subject", options.subject);
|
|
46
|
-
if (options.text) {
|
|
47
|
-
form.append("text", options.text);
|
|
48
|
-
}
|
|
49
|
-
if (options.html) {
|
|
50
|
-
form.append("html", options.html);
|
|
51
|
-
}
|
|
52
|
-
if (options.replyTo) {
|
|
53
|
-
const replyTo = parseAddresses(options.replyTo)[0];
|
|
54
|
-
if (replyTo) {
|
|
55
|
-
form.append("h:Reply-To", toMIMEHeader(replyTo));
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
for (const attachment of attachments) {
|
|
59
|
-
const content = attachment.content instanceof Uint8Array ? attachment.content : new TextEncoder().encode(String(attachment.content ?? ""));
|
|
60
|
-
const blob = new Blob([new Uint8Array(content)], {
|
|
61
|
-
type: attachment.contentType ?? "application/octet-stream"
|
|
62
|
-
});
|
|
63
|
-
form.append("attachment", blob, attachment.filename);
|
|
64
|
-
}
|
|
65
|
-
const auth = encodeBase64(`api:${this.apiKey}`).replace(/\r\n/g, "");
|
|
66
|
-
const response = await fetch(`${this.baseUrl}/v3/${this.domain}/messages`, {
|
|
67
|
-
method: "POST",
|
|
68
|
-
headers: {
|
|
69
|
-
Authorization: `Basic ${auth}`
|
|
70
|
-
},
|
|
71
|
-
body: form
|
|
72
|
-
});
|
|
73
|
-
const payload = await response.json();
|
|
74
|
-
if (!response.ok) {
|
|
75
|
-
throw new MailgunError(payload.message ?? "Mailgun API error", response.status, payload);
|
|
76
|
-
}
|
|
77
|
-
const toEmails = extractEmails(options.to);
|
|
78
|
-
return {
|
|
79
|
-
messageId: payload.id ?? "",
|
|
80
|
-
accepted: toEmails,
|
|
81
|
-
rejected: [],
|
|
82
|
-
response: payload.message ?? "queued",
|
|
83
|
-
envelope: {
|
|
84
|
-
from: from?.address ?? "",
|
|
85
|
-
to: toEmails
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
async verify() {
|
|
90
|
-
try {
|
|
91
|
-
const auth = encodeBase64(`api:${this.apiKey}`).replace(/\r\n/g, "");
|
|
92
|
-
const response = await fetch(`${this.baseUrl}/v3/domains`, {
|
|
93
|
-
headers: {
|
|
94
|
-
Authorization: `Basic ${auth}`
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
if (!response.ok) {
|
|
98
|
-
const payload = await response.json().catch(() => ({}));
|
|
99
|
-
return {
|
|
100
|
-
ok: false,
|
|
101
|
-
provider: "mailgun",
|
|
102
|
-
message: payload.message ?? `HTTP ${response.status}`
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
return { ok: true, provider: "mailgun", message: "API key is valid" };
|
|
106
|
-
} catch (err) {
|
|
107
|
-
return {
|
|
108
|
-
ok: false,
|
|
109
|
-
provider: "mailgun",
|
|
110
|
-
message: err instanceof Error ? err.message : String(err)
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
export {
|
|
116
|
-
MailgunTransport,
|
|
117
|
-
MailgunError
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
//# debugId=0BB5E6A11ACE98B264756E2164756E21
|
|
3
|
+
//# debugId=AA6A34EE20A85D7164756E2164756E21
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * @module\n * Mailgun HTTP transport for sently.\n * Uses the Mailgun Messages API v3 with multipart/form-data.\n *\n * @example\n * ```ts\n * import { MailgunTransport } from \"sently/transports/mailgun\";\n * import { createMailer } from \"sently\";\n *\n * const mailer = await createMailer({\n * transport: new MailgunTransport({\n * apiKey: \"key-...\",\n * domain: \"mg.example.com\",\n * }),\n * });\n * ```\n */\nimport { extractEmails, parseAddresses, toMIMEHeader } from \"../core/address.js\";\nimport { encodeBase64 } from \"../core/base64.js\";\nimport type {\n MailgunConfig,\n MailOptions,\n SendResult,\n Transport,\n VerifyResult,\n} from \"../core/types.js\";\nimport { resolveAttachments } from \"./resolve-attachments.js\";\n\n/** Error thrown when the Mailgun API returns a non-success response. */\nexport class MailgunError extends Error {\n /** Creates a Mailgun API error with status code and response payload. */\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly apiError: unknown,\n ) {\n super(message);\n this.name = \"MailgunError\";\n }\n}\n\n/**\n * Mailgun HTTP API transport (multipart/form-data).\n */\nexport class MailgunTransport implements Transport {\n /** Mailgun API key for basic authentication. */\n private readonly apiKey: string;\n /** Mailgun sending domain. */\n private readonly domain: string;\n /** Mailgun API base URL (US or EU region). */\n private readonly baseUrl: string;\n\n /** Creates a Mailgun transport with the given API key and domain. */\n constructor(config: MailgunConfig) {\n this.apiKey = config.apiKey;\n this.domain = config.domain;\n this.baseUrl =\n config.region === \"eu\" ? \"https://api.eu.mailgun.net\" : \"https://api.mailgun.net\";\n }\n\n /** Sends an email via the Mailgun Messages API. */\n async send(options: MailOptions): Promise<SendResult> {\n const attachments = await resolveAttachments(options.attachments);\n const from = parseAddresses(options.from)[0];\n const form = new FormData();\n\n form.append(\"from\", from ? toMIMEHeader(from) : \"\");\n form.append(\"to\", parseAddresses(options.to).map(toMIMEHeader).join(\", \"));\n\n if (options.cc) {\n form.append(\"cc\", parseAddresses(options.cc).map(toMIMEHeader).join(\", \"));\n }\n if (options.bcc) {\n form.append(\"bcc\", parseAddresses(options.bcc).map(toMIMEHeader).join(\", \"));\n }\n\n form.append(\"subject\", options.subject);\n\n if (options.text) {\n form.append(\"text\", options.text);\n }\n if (options.html) {\n form.append(\"html\", options.html);\n }\n if (options.replyTo) {\n const replyTo = parseAddresses(options.replyTo)[0];\n if (replyTo) {\n form.append(\"h:Reply-To\", toMIMEHeader(replyTo));\n }\n }\n\n for (const attachment of attachments) {\n const content =\n attachment.content instanceof Uint8Array\n ? attachment.content\n : new TextEncoder().encode(String(attachment.content ?? \"\"));\n const blob = new Blob([new Uint8Array(content)], {\n type: attachment.contentType ?? \"application/octet-stream\",\n });\n form.append(\"attachment\", blob, attachment.filename);\n }\n\n const auth = encodeBase64(`api:${this.apiKey}`).replace(/\\r\\n/g, \"\");\n const response = await fetch(`${this.baseUrl}/v3/${this.domain}/messages`, {\n method: \"POST\",\n headers: {\n Authorization: `Basic ${auth}`,\n },\n body: form,\n });\n\n const payload = (await response.json()) as { id?: string; message?: string };\n\n if (!response.ok) {\n throw new MailgunError(payload.message ?? \"Mailgun API error\", response.status, payload);\n }\n\n const toEmails = extractEmails(options.to);\n return {\n messageId: payload.id ?? \"\",\n accepted: toEmails,\n rejected: [],\n response: payload.message ?? \"queued\",\n envelope: {\n from: from?.address ?? \"\",\n to: toEmails,\n },\n };\n }\n\n /** Verifies the Mailgun API key by listing domains. */\n async verify(): Promise<VerifyResult> {\n try {\n const auth = encodeBase64(`api:${this.apiKey}`).replace(/\\r\\n/g, \"\");\n const response = await fetch(`${this.baseUrl}/v3/domains`, {\n headers: {\n Authorization: `Basic ${auth}`,\n },\n });\n\n if (!response.ok) {\n const payload = (await response.json().catch(() => ({}))) as { message?: string };\n return {\n ok: false,\n provider: \"mailgun\",\n message: payload.message ?? `HTTP ${response.status}`,\n };\n }\n\n return { ok: true, provider: \"mailgun\", message: \"API key is valid\" };\n } catch (err) {\n return {\n ok: false,\n provider: \"mailgun\",\n message: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "8IA8BO,CAAM,KAAqB,KAAM,CAIpB,WACA,SAHlB,WAAW,CACT,EACgB,EACA,EAChB,CACA,MAAM,CAAO,EAHG,kBACA,gBAGhB,KAAK,KAAO,eAEhB,CAKO,MAAM,CAAsC,CAEhC,OAEA,OAEA,QAGjB,WAAW,CAAC,EAAuB,CACjC,KAAK,OAAS,EAAO,OACrB,KAAK,OAAS,EAAO,OACrB,KAAK,QACH,EAAO,SAAW,KAAO,6BAA+B,+BAItD,KAAI,CAAC,EAA2C,CACpD,IAAM,EAAc,MAAM,EAAmB,EAAQ,WAAW,EAC1D,EAAO,EAAe,EAAQ,IAAI,EAAE,GACpC,EAAO,IAAI,SAKjB,GAHA,EAAK,OAAO,OAAQ,EAAO,EAAa,CAAI,EAAI,EAAE,EAClD,EAAK,OAAO,KAAM,EAAe,EAAQ,EAAE,EAAE,IAAI,CAAY,EAAE,KAAK,IAAI,CAAC,EAErE,EAAQ,GACV,EAAK,OAAO,KAAM,EAAe,EAAQ,EAAE,EAAE,IAAI,CAAY,EAAE,KAAK,IAAI,CAAC,EAE3E,GAAI,EAAQ,IACV,EAAK,OAAO,MAAO,EAAe,EAAQ,GAAG,EAAE,IAAI,CAAY,EAAE,KAAK,IAAI,CAAC,EAK7E,GAFA,EAAK,OAAO,UAAW,EAAQ,OAAO,EAElC,EAAQ,KACV,EAAK,OAAO,OAAQ,EAAQ,IAAI,EAElC,GAAI,EAAQ,KACV,EAAK,OAAO,OAAQ,EAAQ,IAAI,EAElC,GAAI,EAAQ,QAAS,CACnB,IAAM,EAAU,EAAe,EAAQ,OAAO,EAAE,GAChD,GAAI,EACF,EAAK,OAAO,aAAc,EAAa,CAAO,CAAC,EAInD,QAAW,KAAc,EAAa,CACpC,IAAM,EACJ,EAAW,mBAAmB,WAC1B,EAAW,QACX,IAAI,YAAY,EAAE,OAAO,OAAO,EAAW,SAAW,EAAE,CAAC,EACzD,EAAO,IAAI,KAAK,CAAC,IAAI,WAAW,CAAO,CAAC,EAAG,CAC/C,KAAM,EAAW,aAAe,0BAClC,CAAC,EACD,EAAK,OAAO,aAAc,EAAM,EAAW,QAAQ,EAGrD,IAAM,EAAO,EAAa,OAAO,KAAK,QAAQ,EAAE,QAAQ,QAAS,EAAE,EAC7D,EAAW,MAAM,MAAM,GAAG,KAAK,cAAc,KAAK,kBAAmB,CACzE,OAAQ,OACR,QAAS,CACP,cAAe,SAAS,GAC1B,EACA,KAAM,CACR,CAAC,EAEK,EAAW,MAAM,EAAS,KAAK,EAErC,GAAI,CAAC,EAAS,GACZ,MAAM,IAAI,EAAa,EAAQ,SAAW,oBAAqB,EAAS,OAAQ,CAAO,EAGzF,IAAM,EAAW,EAAc,EAAQ,EAAE,EACzC,MAAO,CACL,UAAW,EAAQ,IAAM,GACzB,SAAU,EACV,SAAU,CAAC,EACX,SAAU,EAAQ,SAAW,SAC7B,SAAU,CACR,KAAM,GAAM,SAAW,GACvB,GAAI,CACN,CACF,OAII,OAAM,EAA0B,CACpC,GAAI,CACF,IAAM,EAAO,EAAa,OAAO,KAAK,QAAQ,EAAE,QAAQ,QAAS,EAAE,EAC7D,EAAW,MAAM,MAAM,GAAG,KAAK,qBAAsB,CACzD,QAAS,CACP,cAAe,SAAS,GAC1B,CACF,CAAC,EAED,GAAI,CAAC,EAAS,GAEZ,MAAO,CACL,GAAI,GACJ,SAAU,UACV,SAJe,MAAM,EAAS,KAAK,EAAE,MAAM,KAAO,CAAC,EAAE,GAIpC,SAAW,QAAQ,EAAS,QAC/C,EAGF,MAAO,CAAE,GAAI,GAAM,SAAU,UAAW,QAAS,kBAAmB,EACpE,MAAO,EAAK,CACZ,MAAO,CACL,GAAI,GACJ,SAAU,UACV,QAAS,aAAe,MAAQ,EAAI,QAAU,OAAO,CAAG,CAC1D,GAGN",
|
|
8
|
+
"debugId": "AA6A34EE20A85D7164756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -1,114 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
extractEmails,
|
|
3
|
-
parseAddresses,
|
|
4
|
-
resolveAttachments,
|
|
5
|
-
toMIMEHeader
|
|
6
|
-
} from "../chunk-f4c9ttmr.js";
|
|
7
|
-
import {
|
|
8
|
-
encodeBase64
|
|
9
|
-
} from "../chunk-794hc3m4.js";
|
|
10
|
-
import"../chunk-v0bahtg2.js";
|
|
1
|
+
import{l as C,m as D,n as F,p as O}from"../chunk-va2awz12.js";import{E as L}from"../chunk-6yggz45h.js";import"../chunk-sqn04kae.js";class Q extends Error{statusCode;apiError;constructor(q,z,G){super(q);this.statusCode=z;this.apiError=G;this.name="PostmarkError"}}class T{serverToken;constructor(q){this.serverToken=q.serverToken}async send(q){let z=await O(q.attachments),G=C(q.from)[0],R={From:G?D(G):"",To:C(q.to).map(D).join(", "),Subject:q.subject,...q.cc?{Cc:C(q.cc).map(D).join(", ")}:{},...q.bcc?{Bcc:C(q.bcc).map(D).join(", ")}:{},...q.replyTo?{ReplyTo:C(q.replyTo).map(D).join(", ")}:{},...q.text?{TextBody:q.text}:{},...q.html?{HtmlBody:q.html}:{},...q.headers?{Headers:Object.entries(q.headers).map(([w,S])=>({Name:w,Value:S}))}:{},...z.length>0?{Attachments:z.map((w)=>({Name:w.filename,Content:w.content instanceof Uint8Array?L(w.content).replace(/\r\n/g,""):w.content,ContentType:w.contentType??"application/octet-stream",...w.contentId?{ContentID:w.contentId}:{}}))}:{}},K=await fetch("https://api.postmarkapp.com/email",{method:"POST",headers:{"X-Postmark-Server-Token":this.serverToken,"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(R)}),J=await K.json();if(!K.ok)throw new Q(J.Message??"Postmark API error",K.status,J);return{messageId:J.MessageID??q.messageId??"",accepted:F(q.to),rejected:[],response:J.Message??"OK",envelope:{from:G?.address??"",to:[...F(q.to),...q.cc?F(q.cc):[],...q.bcc?F(q.bcc):[]]}}}async verify(){try{let q=await fetch("https://api.postmarkapp.com/server",{headers:{"X-Postmark-Server-Token":this.serverToken,Accept:"application/json"}}),z=await q.json();if(!q.ok)return{ok:!1,provider:"postmark",message:z.Message??`HTTP ${q.status}`};return{ok:!0,provider:"postmark",...z.Name?{message:z.Name}:{}}}catch(q){return{ok:!1,provider:"postmark",message:q instanceof Error?q.message:String(q)}}}}export{T as PostmarkTransport,Q as PostmarkError};
|
|
11
2
|
|
|
12
|
-
|
|
13
|
-
class PostmarkError extends Error {
|
|
14
|
-
statusCode;
|
|
15
|
-
apiError;
|
|
16
|
-
constructor(message, statusCode, apiError) {
|
|
17
|
-
super(message);
|
|
18
|
-
this.statusCode = statusCode;
|
|
19
|
-
this.apiError = apiError;
|
|
20
|
-
this.name = "PostmarkError";
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
class PostmarkTransport {
|
|
25
|
-
serverToken;
|
|
26
|
-
constructor(config) {
|
|
27
|
-
this.serverToken = config.serverToken;
|
|
28
|
-
}
|
|
29
|
-
async send(options) {
|
|
30
|
-
const attachments = await resolveAttachments(options.attachments);
|
|
31
|
-
const from = parseAddresses(options.from)[0];
|
|
32
|
-
const body = {
|
|
33
|
-
From: from ? toMIMEHeader(from) : "",
|
|
34
|
-
To: parseAddresses(options.to).map(toMIMEHeader).join(", "),
|
|
35
|
-
Subject: options.subject,
|
|
36
|
-
...options.cc ? { Cc: parseAddresses(options.cc).map(toMIMEHeader).join(", ") } : {},
|
|
37
|
-
...options.bcc ? { Bcc: parseAddresses(options.bcc).map(toMIMEHeader).join(", ") } : {},
|
|
38
|
-
...options.replyTo ? { ReplyTo: parseAddresses(options.replyTo).map(toMIMEHeader).join(", ") } : {},
|
|
39
|
-
...options.text ? { TextBody: options.text } : {},
|
|
40
|
-
...options.html ? { HtmlBody: options.html } : {},
|
|
41
|
-
...options.headers ? { Headers: Object.entries(options.headers).map(([Name, Value]) => ({ Name, Value })) } : {},
|
|
42
|
-
...attachments.length > 0 ? {
|
|
43
|
-
Attachments: attachments.map((att) => ({
|
|
44
|
-
Name: att.filename,
|
|
45
|
-
Content: att.content instanceof Uint8Array ? encodeBase64(att.content).replace(/\r\n/g, "") : att.content,
|
|
46
|
-
ContentType: att.contentType ?? "application/octet-stream",
|
|
47
|
-
...att.contentId ? { ContentID: att.contentId } : {}
|
|
48
|
-
}))
|
|
49
|
-
} : {}
|
|
50
|
-
};
|
|
51
|
-
const response = await fetch("https://api.postmarkapp.com/email", {
|
|
52
|
-
method: "POST",
|
|
53
|
-
headers: {
|
|
54
|
-
"X-Postmark-Server-Token": this.serverToken,
|
|
55
|
-
"Content-Type": "application/json",
|
|
56
|
-
Accept: "application/json"
|
|
57
|
-
},
|
|
58
|
-
body: JSON.stringify(body)
|
|
59
|
-
});
|
|
60
|
-
const payload = await response.json();
|
|
61
|
-
if (!response.ok) {
|
|
62
|
-
throw new PostmarkError(payload.Message ?? "Postmark API error", response.status, payload);
|
|
63
|
-
}
|
|
64
|
-
return {
|
|
65
|
-
messageId: payload.MessageID ?? options.messageId ?? "",
|
|
66
|
-
accepted: extractEmails(options.to),
|
|
67
|
-
rejected: [],
|
|
68
|
-
response: payload.Message ?? "OK",
|
|
69
|
-
envelope: {
|
|
70
|
-
from: from?.address ?? "",
|
|
71
|
-
to: [
|
|
72
|
-
...extractEmails(options.to),
|
|
73
|
-
...options.cc ? extractEmails(options.cc) : [],
|
|
74
|
-
...options.bcc ? extractEmails(options.bcc) : []
|
|
75
|
-
]
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
async verify() {
|
|
80
|
-
try {
|
|
81
|
-
const response = await fetch("https://api.postmarkapp.com/server", {
|
|
82
|
-
headers: {
|
|
83
|
-
"X-Postmark-Server-Token": this.serverToken,
|
|
84
|
-
Accept: "application/json"
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
const payload = await response.json();
|
|
88
|
-
if (!response.ok) {
|
|
89
|
-
return {
|
|
90
|
-
ok: false,
|
|
91
|
-
provider: "postmark",
|
|
92
|
-
message: payload.Message ?? `HTTP ${response.status}`
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
ok: true,
|
|
97
|
-
provider: "postmark",
|
|
98
|
-
...payload.Name ? { message: payload.Name } : {}
|
|
99
|
-
};
|
|
100
|
-
} catch (err) {
|
|
101
|
-
return {
|
|
102
|
-
ok: false,
|
|
103
|
-
provider: "postmark",
|
|
104
|
-
message: err instanceof Error ? err.message : String(err)
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
export {
|
|
110
|
-
PostmarkTransport,
|
|
111
|
-
PostmarkError
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
//# debugId=650BF60942E0759C64756E2164756E21
|
|
3
|
+
//# debugId=694050BE755D592A64756E2164756E21
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * @module\n * Postmark HTTP API transport for sending email via api.postmarkapp.com.\n *\n * @example\n * ```ts\n * import { PostmarkTransport } from \"sently/transports/postmark\";\n * import { createMailer } from \"sently\";\n *\n * const mailer = await createMailer({\n * transport: new PostmarkTransport({ serverToken: process.env.POSTMARK_TOKEN! }),\n * });\n *\n * await mailer.send({\n * from: \"sender@example.com\",\n * to: \"recipient@example.com\",\n * subject: \"Hello\",\n * text: \"Plain text body\",\n * });\n * ```\n */\nimport { extractEmails, parseAddresses, toMIMEHeader } from \"../core/address.js\";\nimport { encodeBase64 } from \"../core/base64.js\";\nimport type { MailOptions, SendResult, Transport, VerifyResult } from \"../core/types.js\";\nimport { resolveAttachments } from \"./resolve-attachments.js\";\n\n/** Postmark API configuration. */\nexport interface PostmarkConfig {\n /** Postmark server API token. */\n serverToken: string;\n}\n\n/** Error thrown when the Postmark API returns a non-success response. */\nexport class PostmarkError extends Error {\n /** Creates a Postmark API error with status code and response payload. */\n constructor(\n message: string,\n public readonly statusCode: number,\n public readonly apiError: unknown,\n ) {\n super(message);\n this.name = \"PostmarkError\";\n }\n}\n\n/**\n * Postmark HTTP API transport.\n */\nexport class PostmarkTransport implements Transport {\n /** Postmark server API token for the X-Postmark-Server-Token header. */\n private readonly serverToken: string;\n\n /** Creates a Postmark transport with the given server token. */\n constructor(config: PostmarkConfig) {\n this.serverToken = config.serverToken;\n }\n\n /** Sends an email via the Postmark HTTP API. */\n async send(options: MailOptions): Promise<SendResult> {\n const attachments = await resolveAttachments(options.attachments);\n const from = parseAddresses(options.from)[0];\n\n const body = {\n From: from ? toMIMEHeader(from) : \"\",\n To: parseAddresses(options.to).map(toMIMEHeader).join(\", \"),\n Subject: options.subject,\n ...(options.cc ? { Cc: parseAddresses(options.cc).map(toMIMEHeader).join(\", \") } : {}),\n ...(options.bcc ? { Bcc: parseAddresses(options.bcc).map(toMIMEHeader).join(\", \") } : {}),\n ...(options.replyTo\n ? { ReplyTo: parseAddresses(options.replyTo).map(toMIMEHeader).join(\", \") }\n : {}),\n ...(options.text ? { TextBody: options.text } : {}),\n ...(options.html ? { HtmlBody: options.html } : {}),\n ...(options.headers\n ? { Headers: Object.entries(options.headers).map(([Name, Value]) => ({ Name, Value })) }\n : {}),\n ...(attachments.length > 0\n ? {\n Attachments: attachments.map((att) => ({\n Name: att.filename,\n Content:\n att.content instanceof Uint8Array\n ? encodeBase64(att.content).replace(/\\r\\n/g, \"\")\n : att.content,\n ContentType: att.contentType ?? \"application/octet-stream\",\n ...(att.contentId ? { ContentID: att.contentId } : {}),\n })),\n }\n : {}),\n };\n\n const response = await fetch(\"https://api.postmarkapp.com/email\", {\n method: \"POST\",\n headers: {\n \"X-Postmark-Server-Token\": this.serverToken,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n const payload = (await response.json()) as {\n MessageID?: string;\n Message?: string;\n ErrorCode?: number;\n };\n\n if (!response.ok) {\n throw new PostmarkError(payload.Message ?? \"Postmark API error\", response.status, payload);\n }\n\n return {\n messageId: payload.MessageID ?? options.messageId ?? \"\",\n accepted: extractEmails(options.to),\n rejected: [],\n response: payload.Message ?? \"OK\",\n envelope: {\n from: from?.address ?? \"\",\n to: [\n ...extractEmails(options.to),\n ...(options.cc ? extractEmails(options.cc) : []),\n ...(options.bcc ? extractEmails(options.bcc) : []),\n ],\n },\n };\n }\n\n /** Verifies the Postmark server token by fetching server info. */\n async verify(): Promise<VerifyResult> {\n try {\n const response = await fetch(\"https://api.postmarkapp.com/server\", {\n headers: {\n \"X-Postmark-Server-Token\": this.serverToken,\n Accept: \"application/json\",\n },\n });\n\n const payload = (await response.json()) as { Name?: string; Message?: string };\n\n if (!response.ok) {\n return {\n ok: false,\n provider: \"postmark\",\n message: payload.Message ?? `HTTP ${response.status}`,\n };\n }\n\n return {\n ok: true,\n provider: \"postmark\",\n ...(payload.Name ? { message: payload.Name } : {}),\n };\n } catch (err) {\n return {\n ok: false,\n provider: \"postmark\",\n message: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "8IAiCO,CAAM,KAAsB,KAAM,CAIrB,WACA,SAHlB,WAAW,CACT,EACgB,EACA,EAChB,CACA,MAAM,CAAO,EAHG,kBACA,gBAGhB,KAAK,KAAO,gBAEhB,CAKO,MAAM,CAAuC,CAEjC,YAGjB,WAAW,CAAC,EAAwB,CAClC,KAAK,YAAc,EAAO,iBAItB,KAAI,CAAC,EAA2C,CACpD,IAAM,EAAc,MAAM,EAAmB,EAAQ,WAAW,EAC1D,EAAO,EAAe,EAAQ,IAAI,EAAE,GAEpC,EAAO,CACX,KAAM,EAAO,EAAa,CAAI,EAAI,GAClC,GAAI,EAAe,EAAQ,EAAE,EAAE,IAAI,CAAY,EAAE,KAAK,IAAI,EAC1D,QAAS,EAAQ,WACb,EAAQ,GAAK,CAAE,GAAI,EAAe,EAAQ,EAAE,EAAE,IAAI,CAAY,EAAE,KAAK,IAAI,CAAE,EAAI,CAAC,KAChF,EAAQ,IAAM,CAAE,IAAK,EAAe,EAAQ,GAAG,EAAE,IAAI,CAAY,EAAE,KAAK,IAAI,CAAE,EAAI,CAAC,KACnF,EAAQ,QACR,CAAE,QAAS,EAAe,EAAQ,OAAO,EAAE,IAAI,CAAY,EAAE,KAAK,IAAI,CAAE,EACxE,CAAC,KACD,EAAQ,KAAO,CAAE,SAAU,EAAQ,IAAK,EAAI,CAAC,KAC7C,EAAQ,KAAO,CAAE,SAAU,EAAQ,IAAK,EAAI,CAAC,KAC7C,EAAQ,QACR,CAAE,QAAS,OAAO,QAAQ,EAAQ,OAAO,EAAE,IAAI,EAAE,EAAM,MAAY,CAAE,OAAM,OAAM,EAAE,CAAE,EACrF,CAAC,KACD,EAAY,OAAS,EACrB,CACE,YAAa,EAAY,IAAI,CAAC,KAAS,CACrC,KAAM,EAAI,SACV,QACE,EAAI,mBAAmB,WACnB,EAAa,EAAI,OAAO,EAAE,QAAQ,QAAS,EAAE,EAC7C,EAAI,QACV,YAAa,EAAI,aAAe,8BAC5B,EAAI,UAAY,CAAE,UAAW,EAAI,SAAU,EAAI,CAAC,CACtD,EAAE,CACJ,EACA,CAAC,CACP,EAEM,EAAW,MAAM,MAAM,oCAAqC,CAChE,OAAQ,OACR,QAAS,CACP,0BAA2B,KAAK,YAChC,eAAgB,mBAChB,OAAQ,kBACV,EACA,KAAM,KAAK,UAAU,CAAI,CAC3B,CAAC,EAEK,EAAW,MAAM,EAAS,KAAK,EAMrC,GAAI,CAAC,EAAS,GACZ,MAAM,IAAI,EAAc,EAAQ,SAAW,qBAAsB,EAAS,OAAQ,CAAO,EAG3F,MAAO,CACL,UAAW,EAAQ,WAAa,EAAQ,WAAa,GACrD,SAAU,EAAc,EAAQ,EAAE,EAClC,SAAU,CAAC,EACX,SAAU,EAAQ,SAAW,KAC7B,SAAU,CACR,KAAM,GAAM,SAAW,GACvB,GAAI,CACF,GAAG,EAAc,EAAQ,EAAE,EAC3B,GAAI,EAAQ,GAAK,EAAc,EAAQ,EAAE,EAAI,CAAC,EAC9C,GAAI,EAAQ,IAAM,EAAc,EAAQ,GAAG,EAAI,CAAC,CAClD,CACF,CACF,OAII,OAAM,EAA0B,CACpC,GAAI,CACF,IAAM,EAAW,MAAM,MAAM,qCAAsC,CACjE,QAAS,CACP,0BAA2B,KAAK,YAChC,OAAQ,kBACV,CACF,CAAC,EAEK,EAAW,MAAM,EAAS,KAAK,EAErC,GAAI,CAAC,EAAS,GACZ,MAAO,CACL,GAAI,GACJ,SAAU,WACV,QAAS,EAAQ,SAAW,QAAQ,EAAS,QAC/C,EAGF,MAAO,CACL,GAAI,GACJ,SAAU,cACN,EAAQ,KAAO,CAAE,QAAS,EAAQ,IAAK,EAAI,CAAC,CAClD,EACA,MAAO,EAAK,CACZ,MAAO,CACL,GAAI,GACJ,SAAU,WACV,QAAS,aAAe,MAAQ,EAAI,QAAU,OAAO,CAAG,CAC1D,GAGN",
|
|
8
|
+
"debugId": "694050BE755D592A64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -1,73 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
buildMIME
|
|
3
|
-
} from "../chunk-x3szga4k.js";
|
|
4
|
-
import {
|
|
5
|
-
extractEmails,
|
|
6
|
-
resolveAttachments
|
|
7
|
-
} from "../chunk-f4c9ttmr.js";
|
|
8
|
-
import"../chunk-794hc3m4.js";
|
|
9
|
-
import {
|
|
10
|
-
__require
|
|
11
|
-
} from "../chunk-v0bahtg2.js";
|
|
1
|
+
import{j as L}from"../chunk-2t6hjer3.js";import{n as K,p as N}from"../chunk-va2awz12.js";import"../chunk-6yggz45h.js";import{I as J}from"../chunk-sqn04kae.js";function T(k){return k.replace(/[^a-zA-Z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,40)||"no-subject"}function U(k){if(k==="darwin")return"open";if(k==="win32")return"start";return"xdg-open"}class V{outDir;open;format;constructor(k){this.outDir=k?.outDir??"./.emails",this.open=k?.open??!1,this.format=k?.format??"eml"}async send(k){let H=await N(k.attachments),P={...k,attachments:H},D=await L(P),F=await import("node:fs/promises");await F.mkdir(this.outDir,{recursive:!0});let Q=`${Date.now()}-${T(k.subject)}.${this.format}`,B=`${this.outDir}/${Q}`;if(this.format==="html"){let G=k.html??(k.text?`<pre>${k.text.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}</pre>`:"");await F.writeFile(B,G,"utf8")}else await F.writeFile(B,D.raw);if(console.log(`[sently preview] Written: ${B}`),this.open){let{spawn:G}=await import("node:child_process"),R=U(process.platform);G(R,[B],{detached:!0,stdio:"ignore"}).unref()}return{messageId:D.messageId,accepted:K(k.to),rejected:[],response:`preview: ${B}`,envelope:D.envelope}}async verify(){return{ok:!0,provider:"preview"}}}export{V as PreviewTransport};
|
|
12
2
|
|
|
13
|
-
|
|
14
|
-
function sanitizeSubject(subject) {
|
|
15
|
-
const sanitized = subject.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
16
|
-
return sanitized.slice(0, 40) || "no-subject";
|
|
17
|
-
}
|
|
18
|
-
function getOpenCommand(platform) {
|
|
19
|
-
if (platform === "darwin") {
|
|
20
|
-
return "open";
|
|
21
|
-
}
|
|
22
|
-
if (platform === "win32") {
|
|
23
|
-
return "start";
|
|
24
|
-
}
|
|
25
|
-
return "xdg-open";
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
class PreviewTransport {
|
|
29
|
-
outDir;
|
|
30
|
-
open;
|
|
31
|
-
format;
|
|
32
|
-
constructor(config) {
|
|
33
|
-
this.outDir = config?.outDir ?? "./.emails";
|
|
34
|
-
this.open = config?.open ?? false;
|
|
35
|
-
this.format = config?.format ?? "eml";
|
|
36
|
-
}
|
|
37
|
-
async send(options) {
|
|
38
|
-
const attachments = await resolveAttachments(options.attachments);
|
|
39
|
-
const resolvedOptions = { ...options, attachments };
|
|
40
|
-
const mime = await buildMIME(resolvedOptions);
|
|
41
|
-
const fs = await import("node:fs/promises");
|
|
42
|
-
await fs.mkdir(this.outDir, { recursive: true });
|
|
43
|
-
const filename = `${Date.now()}-${sanitizeSubject(options.subject)}.${this.format}`;
|
|
44
|
-
const filepath = `${this.outDir}/${filename}`;
|
|
45
|
-
if (this.format === "html") {
|
|
46
|
-
const html = options.html ?? (options.text ? `<pre>${options.text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")}</pre>` : "");
|
|
47
|
-
await fs.writeFile(filepath, html, "utf8");
|
|
48
|
-
} else {
|
|
49
|
-
await fs.writeFile(filepath, mime.raw);
|
|
50
|
-
}
|
|
51
|
-
console.log(`[sently preview] Written: ${filepath}`);
|
|
52
|
-
if (this.open) {
|
|
53
|
-
const { spawn } = await import("node:child_process");
|
|
54
|
-
const command = getOpenCommand(process.platform);
|
|
55
|
-
spawn(command, [filepath], { detached: true, stdio: "ignore" }).unref();
|
|
56
|
-
}
|
|
57
|
-
return {
|
|
58
|
-
messageId: mime.messageId,
|
|
59
|
-
accepted: extractEmails(options.to),
|
|
60
|
-
rejected: [],
|
|
61
|
-
response: `preview: ${filepath}`,
|
|
62
|
-
envelope: mime.envelope
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
async verify() {
|
|
66
|
-
return { ok: true, provider: "preview" };
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
export {
|
|
70
|
-
PreviewTransport
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
//# debugId=A9DB64292AD1542264756E2164756E21
|
|
3
|
+
//# debugId=7FEBC2278CD74EB264756E2164756E21
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * @module\n * PreviewTransport — development transport that writes emails to disk\n * instead of sending them. Optionally opens in the default browser.\n * Use in place of a real transport during local development.\n *\n * @example\n * ```ts\n * import { PreviewTransport } from 'sently/transports/preview'\n * const transport = new PreviewTransport({ outDir: './.emails', open: true })\n * ```\n */\nimport { extractEmails } from \"../core/address.js\";\nimport { buildMIME } from \"../core/mime.js\";\nimport type {\n MailOptions,\n PreviewConfig,\n SendResult,\n Transport,\n VerifyResult,\n} from \"../core/types.js\";\nimport { resolveAttachments } from \"./resolve-attachments.js\";\n\nfunction sanitizeSubject(subject: string): string {\n const sanitized = subject.replace(/[^a-zA-Z0-9]+/g, \"-\").replace(/^-|-$/g, \"\");\n return sanitized.slice(0, 40) || \"no-subject\";\n}\n\nfunction getOpenCommand(platform: string): string {\n if (platform === \"darwin\") {\n return \"open\";\n }\n if (platform === \"win32\") {\n return \"start\";\n }\n return \"xdg-open\";\n}\n\n/**\n * Development transport that writes emails to disk instead of sending them.\n */\nexport class PreviewTransport implements Transport {\n /** Directory where preview `.eml` or `.html` files are written. */\n private readonly outDir: string;\n /** Whether to open the written file in the default browser. */\n private readonly open: boolean;\n /** Output format: full MIME (`.eml`) or HTML body only. */\n private readonly format: \"eml\" | \"html\";\n\n /** Creates a preview transport with optional output directory and format. */\n constructor(config?: PreviewConfig) {\n this.outDir = config?.outDir ?? \"./.emails\";\n this.open = config?.open ?? false;\n this.format = config?.format ?? \"eml\";\n }\n\n /** Writes the message to disk and returns a synthetic SendResult. */\n async send(options: MailOptions): Promise<SendResult> {\n const attachments = await resolveAttachments(options.attachments);\n const resolvedOptions = { ...options, attachments };\n const mime = await buildMIME(resolvedOptions);\n\n const fs = await import(\"node:fs/promises\");\n await fs.mkdir(this.outDir, { recursive: true });\n\n const filename = `${Date.now()}-${sanitizeSubject(options.subject)}.${this.format}`;\n const filepath = `${this.outDir}/${filename}`;\n\n if (this.format === \"html\") {\n const html =\n options.html ??\n (options.text\n ? `<pre>${options.text.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\")}</pre>`\n : \"\");\n await fs.writeFile(filepath, html, \"utf8\");\n } else {\n await fs.writeFile(filepath, mime.raw);\n }\n\n console.log(`[sently preview] Written: ${filepath}`);\n\n if (this.open) {\n const { spawn } = await import(\"node:child_process\");\n const command = getOpenCommand(process.platform);\n spawn(command, [filepath], { detached: true, stdio: \"ignore\" }).unref();\n }\n\n return {\n messageId: mime.messageId,\n accepted: extractEmails(options.to),\n rejected: [],\n response: `preview: ${filepath}`,\n envelope: mime.envelope,\n };\n }\n\n /** Always succeeds — preview transport requires no external connectivity. */\n async verify(): Promise<VerifyResult> {\n return { ok: true, provider: \"preview\" };\n }\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "8KAuBA,IAAS,JAAe,JAAC,EAAyB,CAEhD,OADkB,EAAQ,QAAQ,iBAAkB,GAAG,EAAE,QAAQ,SAAU,EAAE,EAC5D,MAAM,EAAG,EAAE,GAAK,aAGnC,SAAS,CAAc,CAAC,EAA0B,CAChD,GAAI,IAAa,SACf,MAAO,OAET,GAAI,IAAa,QACf,MAAO,QAET,MAAO,WAMF,MAAM,CAAsC,CAEhC,OAEA,KAEA,OAGjB,WAAW,CAAC,EAAwB,CAClC,KAAK,OAAS,GAAQ,QAAU,YAChC,KAAK,KAAO,GAAQ,MAAQ,GAC5B,KAAK,OAAS,GAAQ,QAAU,WAI5B,KAAI,CAAC,EAA2C,CACpD,IAAM,EAAc,MAAM,EAAmB,EAAQ,WAAW,EAC1D,EAAkB,IAAK,EAAS,aAAY,EAC5C,EAAO,MAAM,EAAU,CAAe,EAEtC,EAAK,KAAa,4BACxB,MAAM,EAAG,MAAM,KAAK,OAAQ,CAAE,UAAW,EAAK,CAAC,EAE/C,IAAM,EAAW,GAAG,KAAK,IAAI,KAAK,EAAgB,EAAQ,OAAO,KAAK,KAAK,SACrE,EAAW,GAAG,KAAK,UAAU,IAEnC,GAAI,KAAK,SAAW,OAAQ,CAC1B,IAAM,EACJ,EAAQ,OACP,EAAQ,KACL,QAAQ,EAAQ,KAAK,QAAQ,KAAM,OAAO,EAAE,QAAQ,KAAM,MAAM,EAAE,QAAQ,KAAM,MAAM,UACtF,IACN,MAAM,EAAG,UAAU,EAAU,EAAM,MAAM,EAEzC,WAAM,EAAG,UAAU,EAAU,EAAK,GAAG,EAKvC,GAFA,QAAQ,IAAI,6BAA6B,GAAU,EAE/C,KAAK,KAAM,CACb,IAAQ,SAAU,KAAa,8BACzB,EAAU,EAAe,QAAQ,QAAQ,EAC/C,EAAM,EAAS,CAAC,CAAQ,EAAG,CAAE,SAAU,GAAM,MAAO,QAAS,CAAC,EAAE,MAAM,EAGxE,MAAO,CACL,UAAW,EAAK,UAChB,SAAU,EAAc,EAAQ,EAAE,EAClC,SAAU,CAAC,EACX,SAAU,YAAY,IACtB,SAAU,EAAK,QACjB,OAII,OAAM,EAA0B,CACpC,MAAO,CAAE,GAAI,GAAM,SAAU,SAAU,EAE3C",
|
|
8
|
+
"debugId": "7FEBC2278CD74EB264756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -1,110 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
extractEmails,
|
|
3
|
-
parseAddresses,
|
|
4
|
-
resolveAttachments,
|
|
5
|
-
toMIMEHeader
|
|
6
|
-
} from "../chunk-f4c9ttmr.js";
|
|
7
|
-
import {
|
|
8
|
-
encodeBase64
|
|
9
|
-
} from "../chunk-794hc3m4.js";
|
|
10
|
-
import"../chunk-v0bahtg2.js";
|
|
1
|
+
import{l as J,m as K,n as u,p as L}from"../chunk-va2awz12.js";import{E as G}from"../chunk-6yggz45h.js";import"../chunk-sqn04kae.js";class N extends Error{statusCode;apiError;constructor(q,z,C){super(q);this.statusCode=z;this.apiError=C;this.name="ResendError"}}class S{apiKey;baseUrl;constructor(q){this.apiKey=q.apiKey,this.baseUrl=q.baseUrl??"https://api.resend.com"}async send(q){let z=await L(q.attachments),C=J(q.from)[0],O={from:C?K(C):"",to:u(q.to),subject:q.subject,...q.cc?{cc:u(q.cc)}:{},...q.bcc?{bcc:u(q.bcc)}:{},...q.replyTo?{reply_to:u(q.replyTo)}:{},...q.text?{text:q.text}:{},...q.html?{html:q.html}:{},...q.headers?{headers:q.headers}:{},...z.length>0?{attachments:z.map((w)=>({filename:w.filename,content:w.content instanceof Uint8Array?G(w.content).replace(/\r\n/g,""):w.content,...w.contentType?{content_type:w.contentType}:{}}))}:{}},F=await fetch(`${this.baseUrl}/emails`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify(O)}),D=await F.json();if(!F.ok)throw new N(D.message??"Resend API error",F.status,D);let Q=u(q.to);return{messageId:D.id??q.messageId??"",accepted:Q,rejected:[],response:D.message??"Email sent",envelope:{from:C?.address??"",to:[...u(q.to),...q.cc?u(q.cc):[],...q.bcc?u(q.bcc):[]]}}}async verify(){try{let q=await fetch(`${this.baseUrl}/domains`,{headers:{Authorization:`Bearer ${this.apiKey}`}});if(!q.ok)return{ok:!1,provider:"resend",message:(await q.json().catch(()=>({}))).message??`HTTP ${q.status}`};return{ok:!0,provider:"resend",message:"API key is valid"}}catch(q){return{ok:!1,provider:"resend",message:q instanceof Error?q.message:String(q)}}}}export{S as ResendTransport,N as ResendError};
|
|
11
2
|
|
|
12
|
-
|
|
13
|
-
class ResendError extends Error {
|
|
14
|
-
statusCode;
|
|
15
|
-
apiError;
|
|
16
|
-
constructor(message, statusCode, apiError) {
|
|
17
|
-
super(message);
|
|
18
|
-
this.statusCode = statusCode;
|
|
19
|
-
this.apiError = apiError;
|
|
20
|
-
this.name = "ResendError";
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
class ResendTransport {
|
|
25
|
-
apiKey;
|
|
26
|
-
baseUrl;
|
|
27
|
-
constructor(config) {
|
|
28
|
-
this.apiKey = config.apiKey;
|
|
29
|
-
this.baseUrl = config.baseUrl ?? "https://api.resend.com";
|
|
30
|
-
}
|
|
31
|
-
async send(options) {
|
|
32
|
-
const attachments = await resolveAttachments(options.attachments);
|
|
33
|
-
const from = parseAddresses(options.from)[0];
|
|
34
|
-
const body = {
|
|
35
|
-
from: from ? toMIMEHeader(from) : "",
|
|
36
|
-
to: extractEmails(options.to),
|
|
37
|
-
subject: options.subject,
|
|
38
|
-
...options.cc ? { cc: extractEmails(options.cc) } : {},
|
|
39
|
-
...options.bcc ? { bcc: extractEmails(options.bcc) } : {},
|
|
40
|
-
...options.replyTo ? { reply_to: extractEmails(options.replyTo) } : {},
|
|
41
|
-
...options.text ? { text: options.text } : {},
|
|
42
|
-
...options.html ? { html: options.html } : {},
|
|
43
|
-
...options.headers ? { headers: options.headers } : {},
|
|
44
|
-
...attachments.length > 0 ? {
|
|
45
|
-
attachments: attachments.map((att) => ({
|
|
46
|
-
filename: att.filename,
|
|
47
|
-
content: att.content instanceof Uint8Array ? encodeBase64(att.content).replace(/\r\n/g, "") : att.content,
|
|
48
|
-
...att.contentType ? { content_type: att.contentType } : {}
|
|
49
|
-
}))
|
|
50
|
-
} : {}
|
|
51
|
-
};
|
|
52
|
-
const response = await fetch(`${this.baseUrl}/emails`, {
|
|
53
|
-
method: "POST",
|
|
54
|
-
headers: {
|
|
55
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
56
|
-
"Content-Type": "application/json"
|
|
57
|
-
},
|
|
58
|
-
body: JSON.stringify(body)
|
|
59
|
-
});
|
|
60
|
-
const payload = await response.json();
|
|
61
|
-
if (!response.ok) {
|
|
62
|
-
throw new ResendError(payload.message ?? "Resend API error", response.status, payload);
|
|
63
|
-
}
|
|
64
|
-
const accepted = extractEmails(options.to);
|
|
65
|
-
return {
|
|
66
|
-
messageId: payload.id ?? options.messageId ?? "",
|
|
67
|
-
accepted,
|
|
68
|
-
rejected: [],
|
|
69
|
-
response: payload.message ?? "Email sent",
|
|
70
|
-
envelope: {
|
|
71
|
-
from: from?.address ?? "",
|
|
72
|
-
to: [
|
|
73
|
-
...extractEmails(options.to),
|
|
74
|
-
...options.cc ? extractEmails(options.cc) : [],
|
|
75
|
-
...options.bcc ? extractEmails(options.bcc) : []
|
|
76
|
-
]
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
async verify() {
|
|
81
|
-
try {
|
|
82
|
-
const response = await fetch(`${this.baseUrl}/domains`, {
|
|
83
|
-
headers: {
|
|
84
|
-
Authorization: `Bearer ${this.apiKey}`
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
if (!response.ok) {
|
|
88
|
-
const payload = await response.json().catch(() => ({}));
|
|
89
|
-
return {
|
|
90
|
-
ok: false,
|
|
91
|
-
provider: "resend",
|
|
92
|
-
message: payload.message ?? `HTTP ${response.status}`
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
return { ok: true, provider: "resend", message: "API key is valid" };
|
|
96
|
-
} catch (err) {
|
|
97
|
-
return {
|
|
98
|
-
ok: false,
|
|
99
|
-
provider: "resend",
|
|
100
|
-
message: err instanceof Error ? err.message : String(err)
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
export {
|
|
106
|
-
ResendTransport,
|
|
107
|
-
ResendError
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
//# debugId=C97D4F9F26828E0A64756E2164756E21
|
|
3
|
+
//# debugId=1A3DCAB71639D29464756E2164756E21
|