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.
Files changed (97) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +94 -41
  3. package/dist/adapters/bun.d.ts +7 -0
  4. package/dist/adapters/bun.js +2 -183
  5. package/dist/adapters/bun.js.map +3 -3
  6. package/dist/adapters/cf.d.ts +6 -0
  7. package/dist/adapters/cf.js +2 -77
  8. package/dist/adapters/cf.js.map +3 -3
  9. package/dist/adapters/deno.d.ts +4 -0
  10. package/dist/adapters/deno.js +2 -72
  11. package/dist/adapters/deno.js.map +3 -3
  12. package/dist/adapters/node.d.ts +7 -0
  13. package/dist/adapters/node.js +2 -180
  14. package/dist/adapters/node.js.map +3 -3
  15. package/dist/auth/oauth2.d.ts +4 -0
  16. package/dist/auth/oauth2.js +2 -13
  17. package/dist/auth/oauth2.js.map +1 -1
  18. package/dist/chunk-2kcwa9gt.js +4 -0
  19. package/dist/chunk-2kcwa9gt.js.map +11 -0
  20. package/dist/chunk-2t6hjer3.js +5 -0
  21. package/dist/chunk-2t6hjer3.js.map +10 -0
  22. package/dist/chunk-6yggz45h.js +5 -0
  23. package/dist/{chunk-794hc3m4.js.map → chunk-6yggz45h.js.map} +2 -2
  24. package/dist/chunk-dgkh77yp.js +4 -0
  25. package/dist/chunk-dgkh77yp.js.map +10 -0
  26. package/dist/chunk-jfs80vhp.js +3 -0
  27. package/dist/chunk-jfs80vhp.js.map +10 -0
  28. package/dist/chunk-sqn04kae.js +4 -0
  29. package/dist/{chunk-v0bahtg2.js.map → chunk-sqn04kae.js.map} +1 -1
  30. package/dist/chunk-va2awz12.js +4 -0
  31. package/dist/{chunk-f4c9ttmr.js.map → chunk-va2awz12.js.map} +2 -2
  32. package/dist/chunk-wgtbr6ge.js +13 -0
  33. package/dist/chunk-wgtbr6ge.js.map +11 -0
  34. package/dist/core/mime.d.ts +4 -0
  35. package/dist/core/sigv4.d.ts +10 -0
  36. package/dist/core/smtp.d.ts +5 -0
  37. package/dist/core/smtp.js +2 -31
  38. package/dist/core/smtp.js.map +1 -1
  39. package/dist/core/types.d.ts +7 -0
  40. package/dist/detect.d.ts +2 -0
  41. package/dist/detect.js +2 -180
  42. package/dist/detect.js.map +4 -5
  43. package/dist/dkim.d.ts +21 -0
  44. package/dist/dkim.js +9 -0
  45. package/dist/dkim.js.map +10 -0
  46. package/dist/index.d.ts +74 -16
  47. package/dist/index.js +85 -14
  48. package/dist/mailer.d.ts +16 -0
  49. package/dist/mailer.js +3 -0
  50. package/dist/mailer.js.map +9 -0
  51. package/dist/plugins/template.js +2 -28
  52. package/dist/plugins/template.js.map +2 -2
  53. package/dist/pool/connection.d.ts +4 -0
  54. package/dist/pool/pool.d.ts +20 -0
  55. package/dist/pool/pool.js +2 -16
  56. package/dist/pool/pool.js.map +5 -3
  57. package/dist/transports/brevo.d.ts +1 -0
  58. package/dist/transports/brevo.js +2 -115
  59. package/dist/transports/brevo.js.map +3 -3
  60. package/dist/transports/mailgun.d.ts +3 -0
  61. package/dist/transports/mailgun.js +2 -119
  62. package/dist/transports/mailgun.js.map +3 -3
  63. package/dist/transports/postmark.d.ts +1 -0
  64. package/dist/transports/postmark.js +2 -113
  65. package/dist/transports/postmark.js.map +3 -3
  66. package/dist/transports/preview.d.ts +3 -0
  67. package/dist/transports/preview.js +2 -72
  68. package/dist/transports/preview.js.map +3 -3
  69. package/dist/transports/resend.d.ts +2 -0
  70. package/dist/transports/resend.js +2 -109
  71. package/dist/transports/resend.js.map +3 -3
  72. package/dist/transports/retry.d.ts +12 -1
  73. package/dist/transports/retry.js +2 -78
  74. package/dist/transports/retry.js.map +3 -3
  75. package/dist/transports/sendgrid.d.ts +1 -0
  76. package/dist/transports/sendgrid.js +2 -132
  77. package/dist/transports/sendgrid.js.map +3 -3
  78. package/dist/transports/ses.d.ts +5 -0
  79. package/dist/transports/ses.js +5 -251
  80. package/dist/transports/ses.js.map +4 -4
  81. package/dist/transports/smtp.d.ts +3 -0
  82. package/dist/transports/smtp.js +2 -26
  83. package/dist/transports/smtp.js.map +1 -1
  84. package/package.json +17 -6
  85. package/dist/chunk-794hc3m4.js +0 -105
  86. package/dist/chunk-7fqv71z1.js +0 -251
  87. package/dist/chunk-7fqv71z1.js.map +0 -10
  88. package/dist/chunk-f4c9ttmr.js +0 -154
  89. package/dist/chunk-mp5c9bfd.js +0 -270
  90. package/dist/chunk-mp5c9bfd.js.map +0 -11
  91. package/dist/chunk-tymfm441.js +0 -405
  92. package/dist/chunk-tymfm441.js.map +0 -11
  93. package/dist/chunk-v0bahtg2.js +0 -6
  94. package/dist/chunk-x3szga4k.js +0 -367
  95. package/dist/chunk-x3szga4k.js.map +0 -11
  96. package/dist/chunk-ym3zzv8b.js +0 -74
  97. package/dist/chunk-ym3zzv8b.js.map +0 -10
package/dist/detect.js CHANGED
@@ -1,181 +1,3 @@
1
- import {
2
- SMTPPool
3
- } from "./chunk-mp5c9bfd.js";
4
- import {
5
- SMTPTransport
6
- } from "./chunk-7fqv71z1.js";
7
- import"./chunk-ym3zzv8b.js";
8
- import"./chunk-x3szga4k.js";
9
- import"./chunk-tymfm441.js";
10
- import"./chunk-f4c9ttmr.js";
11
- import"./chunk-794hc3m4.js";
12
- import {
13
- __require
14
- } from "./chunk-v0bahtg2.js";
1
+ import{q as z,r as w}from"./chunk-2kcwa9gt.js";import{I as v}from"./chunk-sqn04kae.js";function K(){if(typeof Bun<"u")return"bun";if(typeof Deno<"u")return"deno";if(typeof caches<"u"&&globalThis.navigator?.userAgent==="Cloudflare-Workers")return"cf-workers";if(typeof window<"u")return"browser";if(typeof process<"u"&&process.versions?.node)return"node";return"unknown"}async function x(k){let h=K();switch(h){case"node":{let{NodeAdapter:q}=await import("./adapters/node.js");return new q(k)}case"bun":{let{BunAdapter:q}=await import("./adapters/bun.js");return new q(k)}case"deno":{let{DenoAdapter:q}=await import("./adapters/deno.js");return new q(k)}case"cf-workers":{let{CloudflareAdapter:q}=await import("./adapters/cf.js");return new q(k)}default:throw Error(`No socket adapter available for runtime: ${h}`)}}async function Q(k){if("transport"in k)return z({transport:k.transport,...k.plugins!==void 0?{plugins:k.plugins}:{}});let h=k,q={...h.secure!==void 0?{secure:h.secure}:{},...h.connectionTimeout!==void 0?{connectionTimeout:h.connectionTimeout}:{},...h.tls!==void 0?{tls:h.tls}:{}};if(h.pool){let{SMTPPool:J}=await import("./pool/pool.js");return new w(new J(h,{createAdapter:async()=>h.adapter??await x(q)}),h.plugins)}let E=h.adapter??await x(q),{SMTPTransport:G}=await import("./transports/smtp.js");return new w(new G({...h,adapter:E}),h.plugins)}export{K as detectRuntime,Q as createMailer,x as createDefaultAdapter};
15
2
 
