sently 0.4.5 → 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 +44 -0
- package/README.md +94 -41
- package/dist/adapters/bun.d.ts +7 -0
- package/dist/adapters/bun.js +2 -183
- package/dist/adapters/bun.js.map +3 -3
- package/dist/adapters/cf.d.ts +6 -0
- package/dist/adapters/cf.js +2 -77
- package/dist/adapters/cf.js.map +3 -3
- package/dist/adapters/deno.d.ts +4 -0
- package/dist/adapters/deno.js +2 -72
- package/dist/adapters/deno.js.map +3 -3
- package/dist/adapters/node.d.ts +7 -0
- package/dist/adapters/node.js +2 -180
- package/dist/adapters/node.js.map +3 -3
- package/dist/auth/oauth2.d.ts +4 -0
- 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-dgkh77yp.js.map +10 -0
- package/dist/chunk-jfs80vhp.js +3 -0
- package/dist/chunk-jfs80vhp.js.map +10 -0
- 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-wgtbr6ge.js.map +11 -0
- package/dist/core/mime.d.ts +4 -0
- package/dist/core/sigv4.d.ts +10 -0
- package/dist/core/smtp.d.ts +5 -0
- 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/connection.d.ts +4 -0
- package/dist/pool/pool.d.ts +20 -0
- package/dist/pool/pool.js +2 -16
- package/dist/pool/pool.js.map +5 -3
- package/dist/transports/brevo.d.ts +1 -0
- package/dist/transports/brevo.js +2 -115
- package/dist/transports/brevo.js.map +3 -3
- package/dist/transports/mailgun.d.ts +3 -0
- package/dist/transports/mailgun.js +2 -119
- package/dist/transports/mailgun.js.map +3 -3
- package/dist/transports/postmark.d.ts +1 -0
- package/dist/transports/postmark.js +2 -113
- package/dist/transports/postmark.js.map +3 -3
- package/dist/transports/preview.d.ts +3 -0
- package/dist/transports/preview.js +2 -72
- package/dist/transports/preview.js.map +3 -3
- package/dist/transports/resend.d.ts +2 -0
- package/dist/transports/resend.js +2 -109
- package/dist/transports/resend.js.map +3 -3
- package/dist/transports/retry.d.ts +12 -1
- package/dist/transports/retry.js +2 -78
- package/dist/transports/retry.js.map +3 -3
- package/dist/transports/sendgrid.d.ts +1 -0
- package/dist/transports/sendgrid.js +2 -132
- package/dist/transports/sendgrid.js.map +3 -3
- package/dist/transports/ses.d.ts +5 -0
- package/dist/transports/ses.js +5 -251
- package/dist/transports/ses.js.map +4 -4
- package/dist/transports/smtp.d.ts +3 -0
- 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-7fqv71z1.js.map +0 -10
- 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-tymfm441.js.map +0 -11
- 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
- package/dist/chunk-ym3zzv8b.js.map +0 -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
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/transports/postmark.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
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 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"
|
|
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
|
}
|
|
@@ -3,8 +3,11 @@ import type { MailOptions, PreviewConfig, SendResult, Transport, VerifyResult }
|
|
|
3
3
|
* Development transport that writes emails to disk instead of sending them.
|
|
4
4
|
*/
|
|
5
5
|
export declare class PreviewTransport implements Transport {
|
|
6
|
+
/** Directory where preview `.eml` or `.html` files are written. */
|
|
6
7
|
private readonly outDir;
|
|
8
|
+
/** Whether to open the written file in the default browser. */
|
|
7
9
|
private readonly open;
|
|
10
|
+
/** Output format: full MIME (`.eml`) or HTML body only. */
|
|
8
11
|
private readonly format;
|
|
9
12
|
/** Creates a preview transport with optional output directory and format. */
|
|
10
13
|
constructor(config?: PreviewConfig);
|
|
@@ -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
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/transports/preview.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
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 private readonly outDir: string;\n private readonly open: boolean;\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"
|
|
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
|
}
|
|
@@ -17,7 +17,9 @@ export declare class ResendError extends Error {
|
|
|
17
17
|
* Resend HTTP API transport.
|
|
18
18
|
*/
|
|
19
19
|
export declare class ResendTransport implements Transport {
|
|
20
|
+
/** Resend API key for Bearer authentication. */
|
|
20
21
|
private readonly apiKey;
|
|
22
|
+
/** Resend API base URL. */
|
|
21
23
|
private readonly baseUrl;
|
|
22
24
|
/** Creates a Resend transport with the given API key. */
|
|
23
25
|
constructor(config: ResendConfig);
|
|
@@ -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
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/transports/resend.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * @module\n * Resend HTTP API transport for sending email via api.resend.com.\n *\n * @example\n * ```ts\n * import { ResendTransport } from \"sently/transports/resend\";\n * import { createMailer } from \"sently\";\n *\n * const mailer = await createMailer({\n * transport: new ResendTransport({ apiKey: process.env.RESEND_API_KEY! }),\n * });\n *\n * await mailer.send({\n * from: \"onboarding@yourdomain.com\",\n * to: \"recipient@example.com\",\n * subject: \"Hello\",\n * html: \"<p>Sent via Resend</p>\",\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/** Resend API configuration. */\nexport interface ResendConfig {\n /** Resend API key (starts with `re_`). */\n apiKey: string;\n /** API base URL. Default: `https://api.resend.com`. */\n baseUrl?: string;\n}\n\n/** Error thrown when the Resend API returns a non-success response. */\nexport class ResendError extends Error {\n /** Creates a Resend 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 = \"ResendError\";\n }\n}\n\n/**\n * Resend HTTP API transport.\n */\nexport class ResendTransport implements Transport {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n\n /** Creates a Resend transport with the given API key. */\n constructor(config: ResendConfig) {\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl ?? \"https://api.resend.com\";\n }\n\n /** Sends an email via the Resend HTTP API. */\n async send(options: MailOptions): Promise<SendResult> {\n const attachments = await resolveAttachments(options.attachments);\n const from = parseAddresses(options.from)[0];\n const body = {\n from: from ? toMIMEHeader(from) : \"\",\n to: extractEmails(options.to),\n subject: options.subject,\n ...(options.cc ? { cc: extractEmails(options.cc) } : {}),\n ...(options.bcc ? { bcc: extractEmails(options.bcc) } : {}),\n ...(options.replyTo ? { reply_to: extractEmails(options.replyTo) } : {}),\n ...(options.text ? { text: options.text } : {}),\n ...(options.html ? { html: options.html } : {}),\n ...(options.headers ? { headers: options.headers } : {}),\n ...(attachments.length > 0\n ? {\n attachments: attachments.map((att) => ({\n filename: att.filename,\n content:\n att.content instanceof Uint8Array\n ? encodeBase64(att.content).replace(/\\r\\n/g, \"\")\n : att.content,\n ...(att.contentType ? { content_type: att.contentType } : {}),\n })),\n }\n : {}),\n };\n\n const response = await fetch(`${this.baseUrl}/emails`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n const payload = (await response.json()) as { id?: string; message?: string };\n\n if (!response.ok) {\n throw new ResendError(payload.message ?? \"Resend API error\", response.status, payload);\n }\n\n const accepted = extractEmails(options.to);\n return {\n messageId: payload.id ?? options.messageId ?? \"\",\n accepted,\n rejected: [],\n response: payload.message ?? \"Email sent\",\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 Resend API key by listing domains. */\n async verify(): Promise<VerifyResult> {\n try {\n const response = await fetch(`${this.baseUrl}/domains`, {\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n },\n });\n\n if (!response.ok) {\n const payload = (await response.json().catch(() => ({}))) as { message?: string };\n return {\n ok: false,\n provider: \"resend\",\n message: payload.message ?? `HTTP ${response.status}`,\n };\n }\n\n return { ok: true, provider: \"resend\", message: \"API key is valid\" };\n } catch (err) {\n return {\n ok: false,\n provider: \"resend\",\n message: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n"
|
|
5
|
+
"/**\n * @module\n * Resend HTTP API transport for sending email via api.resend.com.\n *\n * @example\n * ```ts\n * import { ResendTransport } from \"sently/transports/resend\";\n * import { createMailer } from \"sently\";\n *\n * const mailer = await createMailer({\n * transport: new ResendTransport({ apiKey: process.env.RESEND_API_KEY! }),\n * });\n *\n * await mailer.send({\n * from: \"onboarding@yourdomain.com\",\n * to: \"recipient@example.com\",\n * subject: \"Hello\",\n * html: \"<p>Sent via Resend</p>\",\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/** Resend API configuration. */\nexport interface ResendConfig {\n /** Resend API key (starts with `re_`). */\n apiKey: string;\n /** API base URL. Default: `https://api.resend.com`. */\n baseUrl?: string;\n}\n\n/** Error thrown when the Resend API returns a non-success response. */\nexport class ResendError extends Error {\n /** Creates a Resend 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 = \"ResendError\";\n }\n}\n\n/**\n * Resend HTTP API transport.\n */\nexport class ResendTransport implements Transport {\n /** Resend API key for Bearer authentication. */\n private readonly apiKey: string;\n /** Resend API base URL. */\n private readonly baseUrl: string;\n\n /** Creates a Resend transport with the given API key. */\n constructor(config: ResendConfig) {\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl ?? \"https://api.resend.com\";\n }\n\n /** Sends an email via the Resend HTTP API. */\n async send(options: MailOptions): Promise<SendResult> {\n const attachments = await resolveAttachments(options.attachments);\n const from = parseAddresses(options.from)[0];\n const body = {\n from: from ? toMIMEHeader(from) : \"\",\n to: extractEmails(options.to),\n subject: options.subject,\n ...(options.cc ? { cc: extractEmails(options.cc) } : {}),\n ...(options.bcc ? { bcc: extractEmails(options.bcc) } : {}),\n ...(options.replyTo ? { reply_to: extractEmails(options.replyTo) } : {}),\n ...(options.text ? { text: options.text } : {}),\n ...(options.html ? { html: options.html } : {}),\n ...(options.headers ? { headers: options.headers } : {}),\n ...(attachments.length > 0\n ? {\n attachments: attachments.map((att) => ({\n filename: att.filename,\n content:\n att.content instanceof Uint8Array\n ? encodeBase64(att.content).replace(/\\r\\n/g, \"\")\n : att.content,\n ...(att.contentType ? { content_type: att.contentType } : {}),\n })),\n }\n : {}),\n };\n\n const response = await fetch(`${this.baseUrl}/emails`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n const payload = (await response.json()) as { id?: string; message?: string };\n\n if (!response.ok) {\n throw new ResendError(payload.message ?? \"Resend API error\", response.status, payload);\n }\n\n const accepted = extractEmails(options.to);\n return {\n messageId: payload.id ?? options.messageId ?? \"\",\n accepted,\n rejected: [],\n response: payload.message ?? \"Email sent\",\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 Resend API key by listing domains. */\n async verify(): Promise<VerifyResult> {\n try {\n const response = await fetch(`${this.baseUrl}/domains`, {\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n },\n });\n\n if (!response.ok) {\n const payload = (await response.json().catch(() => ({}))) as { message?: string };\n return {\n ok: false,\n provider: \"resend\",\n message: payload.message ?? `HTTP ${response.status}`,\n };\n }\n\n return { ok: true, provider: \"resend\", message: \"API key is valid\" };\n } catch (err) {\n return {\n ok: false,\n provider: \"resend\",\n message: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "8IAmCO,CAAM,KAAoB,KAAM,CAInB,WACA,SAHlB,WAAW,CACT,EACgB,EACA,EAChB,CACA,MAAM,CAAO,EAHG,kBACA,gBAGhB,KAAK,KAAO,cAEhB,CAKO,MAAM,CAAqC,CAE/B,OAEA,QAGjB,WAAW,CAAC,EAAsB,CAChC,KAAK,OAAS,EAAO,OACrB,KAAK,QAAU,EAAO,SAAW,8BAI7B,KAAI,CAAC,EAA2C,CACpD,IAAM,EAAc,MAAM,EAAmB,EAAQ,WAAW,EAC1D,EAAO,EAAe,EAAQ,IAAI,EAAE,GACpC,EAAO,CACX,KAAM,EAAO,EAAa,CAAI,EAAI,GAClC,GAAI,EAAc,EAAQ,EAAE,EAC5B,QAAS,EAAQ,WACb,EAAQ,GAAK,CAAE,GAAI,EAAc,EAAQ,EAAE,CAAE,EAAI,CAAC,KAClD,EAAQ,IAAM,CAAE,IAAK,EAAc,EAAQ,GAAG,CAAE,EAAI,CAAC,KACrD,EAAQ,QAAU,CAAE,SAAU,EAAc,EAAQ,OAAO,CAAE,EAAI,CAAC,KAClE,EAAQ,KAAO,CAAE,KAAM,EAAQ,IAAK,EAAI,CAAC,KACzC,EAAQ,KAAO,CAAE,KAAM,EAAQ,IAAK,EAAI,CAAC,KACzC,EAAQ,QAAU,CAAE,QAAS,EAAQ,OAAQ,EAAI,CAAC,KAClD,EAAY,OAAS,EACrB,CACE,YAAa,EAAY,IAAI,CAAC,KAAS,CACrC,SAAU,EAAI,SACd,QACE,EAAI,mBAAmB,WACnB,EAAa,EAAI,OAAO,EAAE,QAAQ,QAAS,EAAE,EAC7C,EAAI,WACN,EAAI,YAAc,CAAE,aAAc,EAAI,WAAY,EAAI,CAAC,CAC7D,EAAE,CACJ,EACA,CAAC,CACP,EAEM,EAAW,MAAM,MAAM,GAAG,KAAK,iBAAkB,CACrD,OAAQ,OACR,QAAS,CACP,cAAe,UAAU,KAAK,SAC9B,eAAgB,kBAClB,EACA,KAAM,KAAK,UAAU,CAAI,CAC3B,CAAC,EAEK,EAAW,MAAM,EAAS,KAAK,EAErC,GAAI,CAAC,EAAS,GACZ,MAAM,IAAI,EAAY,EAAQ,SAAW,mBAAoB,EAAS,OAAQ,CAAO,EAGvF,IAAM,EAAW,EAAc,EAAQ,EAAE,EACzC,MAAO,CACL,UAAW,EAAQ,IAAM,EAAQ,WAAa,GAC9C,WACA,SAAU,CAAC,EACX,SAAU,EAAQ,SAAW,aAC7B,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,GAAG,KAAK,kBAAmB,CACtD,QAAS,CACP,cAAe,UAAU,KAAK,QAChC,CACF,CAAC,EAED,GAAI,CAAC,EAAS,GAEZ,MAAO,CACL,GAAI,GACJ,SAAU,SACV,SAJe,MAAM,EAAS,KAAK,EAAE,MAAM,KAAO,CAAC,EAAE,GAIpC,SAAW,QAAQ,EAAS,QAC/C,EAGF,MAAO,CAAE,GAAI,GAAM,SAAU,SAAU,QAAS,kBAAmB,EACnE,MAAO,EAAK,CACZ,MAAO,CACL,GAAI,GACJ,SAAU,SACV,QAAS,aAAe,MAAQ,EAAI,QAAU,OAAO,CAAG,CAC1D,GAGN",
|
|
8
|
+
"debugId": "1A3DCAB71639D29464756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -3,15 +3,26 @@ import type { MailOptions, RetryConfig, SendResult, Transport, VerifyResult } fr
|
|
|
3
3
|
* Decorator transport that retries failed sends with configurable backoff.
|
|
4
4
|
*/
|
|
5
5
|
export declare class RetryTransport implements Transport {
|
|
6
|
+
/** Transport that performs the actual send on each attempt. */
|
|
6
7
|
private readonly inner;
|
|
8
|
+
/** Injectable sleep function for testing backoff timing. */
|
|
7
9
|
private readonly _sleep;
|
|
10
|
+
/** Maximum send attempts including the initial try. */
|
|
8
11
|
private readonly maxAttempts;
|
|
12
|
+
/** Backoff strategy between retries. */
|
|
9
13
|
private readonly backoff;
|
|
14
|
+
/** Base delay in milliseconds before the first retry. */
|
|
10
15
|
private readonly baseDelay;
|
|
16
|
+
/** HTTP status codes that trigger a retry. */
|
|
11
17
|
private readonly retryOn;
|
|
18
|
+
/** Optional callback invoked before each retry attempt. */
|
|
12
19
|
private readonly onRetry;
|
|
13
20
|
/** Wraps an inner transport with retry logic and optional backoff configuration. */
|
|
14
|
-
constructor(
|
|
21
|
+
constructor(
|
|
22
|
+
/** Transport that performs the actual send on each attempt. */
|
|
23
|
+
inner: Transport, config?: RetryConfig,
|
|
24
|
+
/** Injectable sleep function for testing backoff timing. */
|
|
25
|
+
_sleep?: (ms: number) => Promise<void>);
|
|
15
26
|
/** Sends with retries according to configured backoff and retry rules. */
|
|
16
27
|
send(options: MailOptions): Promise<SendResult>;
|
|
17
28
|
/** Delegates to the inner transport verify or returns a default success result. */
|
package/dist/transports/retry.js
CHANGED
|
@@ -1,79 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
SMTPError
|
|
3
|
-
} from "../chunk-tymfm441.js";
|
|
4
|
-
import"../chunk-794hc3m4.js";
|
|
5
|
-
import"../chunk-v0bahtg2.js";
|
|
1
|
+
import{t as C}from"../chunk-wgtbr6ge.js";import"../chunk-6yggz45h.js";import"../chunk-sqn04kae.js";var G=[429,500,502,503,504];function H(q,w,x){if(w==="exponential")return x*2**(q-1);if(w==="linear")return x*q;return x}function I(q,w){if(q instanceof C&&q.code===535)return!1;if(typeof q==="object"&&q!==null&&"statusCode"in q&&typeof q.statusCode==="number")return w.includes(q.statusCode);return!0}class J{inner;_sleep;maxAttempts;backoff;baseDelay;retryOn;onRetry;constructor(q,w,x=(z)=>new Promise((B)=>setTimeout(B,z))){this.inner=q;this._sleep=x;this.maxAttempts=w?.maxAttempts??3,this.backoff=w?.backoff??"exponential",this.baseDelay=w?.baseDelay??1000,this.retryOn=w?.retryOn??G,this.onRetry=w?.onRetry}async send(q){let w;for(let x=1;x<=this.maxAttempts;x++)try{return await this.inner.send(q)}catch(z){if(w=z,x===this.maxAttempts)throw z;if(!I(z,this.retryOn))throw z;let B=H(x,this.backoff,this.baseDelay);this.onRetry?.(x,z),await this._sleep(B)}throw w}async verify(){if(this.inner.verify)return this.inner.verify();return{ok:!0,provider:"retry"}}async close(){await this.inner.close?.()}}export{J as RetryTransport};
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
var DEFAULT_RETRY_ON = [429, 500, 502, 503, 504];
|
|
9
|
-
function computeDelay(attempt, backoff, base) {
|
|
10
|
-
if (backoff === "exponential") {
|
|
11
|
-
return base * 2 ** (attempt - 1);
|
|
12
|
-
}
|
|
13
|
-
if (backoff === "linear") {
|
|
14
|
-
return base * attempt;
|
|
15
|
-
}
|
|
16
|
-
return base;
|
|
17
|
-
}
|
|
18
|
-
function shouldRetry(err, retryOn) {
|
|
19
|
-
if (err instanceof SMTPError && err.code === 535) {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
if (typeof err === "object" && err !== null && "statusCode" in err && typeof err.statusCode === "number") {
|
|
23
|
-
return retryOn.includes(err.statusCode);
|
|
24
|
-
}
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
class RetryTransport {
|
|
29
|
-
inner;
|
|
30
|
-
_sleep;
|
|
31
|
-
maxAttempts;
|
|
32
|
-
backoff;
|
|
33
|
-
baseDelay;
|
|
34
|
-
retryOn;
|
|
35
|
-
onRetry;
|
|
36
|
-
constructor(inner, config, _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
|
|
37
|
-
this.inner = inner;
|
|
38
|
-
this._sleep = _sleep;
|
|
39
|
-
this.maxAttempts = config?.maxAttempts ?? 3;
|
|
40
|
-
this.backoff = config?.backoff ?? "exponential";
|
|
41
|
-
this.baseDelay = config?.baseDelay ?? 1000;
|
|
42
|
-
this.retryOn = config?.retryOn ?? DEFAULT_RETRY_ON;
|
|
43
|
-
this.onRetry = config?.onRetry;
|
|
44
|
-
}
|
|
45
|
-
async send(options) {
|
|
46
|
-
let lastError;
|
|
47
|
-
for (let attempt = 1;attempt <= this.maxAttempts; attempt++) {
|
|
48
|
-
try {
|
|
49
|
-
return await this.inner.send(options);
|
|
50
|
-
} catch (err) {
|
|
51
|
-
lastError = err;
|
|
52
|
-
if (attempt === this.maxAttempts) {
|
|
53
|
-
throw err;
|
|
54
|
-
}
|
|
55
|
-
if (!shouldRetry(err, this.retryOn)) {
|
|
56
|
-
throw err;
|
|
57
|
-
}
|
|
58
|
-
const delay = computeDelay(attempt, this.backoff, this.baseDelay);
|
|
59
|
-
this.onRetry?.(attempt, err);
|
|
60
|
-
await this._sleep(delay);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
throw lastError;
|
|
64
|
-
}
|
|
65
|
-
async verify() {
|
|
66
|
-
if (this.inner.verify) {
|
|
67
|
-
return this.inner.verify();
|
|
68
|
-
}
|
|
69
|
-
return { ok: true, provider: "retry" };
|
|
70
|
-
}
|
|
71
|
-
async close() {
|
|
72
|
-
await this.inner.close?.();
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
export {
|
|
76
|
-
RetryTransport
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
//# debugId=F5AD32E7B75CAE2A64756E2164756E21
|
|
3
|
+
//# debugId=1E2375BF1AD866DC64756E2164756E21
|