16
- // src/core/plugin.ts
17
- async function runPlugins(options, plugins) {
18
- if (!plugins || plugins.length === 0) {
19
- return options;
20
- }
21
- let current = options;
22
- for (const plugin of plugins) {
23
- current = await plugin(current);
24
- }
25
- return current;
26
- }
27
-
28
- // src/detect.ts
29
- function detectRuntime() {
30
- if (typeof Bun !== "undefined") {
31
- return "bun";
32
- }
33
- if (typeof Deno !== "undefined") {
34
- return "deno";
35
- }
36
- if (typeof caches !== "undefined" && globalThis.navigator?.userAgent === "Cloudflare-Workers") {
37
- return "cf-workers";
38
- }
39
- if (typeof window !== "undefined") {
40
- return "browser";
41
- }
42
- if (typeof process !== "undefined" && process.versions?.node) {
43
- return "node";
44
- }
45
- return "unknown";
46
- }
47
- async function createDefaultAdapter(options) {
48
- const runtime = detectRuntime();
49
- switch (runtime) {
50
- case "node": {
51
- const { NodeAdapter } = await import("./adapters/node.js");
52
- return new NodeAdapter(options);
53
- }
54
- case "bun": {
55
- const { BunAdapter } = await import("./adapters/bun.js");
56
- return new BunAdapter(options);
57
- }
58
- case "deno": {
59
- const { DenoAdapter } = await import("./adapters/deno.js");
60
- return new DenoAdapter(options);
61
- }
62
- case "cf-workers": {
63
- const { CloudflareAdapter } = await import("./adapters/cf.js");
64
- return new CloudflareAdapter(options);
65
- }
66
- default:
67
- throw new Error(`No socket adapter available for runtime: ${runtime}`);
68
- }
69
- }
70
- async function createMailer(options) {
71
- if ("transport" in options) {
72
- return new MailerImpl(options.transport, options.plugins ?? []);
73
- }
74
- const smtpConfig = options;
75
- if (smtpConfig.pool) {
76
- return new MailerImpl(new SMTPPool(smtpConfig, {
77
- createAdapter: async () => smtpConfig.adapter ?? await createDefaultAdapter({
78
- ...smtpConfig.secure !== undefined ? { secure: smtpConfig.secure } : {},
79
- ...smtpConfig.connectionTimeout !== undefined ? { connectionTimeout: smtpConfig.connectionTimeout } : {},
80
- ...smtpConfig.tls !== undefined ? { tls: smtpConfig.tls } : {}
81
- })
82
- }), smtpConfig.plugins);
83
- }
84
- const adapter = smtpConfig.adapter ?? await createDefaultAdapter({
85
- ...smtpConfig.secure !== undefined ? { secure: smtpConfig.secure } : {},
86
- ...smtpConfig.connectionTimeout !== undefined ? { connectionTimeout: smtpConfig.connectionTimeout } : {},
87
- ...smtpConfig.tls !== undefined ? { tls: smtpConfig.tls } : {}
88
- });
89
- return new MailerImpl(new SMTPTransport({ ...smtpConfig, adapter }), smtpConfig.plugins);
90
- }
91
-
92
- class MailerImpl {
93
- transport;
94
- plugins;
95
- constructor(transport, plugins = []) {
96
- this.transport = transport;
97
- this.plugins = plugins;
98
- }
99
- async send(options) {
100
- const processed = await runPlugins(options, this.plugins);
101
- return this.transport.send(processed);
102
- }
103
- async sendBulk(messages, options) {
104
- const concurrency = options?.concurrency ?? 1;
105
- const results = new Array(messages.length);
106
- const queue = [...messages.entries()];
107
- let active = 0;
108
- await new Promise((resolve) => {
109
- if (messages.length === 0) {
110
- resolve();
111
- return;
112
- }
113
- const maybeDone = () => {
114
- if (queue.length === 0 && active === 0) {
115
- resolve();
116
- }
117
- };
118
- const processNext = () => {
119
- if (queue.length === 0) {
120
- maybeDone();
121
- return;
122
- }
123
- const entry = queue.shift();
124
- if (entry === undefined) {
125
- maybeDone();
126
- return;
127
- }
128
- const [index, message] = entry;
129
- active++;
130
- this.send(message).then((result) => {
131
- results[index] = { status: "sent", result };
132
- options?.onSuccess?.(message, index, result);
133
- }).catch((error) => {
134
- results[index] = { status: "failed", error };
135
- options?.onError?.(message, index, error);
136
- }).finally(() => {
137
- active--;
138
- processNext();
139
- maybeDone();
140
- });
141
- };
142
- for (let i = 0;i < concurrency; i++) {
143
- processNext();
144
- }
145
- });
146
- let sent = 0;
147
- let failed = 0;
148
- for (const result of results) {
149
- if (result.status === "sent") {
150
- sent++;
151
- } else {
152
- failed++;
153
- }
154
- }
155
- return {
156
- total: messages.length,
157
- sent,
158
- failed,
159
- results
160
- };
161
- }
162
- verify() {
163
- if (this.transport.verify) {
164
- return this.transport.verify();
165
- }
166
- return Promise.resolve({ ok: true, provider: "mailer" });
167
- }
168
- close() {
169
- if (this.transport.close) {
170
- return this.transport.close();
171
- }
172
- return Promise.resolve();
173
- }
174
- }
175
- export {
176
- detectRuntime,
177
- createMailer,
178
- createDefaultAdapter
179
- };
180
-
181
- //# debugId=685AB5DE4D1E74D864756E2164756E21
3
+ //# debugId=1210DC19744F68B364756E2164756E21
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/core/plugin.ts", "../src/detect.ts"],
3
+ "sources": ["../src/detect.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * @module\n * Plugin pipeline for sently.\n * Plugins transform MailOptions before message construction.\n * They run sequentially each receives the previous plugin's output.\n *\n * @example\n * ```ts\n * import { runPlugins } from \"sently/core/plugin\";\n * const result = await runPlugins(options, [pluginA, pluginB]);\n * ```\n */\nimport type { MailOptions, MailPlugin } from \"./types.js\";\n\n/**\n * Run a list of plugins sequentially over MailOptions.\n * If plugins is empty or undefined, returns options unchanged.\n * Each plugin may be sync or async.\n *\n * @param options - the original mail options\n * @param plugins - ordered list of plugins to apply\n * @returns transformed mail options after all plugins have run\n */\nexport async function runPlugins(\n options: MailOptions,\n plugins: MailPlugin[] | undefined,\n): Promise<MailOptions> {\n if (!plugins || plugins.length === 0) {\n return options;\n }\n\n let current = options;\n for (const plugin of plugins) {\n current = await plugin(current);\n }\n return current;\n}\n",
6
- "// src/detect.ts\nimport { runPlugins } from \"./core/plugin.js\";\nimport type {\n BulkSendOptions,\n BulkSendResult,\n CreateMailerOptions,\n Mailer,\n MailOptions,\n MailPlugin,\n Runtime,\n SendResult,\n SMTPConfig,\n SocketAdapter,\n TLSOptions,\n Transport,\n VerifyResult,\n} from \"./core/types.js\";\nimport { SMTPPool } from \"./pool/pool.js\";\nimport { SMTPTransport } from \"./transports/smtp.js\";\n\n/** Detect the current JavaScript runtime. */\nexport function detectRuntime(): Runtime {\n if (typeof Bun !== \"undefined\") {\n return \"bun\";\n }\n if (typeof Deno !== \"undefined\") {\n return \"deno\";\n }\n if (typeof caches !== \"undefined\" && globalThis.navigator?.userAgent === \"Cloudflare-Workers\") {\n return \"cf-workers\";\n }\n if (typeof window !== \"undefined\") {\n return \"browser\";\n }\n if (typeof process !== \"undefined\" && process.versions?.node) {\n return \"node\";\n }\n return \"unknown\";\n}\n\n/**\n * Dynamically import and instantiate the correct adapter for the current runtime.\n */\nexport async function createDefaultAdapter(options?: {\n secure?: boolean;\n connectionTimeout?: number;\n tls?: TLSOptions;\n}): Promise<SocketAdapter> {\n const runtime = detectRuntime();\n\n switch (runtime) {\n case \"node\": {\n const { NodeAdapter } = await import(\"./adapters/node.js\");\n return new NodeAdapter(options);\n }\n case \"bun\": {\n const { BunAdapter } = await import(\"./adapters/bun.js\");\n return new BunAdapter(options);\n }\n case \"deno\": {\n const { DenoAdapter } = await import(\"./adapters/deno.js\");\n return new DenoAdapter(options);\n }\n case \"cf-workers\": {\n const { CloudflareAdapter } = await import(\"./adapters/cf.js\");\n return new CloudflareAdapter(options);\n }\n default:\n throw new Error(`No socket adapter available for runtime: ${runtime}`);\n }\n}\n\n/**\n * Create a ready-to-use Mailer instance.\n */\nexport async function createMailer(options: CreateMailerOptions): Promise<Mailer> {\n if (\"transport\" in options) {\n return new MailerImpl(options.transport, options.plugins ?? []);\n }\n\n const smtpConfig = options as SMTPConfig;\n\n if (smtpConfig.pool) {\n return new MailerImpl(\n new SMTPPool(smtpConfig, {\n createAdapter: async () =>\n smtpConfig.adapter ??\n (await createDefaultAdapter({\n ...(smtpConfig.secure !== undefined ? { secure: smtpConfig.secure } : {}),\n ...(smtpConfig.connectionTimeout !== undefined\n ? { connectionTimeout: smtpConfig.connectionTimeout }\n : {}),\n ...(smtpConfig.tls !== undefined ? { tls: smtpConfig.tls } : {}),\n })),\n }),\n smtpConfig.plugins,\n );\n }\n\n const adapter =\n smtpConfig.adapter ??\n (await createDefaultAdapter({\n ...(smtpConfig.secure !== undefined ? { secure: smtpConfig.secure } : {}),\n ...(smtpConfig.connectionTimeout !== undefined\n ? { connectionTimeout: smtpConfig.connectionTimeout }\n : {}),\n ...(smtpConfig.tls !== undefined ? { tls: smtpConfig.tls } : {}),\n }));\n\n return new MailerImpl(new SMTPTransport({ ...smtpConfig, adapter }), smtpConfig.plugins);\n}\n\nclass MailerImpl implements Mailer {\n constructor(\n private readonly transport: Transport,\n private readonly plugins: MailPlugin[] = [],\n ) {}\n\n async send(options: MailOptions): Promise<SendResult> {\n const processed = await runPlugins(options, this.plugins);\n return this.transport.send(processed);\n }\n\n async sendBulk(messages: MailOptions[], options?: BulkSendOptions): Promise<BulkSendResult> {\n const concurrency = options?.concurrency ?? 1;\n const results: BulkSendResult[\"results\"] = new Array(messages.length);\n const queue = [...messages.entries()];\n let active = 0;\n\n await new Promise<void>((resolve) => {\n if (messages.length === 0) {\n resolve();\n return;\n }\n\n const maybeDone = (): void => {\n if (queue.length === 0 && active === 0) {\n resolve();\n }\n };\n\n const processNext = (): void => {\n if (queue.length === 0) {\n maybeDone();\n return;\n }\n\n const entry = queue.shift();\n if (entry === undefined) {\n maybeDone();\n return;\n }\n\n const [index, message] = entry;\n active++;\n\n void this.send(message)\n .then((result) => {\n results[index] = { status: \"sent\", result };\n options?.onSuccess?.(message, index, result);\n })\n .catch((error: unknown) => {\n results[index] = { status: \"failed\", error };\n options?.onError?.(message, index, error);\n })\n .finally(() => {\n active--;\n processNext();\n maybeDone();\n });\n };\n\n for (let i = 0; i < concurrency; i++) {\n processNext();\n }\n });\n\n let sent = 0;\n let failed = 0;\n for (const result of results) {\n if (result.status === \"sent\") {\n sent++;\n } else {\n failed++;\n }\n }\n\n return {\n total: messages.length,\n sent,\n failed,\n results,\n };\n }\n\n verify(): Promise<VerifyResult> {\n if (this.transport.verify) {\n return this.transport.verify();\n }\n return Promise.resolve({ ok: true, provider: \"mailer\" });\n }\n\n close(): Promise<void> {\n if (this.transport.close) {\n return this.transport.close();\n }\n return Promise.resolve();\n }\n}\n\ndeclare const Bun: unknown;\ndeclare const Deno: unknown;\n"
5
+ "// src/detect.ts\nimport type {\n CreateMailerOptions,\n Mailer,\n Runtime,\n SMTPConfig,\n SocketAdapter,\n TLSOptions,\n} from \"./core/types.js\";\nimport { createMailer as createTransportMailer, MailerImpl } from \"./mailer.js\";\n\n/** Detect the current JavaScript runtime. */\nexport function detectRuntime(): Runtime {\n if (typeof Bun !== \"undefined\") {\n return \"bun\";\n }\n if (typeof Deno !== \"undefined\") {\n return \"deno\";\n }\n if (typeof caches !== \"undefined\" && globalThis.navigator?.userAgent === \"Cloudflare-Workers\") {\n return \"cf-workers\";\n }\n if (typeof window !== \"undefined\") {\n return \"browser\";\n }\n if (typeof process !== \"undefined\" && process.versions?.node) {\n return \"node\";\n }\n return \"unknown\";\n}\n\n/**\n * Dynamically import and instantiate the correct adapter for the current runtime.\n */\nexport async function createDefaultAdapter(options?: {\n secure?: boolean;\n connectionTimeout?: number;\n tls?: TLSOptions;\n}): Promise<SocketAdapter> {\n const runtime = detectRuntime();\n\n switch (runtime) {\n case \"node\": {\n const { NodeAdapter } = await import(\"./adapters/node.js\");\n return new NodeAdapter(options);\n }\n case \"bun\": {\n const { BunAdapter } = await import(\"./adapters/bun.js\");\n return new BunAdapter(options);\n }\n case \"deno\": {\n const { DenoAdapter } = await import(\"./adapters/deno.js\");\n return new DenoAdapter(options);\n }\n case \"cf-workers\": {\n const { CloudflareAdapter } = await import(\"./adapters/cf.js\");\n return new CloudflareAdapter(options);\n }\n default:\n throw new Error(`No socket adapter available for runtime: ${runtime}`);\n }\n}\n\n/**\n * Create a ready-to-use Mailer instance.\n *\n * For HTTP transports and smallest bundles, prefer `import { createMailer } from \"sently/mailer\"`.\n */\nexport async function createMailer(options: CreateMailerOptions): Promise<Mailer> {\n if (\"transport\" in options) {\n return createTransportMailer({\n transport: options.transport,\n ...(options.plugins !== undefined ? { plugins: options.plugins } : {}),\n });\n }\n\n const smtpConfig = options as SMTPConfig;\n const adapterOptions = {\n ...(smtpConfig.secure !== undefined ? { secure: smtpConfig.secure } : {}),\n ...(smtpConfig.connectionTimeout !== undefined\n ? { connectionTimeout: smtpConfig.connectionTimeout }\n : {}),\n ...(smtpConfig.tls !== undefined ? { tls: smtpConfig.tls } : {}),\n };\n\n if (smtpConfig.pool) {\n const { SMTPPool } = await import(\"./pool/pool.js\");\n return new MailerImpl(\n new SMTPPool(smtpConfig, {\n createAdapter: async () =>\n smtpConfig.adapter ?? (await createDefaultAdapter(adapterOptions)),\n }),\n smtpConfig.plugins,\n );\n }\n\n const adapter = smtpConfig.adapter ?? (await createDefaultAdapter(adapterOptions));\n const { SMTPTransport } = await import(\"./transports/smtp.js\");\n\n return new MailerImpl(new SMTPTransport({ ...smtpConfig, adapter }), smtpConfig.plugins);\n}\n\ndeclare const Bun: unknown;\ndeclare const Deno: unknown;\n"
7
6
  ],
8
- "mappings": "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",
9
- "debugId": "685AB5DE4D1E74D864756E2164756E21",
7
+ "mappings": "6FAYO,GAAS,CAAa,EAAY,CACvC,GAAI,OAAO,IAAQ,IACjB,MAAO,MAET,GAAI,OAAO,KAAS,IAClB,MAAO,OAET,GAAI,OAAO,OAAW,KAAe,WAAW,WAAW,YAAc,qBACvE,MAAO,aAET,GAAI,OAAO,OAAW,IACpB,MAAO,UAET,GAAI,OAAO,QAAY,KAAe,QAAQ,UAAU,KACtD,MAAO,OAET,MAAO,UAMT,eAAsB,CAAoB,CAAC,EAIhB,CACzB,IAAM,EAAU,EAAc,EAE9B,OAAQ,OACD,OAAQ,CACX,IAAQ,eAAgB,KAAa,8BACrC,OAAO,IAAI,EAAY,CAAO,CAChC,KACK,MAAO,CACV,IAAQ,cAAe,KAAa,6BACpC,OAAO,IAAI,EAAW,CAAO,CAC/B,KACK,OAAQ,CACX,IAAQ,eAAgB,KAAa,8BACrC,OAAO,IAAI,EAAY,CAAO,CAChC,KACK,aAAc,CACjB,IAAQ,qBAAsB,KAAa,4BAC3C,OAAO,IAAI,EAAkB,CAAO,CACtC,SAEE,MAAU,MAAM,4CAA4C,GAAS,GAS3E,eAAsB,CAAY,CAAC,EAA+C,CAChF,GAAI,cAAe,EACjB,OAAO,EAAsB,CAC3B,UAAW,EAAQ,aACf,EAAQ,UAAY,OAAY,CAAE,QAAS,EAAQ,OAAQ,EAAI,CAAC,CACtE,CAAC,EAGH,IAAM,EAAa,EACb,EAAiB,IACjB,EAAW,SAAW,OAAY,CAAE,OAAQ,EAAW,MAAO,EAAI,CAAC,KACnE,EAAW,oBAAsB,OACjC,CAAE,kBAAmB,EAAW,iBAAkB,EAClD,CAAC,KACD,EAAW,MAAQ,OAAY,CAAE,IAAK,EAAW,GAAI,EAAI,CAAC,CAChE,EAEA,GAAI,EAAW,KAAM,CACnB,IAAQ,YAAa,KAAa,0BAClC,OAAO,IAAI,EACT,IAAI,EAAS,EAAY,CACvB,cAAe,SACb,EAAW,SAAY,MAAM,EAAqB,CAAc,CACpE,CAAC,EACD,EAAW,OACb,EAGF,IAAM,EAAU,EAAW,SAAY,MAAM,EAAqB,CAAc,GACxE,iBAAkB,KAAa,gCAEvC,OAAO,IAAI,EAAW,IAAI,EAAc,IAAK,EAAY,SAAQ,CAAC,EAAG,EAAW,OAAO",
8
+ "debugId": "1210DC19744F68B364756E2164756E21",
10
9
  "names": []
11
10
  }
package/dist/dkim.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @module
3
+ * DKIM (DomainKeys Identified Mail) signing per RFC 6376.
4
+ * Supports RSA-SHA256 and Ed25519-SHA256 using Web Crypto.
5
+ *
6
+ * Import from this entry when signing mail explicitly. MIME building lazy-loads
7
+ * DKIM only when a `dkim` option is passed to {@link buildMIME}.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { signDKIM } from "sently/dkim";
12
+ *
13
+ * const { header } = await signDKIM(rawMessage, {
14
+ * domainName: "example.com",
15
+ * keySelector: "2024",
16
+ * privateKey: process.env.DKIM_PRIVATE_KEY!,
17
+ * });
18
+ * ```
19
+ */
20
+ export type { DKIMSignResult } from "./core/dkim.js";
21
+ export { canonicalizeBodyRelaxed, canonicalizeHeadersRelaxed, importPrivateKey, signDKIM, } from "./core/dkim.js";
package/dist/dkim.js ADDED
@@ -0,0 +1,9 @@
1
+ import{E as G,H as E}from"./chunk-6yggz45h.js";import"./chunk-sqn04kae.js";var j=`\r
2
+ `,C="from:to:subject:date:message-id:mime-version:content-type";function _(M,I){let x=F(M),K=[];for(let S of I){let Y=S.toLowerCase().trim(),z=x.get(Y);if(!z)continue;for(let D of z){let w=D.replace(/\r?\n/g,"").replace(/\s+/g," ").trim();K.push(`${Y}:${w}`)}}return K.length>0?`${K.join(j)}${j}`:""}function $(M){let x=M.replace(/\r\n/g,`
3
+ `).replace(/\r/g,`
4
+ `).split(`
5
+ `).map((K)=>K.replace(/[ \t]+$/g,"").replace(/[ \t]+/g," ")).filter((K)=>K.length>0);if(x.length===0)return j;return`${x.join(j)}${j}`}async function v(M,I){if(I==="ed25519-sha256"&&/OPENSSH PRIVATE KEY/i.test(M))throw Error("Ed25519 keys must be in PKCS#8 PEM format (-----BEGIN PRIVATE KEY-----). Convert with: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key_pkcs8.pem");let x=B(M),K=J(x);try{if(I==="ed25519-sha256")return await crypto.subtle.importKey("pkcs8",K,{name:"Ed25519"},!1,["sign"]);return await crypto.subtle.importKey("pkcs8",K,{name:"RSASSA-PKCS1-v1_5",hash:"SHA-256"},!1,["sign"])}catch(S){if(I==="ed25519-sha256"&&S instanceof DOMException)throw Error("Ed25519 DKIM requires Node.js ≥ 18.4, Bun ≥ 1.0, or Cloudflare Workers",{cause:S});throw S}}async function N(M,I){let x=I.algorithm??"rsa-sha256",K=(I.headerFieldNames??C).split(":").map((q)=>q.trim().toLowerCase()).filter(Boolean),S=new Set((I.skipFields??"").split(":").map((q)=>q.trim().toLowerCase()).filter(Boolean)),Y=K.filter((q)=>!S.has(q)),z=new TextDecoder().decode(M),D=z.indexOf(`\r
6
+ \r
7
+ `),w=D>=0?z.slice(0,D):z,P=D>=0?z.slice(D+4):"",T=$(P),O=await k(E(T)),Q=x==="ed25519-sha256"?"ed25519-sha256":"rsa-sha256",X=Y.join(":"),Z=Math.floor(Date.now()/1000),W=["v=1",`a=${Q}`,"c=relaxed/relaxed",`d=${I.domainName}`,`s=${I.keySelector}`,`h=${X}`,`bh=${O}`,"b=",`t=${Z}`].join("; "),b="dkim-signature",H=`${w}${j}dkim-signature:${W}`,p=_(H,[...Y,"dkim-signature"]),A=await v(I.privateKey,x),R=E(p),U=await L(A,R,x),V=G(U).replace(/\r\n/g,"");return{header:`DKIM-Signature: v=1; a=${Q}; c=relaxed/relaxed; d=${I.domainName}; s=${I.keySelector}; h=${X}; bh=${O}; b=${V}; t=${Z}`}}function F(M){let I=new Map,x=M.split(/\r?\n/).filter((z)=>z.length>0),K="",S="",Y=()=>{if(!K)return;let z=K.toLowerCase(),D=I.get(z)??[];D.push(S),I.set(z,D),K="",S=""};for(let z of x){if(/^[ \t]/.test(z)&&K){S+=` ${z.trim()}`;continue}Y();let D=z.indexOf(":");if(D>0)K=z.slice(0,D).trim(),S=z.slice(D+1).trim()}return Y(),I}function B(M){let I=M.replace(/-----BEGIN[^-]+-----/g,"").replace(/-----END[^-]+-----/g,"").replace(/\s/g,""),x=atob(I),K=new Uint8Array(x.length);for(let S=0;S<x.length;S++)K[S]=x.charCodeAt(S);return K}function J(M){return M.buffer.slice(M.byteOffset,M.byteOffset+M.byteLength)}async function k(M){let I=await crypto.subtle.digest("SHA-256",J(M));return G(new Uint8Array(I)).replace(/\r\n/g,"")}async function L(M,I,x){let K=J(I);if(x==="ed25519-sha256"){let Y=await crypto.subtle.sign("Ed25519",M,K);return new Uint8Array(Y)}let S=await crypto.subtle.sign({name:"RSASSA-PKCS1-v1_5"},M,K);return new Uint8Array(S)}export{N as signDKIM,v as importPrivateKey,_ as canonicalizeHeadersRelaxed,$ as canonicalizeBodyRelaxed};
8
+
9
+ //# debugId=6C34EDE3095573A464756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/core/dkim.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * DKIM signing implementation (RFC 6376). Public entry: `sently/dkim`.\n */\nimport { encodeBase64, encodeUtf8 } from \"./base64.js\";\nimport type { DKIMConfig } from \"./types.js\";\n\nconst CRLF = \"\\r\\n\";\nconst DEFAULT_HEADER_FIELDS = \"from:to:subject:date:message-id:mime-version:content-type\";\n\n/** Result of DKIM signing — the header line to prepend. */\nexport interface DKIMSignResult {\n /** Complete DKIM-Signature header line (without trailing CRLF). */\n header: string;\n}\n\n/**\n * Canonicalize headers using the relaxed algorithm (RFC 6376 §3.4.2).\n */\nexport function canonicalizeHeadersRelaxed(headers: string, fieldNames: string[]): string {\n const parsed = parseHeaders(headers);\n const lines: string[] = [];\n\n for (const name of fieldNames) {\n const key = name.toLowerCase().trim();\n const values = parsed.get(key);\n if (!values) {\n continue;\n }\n for (const value of values) {\n const unfolded = value.replace(/\\r?\\n/g, \"\").replace(/\\s+/g, \" \").trim();\n lines.push(`${key}:${unfolded}`);\n }\n }\n\n return lines.length > 0 ? `${lines.join(CRLF)}${CRLF}` : \"\";\n}\n\n/**\n * Canonicalize body using the relaxed algorithm (RFC 6376 §3.4.4).\n */\nexport function canonicalizeBodyRelaxed(body: string): string {\n const normalized = body.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n const lines = normalized\n .split(\"\\n\")\n .map((line) => line.replace(/[ \\t]+$/g, \"\").replace(/[ \\t]+/g, \" \"))\n .filter((line) => line.length > 0);\n if (lines.length === 0) {\n return CRLF;\n }\n return `${lines.join(CRLF)}${CRLF}`;\n}\n\n/**\n * Import a PEM-encoded private key into a Web Crypto CryptoKey.\n */\nexport async function importPrivateKey(\n pem: string,\n algorithm: \"rsa-sha256\" | \"ed25519-sha256\",\n): Promise<CryptoKey> {\n if (algorithm === \"ed25519-sha256\" && /OPENSSH PRIVATE KEY/i.test(pem)) {\n throw new Error(\n \"Ed25519 keys must be in PKCS#8 PEM format (-----BEGIN PRIVATE KEY-----). Convert with: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key_pkcs8.pem\",\n );\n }\n\n const der = pemToDer(pem);\n\n const derBuffer = toArrayBuffer(der);\n\n try {\n if (algorithm === \"ed25519-sha256\") {\n return await crypto.subtle.importKey(\"pkcs8\", derBuffer, { name: \"Ed25519\" }, false, [\n \"sign\",\n ]);\n }\n return await crypto.subtle.importKey(\n \"pkcs8\",\n derBuffer,\n { name: \"RSASSA-PKCS1-v1_5\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n } catch (err) {\n if (algorithm === \"ed25519-sha256\" && err instanceof DOMException) {\n throw new Error(\"Ed25519 DKIM requires Node.js ≥ 18.4, Bun ≥ 1.0, or Cloudflare Workers\", {\n cause: err,\n });\n }\n throw err;\n }\n}\n\n/**\n * Sign a raw MIME message with DKIM.\n */\nexport async function signDKIM(\n rawMessage: Uint8Array,\n config: DKIMConfig,\n): Promise<DKIMSignResult> {\n const algorithm = config.algorithm ?? \"rsa-sha256\";\n const fieldList = (config.headerFieldNames ?? DEFAULT_HEADER_FIELDS)\n .split(\":\")\n .map((f) => f.trim().toLowerCase())\n .filter(Boolean);\n const skip = new Set(\n (config.skipFields ?? \"\")\n .split(\":\")\n .map((f) => f.trim().toLowerCase())\n .filter(Boolean),\n );\n const signFields = fieldList.filter((f) => !skip.has(f));\n\n const text = new TextDecoder().decode(rawMessage);\n const sep = text.indexOf(\"\\r\\n\\r\\n\");\n const headerPart = sep >= 0 ? text.slice(0, sep) : text;\n const bodyPart = sep >= 0 ? text.slice(sep + 4) : \"\";\n\n const bodyCanonical = canonicalizeBodyRelaxed(bodyPart);\n const bodyHash = await sha256Base64(encodeUtf8(bodyCanonical));\n\n const dkimAlgo = algorithm === \"ed25519-sha256\" ? \"ed25519-sha256\" : \"rsa-sha256\";\n const headerList = signFields.join(\":\");\n const timestamp = Math.floor(Date.now() / 1000);\n\n const dkimWithoutSig = [\n `v=1`,\n `a=${dkimAlgo}`,\n `c=relaxed/relaxed`,\n `d=${config.domainName}`,\n `s=${config.keySelector}`,\n `h=${headerList}`,\n `bh=${bodyHash}`,\n `b=`,\n `t=${timestamp}`,\n ].join(\"; \");\n\n const dkimHeaderName = \"dkim-signature\";\n const dkimHeaderValue = dkimWithoutSig;\n const headersWithDkim = `${headerPart}${CRLF}${dkimHeaderName}:${dkimHeaderValue}`;\n const canonical = canonicalizeHeadersRelaxed(headersWithDkim, [...signFields, dkimHeaderName]);\n\n const key = await importPrivateKey(config.privateKey, algorithm);\n const data = encodeUtf8(canonical);\n const signature = await signData(key, data, algorithm);\n const bValue = encodeBase64(signature).replace(/\\r\\n/g, \"\");\n\n const header = `DKIM-Signature: v=1; a=${dkimAlgo}; c=relaxed/relaxed; d=${config.domainName}; s=${config.keySelector}; h=${headerList}; bh=${bodyHash}; b=${bValue}; t=${timestamp}`;\n\n return { header };\n}\n\nfunction parseHeaders(headerBlock: string): Map<string, string[]> {\n const map = new Map<string, string[]>();\n const lines = headerBlock.split(/\\r?\\n/).filter((l) => l.length > 0);\n let currentName = \"\";\n let currentValue = \"\";\n\n const flush = (): void => {\n if (!currentName) {\n return;\n }\n const key = currentName.toLowerCase();\n const list = map.get(key) ?? [];\n list.push(currentValue);\n map.set(key, list);\n currentName = \"\";\n currentValue = \"\";\n };\n\n for (const line of lines) {\n if (/^[ \\t]/.test(line) && currentName) {\n currentValue += ` ${line.trim()}`;\n continue;\n }\n flush();\n const colon = line.indexOf(\":\");\n if (colon > 0) {\n currentName = line.slice(0, colon).trim();\n currentValue = line.slice(colon + 1).trim();\n }\n }\n flush();\n return map;\n}\n\nfunction pemToDer(pem: string): Uint8Array {\n const lines = pem\n .replace(/-----BEGIN[^-]+-----/g, \"\")\n .replace(/-----END[^-]+-----/g, \"\")\n .replace(/\\s/g, \"\");\n const binary = atob(lines);\n const der = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n der[i] = binary.charCodeAt(i);\n }\n return der;\n}\n\nfunction toArrayBuffer(bytes: Uint8Array): ArrayBuffer {\n return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer;\n}\n\nasync function sha256Base64(data: Uint8Array): Promise<string> {\n const hash = await crypto.subtle.digest(\"SHA-256\", toArrayBuffer(data));\n return encodeBase64(new Uint8Array(hash)).replace(/\\r\\n/g, \"\");\n}\n\nasync function signData(\n key: CryptoKey,\n data: Uint8Array,\n algorithm: \"rsa-sha256\" | \"ed25519-sha256\",\n): Promise<Uint8Array> {\n const buf = toArrayBuffer(data);\n if (algorithm === \"ed25519-sha256\") {\n const sig = await crypto.subtle.sign(\"Ed25519\", key, buf);\n return new Uint8Array(sig);\n }\n const sig = await crypto.subtle.sign({ name: \"RSASSA-PKCS1-v1_5\" }, key, buf);\n return new Uint8Array(sig);\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "6C34EDE3095573A464756E2164756E21",
9
+ "names": []
10
+ }
package/dist/index.d.ts CHANGED
@@ -19,19 +19,77 @@
19
19
  * });
20
20
  * ```
21
21
  */
22
- export { GOOGLE_TOKEN_URL, MICROSOFT_TOKEN_URL, OAuth2Client } from "./auth/oauth2.js";
23
- export { SMTPError } from "./core/smtp.js";
24
- export type { Address, AddressInput, Attachment, BrevoConfig, BulkSendOptions, BulkSendResult, CreateMailerOptions, DKIMConfig, Envelope, Mailer, MailgunConfig, MailOptions, MailPlugin, OAuth2Config, PoolConfig, PreviewConfig, RetryConfig, Runtime, SESConfig, SendResult, SMTPAuth, SMTPConfig, SocketAdapter, TLSOptions, Transport, VerifyResult, } from "./core/types.js";
25
- export { createMailer, detectRuntime } from "./detect.js";
26
- export type { TemplateEngine, TemplatePluginConfig } from "./plugins/template.js";
27
- export { simpleEngine, templatePlugin } from "./plugins/template.js";
28
- export { SMTPPool } from "./pool/pool.js";
29
- export { BrevoError, BrevoTransport } from "./transports/brevo.js";
30
- export { MailgunError, MailgunTransport } from "./transports/mailgun.js";
31
- export { PostmarkError, PostmarkTransport } from "./transports/postmark.js";
32
- export { PreviewTransport } from "./transports/preview.js";
33
- export { ResendError, ResendTransport } from "./transports/resend.js";
34
- export { RetryTransport } from "./transports/retry.js";
35
- export { SendGridError, SendGridTransport } from "./transports/sendgrid.js";
36
- export { SESError, SESTransport } from "./transports/ses.js";
37
- export { SMTPTransport } from "./transports/smtp.js";
22
+ export {
23
+ /** Default Google OAuth2 token endpoint. */
24
+ GOOGLE_TOKEN_URL,
25
+ /** Microsoft OAuth2 token endpoint (common tenant). */
26
+ MICROSOFT_TOKEN_URL,
27
+ /** OAuth2 client with in-memory token cache and automatic refresh. */
28
+ OAuth2Client, } from "./auth/oauth2.js";
29
+ export {
30
+ /** SMTP protocol error with server response details. */
31
+ SMTPError, } from "./core/smtp.js";
32
+ export type { Address, AddressInput, Attachment, BrevoConfig, BulkSendOptions, BulkSendResult, CreateMailerOptions, DKIMConfig, Envelope, Mailer, MailgunConfig, MailOptions, MailPlugin, OAuth2Config, PoolConfig, PreviewConfig, RetryConfig, Runtime, SESConfig, SendResult, SMTPAuth, SMTPConfig, SocketAdapter, TLSOptions, Transport, TransportMailerOptions, VerifyResult, } from "./core/types.js";
33
+ export {
34
+ /** Create a ready-to-use Mailer instance. */
35
+ createMailer,
36
+ /** Detect the current JavaScript runtime. */
37
+ detectRuntime, } from "./detect.js";
38
+ export type { DKIMSignResult } from "./dkim.js";
39
+ export {
40
+ /** Import a PEM private key for DKIM signing. */
41
+ importPrivateKey,
42
+ /** Sign a raw MIME message with DKIM (RFC 6376). */
43
+ signDKIM, } from "./dkim.js";
44
+ export type {
45
+ /** Renders a template string with the given data object. */
46
+ TemplateEngine,
47
+ /** Configuration for the template plugin. */
48
+ TemplatePluginConfig, } from "./plugins/template.js";
49
+ export {
50
+ /** Built-in zero-dependency template engine using `{{variable}}` interpolation. */
51
+ simpleEngine,
52
+ /** Create a template plugin that renders HTML from a named template and data. */
53
+ templatePlugin, } from "./plugins/template.js";
54
+ export {
55
+ /** SMTP connection pool with optional rate limiting. */
56
+ SMTPPool, } from "./pool/pool.js";
57
+ export {
58
+ /** Error thrown when the Brevo API returns a non-success response. */
59
+ BrevoError,
60
+ /** Brevo HTTP API transport. */
61
+ BrevoTransport, } from "./transports/brevo.js";
62
+ export {
63
+ /** Error thrown when the Mailgun API returns a non-success response. */
64
+ MailgunError,
65
+ /** Mailgun HTTP API transport (multipart/form-data). */
66
+ MailgunTransport, } from "./transports/mailgun.js";
67
+ export {
68
+ /** Error thrown when the Postmark API returns a non-success response. */
69
+ PostmarkError,
70
+ /** Postmark HTTP API transport. */
71
+ PostmarkTransport, } from "./transports/postmark.js";
72
+ export {
73
+ /** Development transport that writes emails to disk instead of sending them. */
74
+ PreviewTransport, } from "./transports/preview.js";
75
+ export {
76
+ /** Error thrown when the Resend API returns a non-success response. */
77
+ ResendError,
78
+ /** Resend HTTP API transport. */
79
+ ResendTransport, } from "./transports/resend.js";
80
+ export {
81
+ /** Decorator transport that retries failed sends with configurable backoff. */
82
+ RetryTransport, } from "./transports/retry.js";
83
+ export {
84
+ /** Error thrown when the SendGrid API returns a non-success response. */
85
+ SendGridError,
86
+ /** SendGrid v3 HTTP API transport. */
87
+ SendGridTransport, } from "./transports/sendgrid.js";
88
+ export {
89
+ /** Error thrown when the AWS SES API returns a non-success response. */
90
+ SESError,
91
+ /** AWS SES v2 HTTP API transport. */
92
+ SESTransport, } from "./transports/ses.js";
93
+ export {
94
+ /** SMTP transport orchestrating adapter, MIME builder, and protocol logic. */
95
+ SMTPTransport, } from "./transports/smtp.js";
package/dist/index.js CHANGED
@@ -1,14 +1,85 @@
1
- export { GOOGLE_TOKEN_URL, MICROSOFT_TOKEN_URL, OAuth2Client } from "./auth/oauth2.js";
2
- export { SMTPError } from "./core/smtp.js";
3
- export { createMailer, detectRuntime } from "./detect.js";
4
- export { simpleEngine, templatePlugin } from "./plugins/template.js";
5
- export { SMTPPool } from "./pool/pool.js";
6
- export { BrevoError, BrevoTransport } from "./transports/brevo.js";
7
- export { MailgunError, MailgunTransport } from "./transports/mailgun.js";
8
- export { PostmarkError, PostmarkTransport } from "./transports/postmark.js";
9
- export { PreviewTransport } from "./transports/preview.js";
10
- export { ResendError, ResendTransport } from "./transports/resend.js";
11
- export { RetryTransport } from "./transports/retry.js";
12
- export { SendGridError, SendGridTransport } from "./transports/sendgrid.js";
13
- export { SESError, SESTransport } from "./transports/ses.js";
14
- export { SMTPTransport } from "./transports/smtp.js";
1
+ export {
2
+
3
+ GOOGLE_TOKEN_URL,
4
+
5
+ MICROSOFT_TOKEN_URL,
6
+
7
+ OAuth2Client,
8
+ } from "./auth/oauth2.js";
9
+ export {
10
+
11
+ SMTPError,
12
+ } from "./core/smtp.js";
13
+
14
+ export {
15
+
16
+ createMailer,
17
+
18
+ detectRuntime,
19
+ } from "./detect.js";
20
+
21
+ export {
22
+
23
+ importPrivateKey,
24
+
25
+ signDKIM,
26
+ } from "./dkim.js";
27
+
28
+ export {
29
+
30
+ simpleEngine,
31
+
32
+ templatePlugin,
33
+ } from "./plugins/template.js";
34
+ export {
35
+
36
+ SMTPPool,
37
+ } from "./pool/pool.js";
38
+ export {
39
+
40
+ BrevoError,
41
+
42
+ BrevoTransport,
43
+ } from "./transports/brevo.js";
44
+ export {
45
+
46
+ MailgunError,
47
+
48
+ MailgunTransport,
49
+ } from "./transports/mailgun.js";
50
+ export {
51
+
52
+ PostmarkError,
53
+
54
+ PostmarkTransport,
55
+ } from "./transports/postmark.js";
56
+ export {
57
+
58
+ PreviewTransport,
59
+ } from "./transports/preview.js";
60
+ export {
61
+
62
+ ResendError,
63
+
64
+ ResendTransport,
65
+ } from "./transports/resend.js";
66
+ export {
67
+
68
+ RetryTransport,
69
+ } from "./transports/retry.js";
70
+ export {
71
+
72
+ SendGridError,
73
+
74
+ SendGridTransport,
75
+ } from "./transports/sendgrid.js";
76
+ export {
77
+
78
+ SESError,
79
+
80
+ SESTransport,
81
+ } from "./transports/ses.js";
82
+ export {
83
+
84
+ SMTPTransport,
85
+ } from "./transports/smtp.js";
@@ -0,0 +1,16 @@
1
+ import type { BulkSendOptions, BulkSendResult, Mailer, MailOptions, MailPlugin, SendResult, Transport, TransportMailerOptions, VerifyResult } from "./core/types.js";
2
+ export type { TransportMailerOptions };
3
+ /**
4
+ * Create a mailer that wraps a custom {@link Transport} (HTTP API, preview, retry, etc.).
5
+ */
6
+ export declare function createMailer(options: TransportMailerOptions): Promise<Mailer>;
7
+ /** Internal mailer implementation shared with the full `sently` entry. */
8
+ export declare class MailerImpl implements Mailer {
9
+ private readonly transport;
10
+ private readonly plugins;
11
+ constructor(transport: Transport, plugins?: MailPlugin[]);
12
+ send(options: MailOptions): Promise<SendResult>;
13
+ sendBulk(messages: MailOptions[], options?: BulkSendOptions): Promise<BulkSendResult>;
14
+ verify(): Promise<VerifyResult>;
15
+ close(): Promise<void>;
16
+ }
package/dist/mailer.js ADDED
@@ -0,0 +1,3 @@
1
+ import{q as a,r as b}from"./chunk-2kcwa9gt.js";import"./chunk-sqn04kae.js";export{a as createMailer,b as MailerImpl};
2
+
3
+ //# debugId=859D49FD0766085D64756E2164756E21
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [
5
+ ],
6
+ "mappings": "",
7
+ "debugId": "859D49FD0766085D64756E2164756E21",
8
+ "names": []
9
+ }
@@ -1,29 +1,3 @@
1
- import"../chunk-v0bahtg2.js";
1
+ import"../chunk-sqn04kae.js";function E(q,j){return q.replace(/\{\{(\w+)\}\}/g,(z,A)=>{let w=j[A];return w!==void 0&&w!==null?String(w):""})}function F(q){return(j)=>{if(!j.template)return j;let z=q.templates[j.template];if(!z)throw Error(`sently: template "${j.template}" not found`);let A=q.engine(z,j.data??{}),{template:w,data:D,...B}=j;return{...B,html:A}}}export{F as templatePlugin,E as simpleEngine};
2
2
 
3
- // src/plugins/template.ts
4
- function simpleEngine(template, data) {
5
- return template.replace(/\{\{(\w+)\}\}/g, (_, key) => {
6
- const val = data[key];
7
- return val !== undefined && val !== null ? String(val) : "";
8
- });
9
- }
10
- function templatePlugin(config) {
11
- return (options) => {
12
- if (!options.template) {
13
- return options;
14
- }
15
- const tmpl = config.templates[options.template];
16
- if (!tmpl) {
17
- throw new Error(`sently: template "${options.template}" not found`);
18
- }
19
- const html = config.engine(tmpl, options.data ?? {});
20
- const { template: _template, data: _data, ...rest } = options;
21
- return { ...rest, html };
22
- };
23
- }
24
- export {
25
- templatePlugin,
26
- simpleEngine
27
- };
28
-
29
- //# debugId=BF4AF728A3AA093064756E2164756E21
3
+ //# debugId=094B3D1AC9B011AB64756E2164756E21
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "/**\n * @module\n * Template plugin for sently.\n * Renders HTML email templates using a pluggable engine.\n * Built-in: simple {{variable}} interpolation (zero dependencies).\n * Bring your own engine: pass any render function.\n *\n * @example\n * ```ts\n * import { templatePlugin, simpleEngine } from 'sently/plugins/template'\n *\n * const mailer = await createMailer({\n * transport: new ResendTransport({ apiKey }),\n * plugins: [\n * templatePlugin({\n * engine: simpleEngine,\n * templates: {\n * welcome: '<h1>Hello, {{name}}!</h1>',\n * reset: '<p>Reset link: {{link}}</p>',\n * },\n * }),\n * ],\n * })\n *\n * await mailer.send({\n * from: '...',\n * to: '...',\n * subject: 'Welcome!',\n * template: 'welcome',\n * data: { name: 'Ali' },\n * })\n * ```\n */\nimport type { MailOptions, MailPlugin } from \"../core/types.js\";\n\n/** Renders a template string with the given data object. */\nexport type TemplateEngine = (template: string, data: Record<string, unknown>) => string;\n\n/** Configuration for the template plugin. */\nexport interface TemplatePluginConfig {\n /**\n * Rendering function. Use `simpleEngine` for zero-dep {{var}} interpolation,\n * or pass any function: (template, data) => string.\n */\n engine: TemplateEngine;\n /**\n * Map of template names to HTML strings.\n * Templates are loaded once at plugin creation time.\n */\n templates: Record<string, string>;\n}\n\n/**\n * Built-in zero-dependency template engine.\n * Replaces {{variable}} with the matching value from data.\n * Unknown variables are replaced with an empty string.\n */\nexport function simpleEngine(template: string, data: Record<string, unknown>): string {\n return template.replace(/\\{\\{(\\w+)\\}\\}/g, (_, key: string) => {\n const val = data[key];\n return val !== undefined && val !== null ? String(val) : \"\";\n });\n}\n\n/**\n * Create a template plugin from the given config.\n * The plugin reads options.template and options.data, renders the HTML,\n * sets options.html, and removes template/data before passing to the next plugin.\n */\nexport function templatePlugin(config: TemplatePluginConfig): MailPlugin {\n return (options: MailOptions): MailOptions => {\n if (!options.template) {\n return options;\n }\n\n const tmpl = config.templates[options.template];\n if (!tmpl) {\n throw new Error(`sently: template \"${options.template}\" not found`);\n }\n\n const html = config.engine(tmpl, options.data ?? {});\n const { template: _template, data: _data, ...rest } = options;\n return { ...rest, html };\n };\n}\n"
6
6
  ],
7
- "mappings": ";;;AAyDO,SAAS,YAAY,CAAC,UAAkB,MAAuC;AAAA,EACpF,OAAO,SAAS,QAAQ,kBAAkB,CAAC,GAAG,QAAgB;AAAA,IAC5D,MAAM,MAAM,KAAK;AAAA,IACjB,OAAO,QAAQ,aAAa,QAAQ,OAAO,OAAO,GAAG,IAAI;AAAA,GAC1D;AAAA;AAQI,SAAS,cAAc,CAAC,QAA0C;AAAA,EACvE,OAAO,CAAC,YAAsC;AAAA,IAC5C,IAAI,CAAC,QAAQ,UAAU;AAAA,MACrB,OAAO;AAAA,IACT;AAAA,IAEA,MAAM,OAAO,OAAO,UAAU,QAAQ;AAAA,IACtC,IAAI,CAAC,MAAM;AAAA,MACT,MAAM,IAAI,MAAM,qBAAqB,QAAQ,qBAAqB;AAAA,IACpE;AAAA,IAEA,MAAM,OAAO,OAAO,OAAO,MAAM,QAAQ,QAAQ,CAAC,CAAC;AAAA,IACnD,QAAQ,UAAU,WAAW,MAAM,UAAU,SAAS;AAAA,IACtD,OAAO,KAAK,MAAM,KAAK;AAAA;AAAA;",
8
- "debugId": "BF4AF728A3AA093064756E2164756E21",
7
+ "mappings": "6BAyDO,SAAS,CAAY,CAAC,EAAkB,EAAuC,CACpF,OAAO,EAAS,QAAQ,iBAAkB,CAAC,EAAG,IAAgB,CAC5D,IAAM,EAAM,EAAK,GACjB,OAAO,IAAQ,QAAa,IAAQ,KAAO,OAAO,CAAG,EAAI,GAC1D,EAQI,SAAS,CAAc,CAAC,EAA0C,CACvE,MAAO,CAAC,IAAsC,CAC5C,GAAI,CAAC,EAAQ,SACX,OAAO,EAGT,IAAM,EAAO,EAAO,UAAU,EAAQ,UACtC,GAAI,CAAC,EACH,MAAU,MAAM,qBAAqB,EAAQ,qBAAqB,EAGpE,IAAM,EAAO,EAAO,OAAO,EAAM,EAAQ,MAAQ,CAAC,CAAC,GAC3C,SAAU,EAAW,KAAM,KAAU,GAAS,EACtD,MAAO,IAAK,EAAM,MAAK",
8
+ "debugId": "094B3D1AC9B011AB64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -14,9 +14,13 @@ export interface PooledConnection {
14
14
  }
15
15
  /** Options for creating a pooled connection. */
16
16
  export interface PooledConnectionOptions {
17
+ /** SMTP configuration for the pooled session. */
17
18
  config: SMTPConfig;
19
+ /** Maximum messages before this connection is recycled. */
18
20
  maxMessages: number;
21
+ /** Hostname to connect to (may differ from config.host for direct MX). */
19
22
  connectHost: string;
23
+ /** Factory that creates the socket adapter for this connection. */
20
24
  createAdapter: () => Promise<import("../core/types.js").SocketAdapter>;
21
25
  }
22
26
  /**