sently 0.4.6 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +94 -41
  3. package/dist/adapters/bun.js +2 -183
  4. package/dist/adapters/bun.js.map +2 -2
  5. package/dist/adapters/cf.js +2 -77
  6. package/dist/adapters/cf.js.map +2 -2
  7. package/dist/adapters/deno.js +2 -72
  8. package/dist/adapters/deno.js.map +2 -2
  9. package/dist/adapters/node.js +2 -180
  10. package/dist/adapters/node.js.map +2 -2
  11. package/dist/auth/oauth2.js +2 -13
  12. package/dist/auth/oauth2.js.map +1 -1
  13. package/dist/chunk-2kcwa9gt.js +4 -0
  14. package/dist/chunk-2kcwa9gt.js.map +11 -0
  15. package/dist/chunk-2t6hjer3.js +5 -0
  16. package/dist/chunk-2t6hjer3.js.map +10 -0
  17. package/dist/chunk-6yggz45h.js +5 -0
  18. package/dist/{chunk-794hc3m4.js.map → chunk-6yggz45h.js.map} +2 -2
  19. package/dist/chunk-dgkh77yp.js +4 -0
  20. package/dist/{chunk-ym3zzv8b.js.map → chunk-dgkh77yp.js.map} +2 -2
  21. package/dist/chunk-jfs80vhp.js +3 -0
  22. package/dist/{chunk-7fqv71z1.js.map → chunk-jfs80vhp.js.map} +2 -2
  23. package/dist/chunk-sqn04kae.js +4 -0
  24. package/dist/{chunk-v0bahtg2.js.map → chunk-sqn04kae.js.map} +1 -1
  25. package/dist/chunk-va2awz12.js +4 -0
  26. package/dist/{chunk-f4c9ttmr.js.map → chunk-va2awz12.js.map} +2 -2
  27. package/dist/chunk-wgtbr6ge.js +13 -0
  28. package/dist/{chunk-tymfm441.js.map → chunk-wgtbr6ge.js.map} +2 -2
  29. package/dist/core/smtp.js +2 -31
  30. package/dist/core/smtp.js.map +1 -1
  31. package/dist/core/types.d.ts +7 -0
  32. package/dist/detect.d.ts +2 -0
  33. package/dist/detect.js +2 -180
  34. package/dist/detect.js.map +4 -5
  35. package/dist/dkim.d.ts +21 -0
  36. package/dist/dkim.js +9 -0
  37. package/dist/dkim.js.map +10 -0
  38. package/dist/index.d.ts +74 -16
  39. package/dist/index.js +85 -14
  40. package/dist/mailer.d.ts +16 -0
  41. package/dist/mailer.js +3 -0
  42. package/dist/mailer.js.map +9 -0
  43. package/dist/plugins/template.js +2 -28
  44. package/dist/plugins/template.js.map +2 -2
  45. package/dist/pool/pool.js +2 -16
  46. package/dist/pool/pool.js.map +5 -3
  47. package/dist/transports/brevo.js +2 -115
  48. package/dist/transports/brevo.js.map +2 -2
  49. package/dist/transports/mailgun.js +2 -119
  50. package/dist/transports/mailgun.js.map +2 -2
  51. package/dist/transports/postmark.js +2 -113
  52. package/dist/transports/postmark.js.map +2 -2
  53. package/dist/transports/preview.js +2 -72
  54. package/dist/transports/preview.js.map +2 -2
  55. package/dist/transports/resend.js +2 -109
  56. package/dist/transports/resend.js.map +2 -2
  57. package/dist/transports/retry.js +2 -78
  58. package/dist/transports/retry.js.map +2 -2
  59. package/dist/transports/sendgrid.js +2 -132
  60. package/dist/transports/sendgrid.js.map +2 -2
  61. package/dist/transports/ses.js +5 -251
  62. package/dist/transports/ses.js.map +2 -2
  63. package/dist/transports/smtp.js +2 -26
  64. package/dist/transports/smtp.js.map +1 -1
  65. package/package.json +17 -6
  66. package/dist/chunk-794hc3m4.js +0 -105
  67. package/dist/chunk-7fqv71z1.js +0 -251
  68. package/dist/chunk-f4c9ttmr.js +0 -154
  69. package/dist/chunk-mp5c9bfd.js +0 -270
  70. package/dist/chunk-mp5c9bfd.js.map +0 -11
  71. package/dist/chunk-tymfm441.js +0 -405
  72. package/dist/chunk-v0bahtg2.js +0 -6
  73. package/dist/chunk-x3szga4k.js +0 -367
  74. package/dist/chunk-x3szga4k.js.map +0 -11
  75. package/dist/chunk-ym3zzv8b.js +0 -74
@@ -1,73 +1,3 @@
1
- import"../chunk-v0bahtg2.js";
1
+ import"../chunk-sqn04kae.js";class v{conn=null;_secure;_connected=!1;tlsOptions;constructor(j={}){if(typeof Deno>"u")throw Error("DenoAdapter requires the Deno runtime");this._secure=j.secure??!1,this.tlsOptions=j.tls??{}}get secure(){return this._secure}get connected(){return this._connected}async connect(j,q){if(this._secure)this.conn=await Deno.connectTls({hostname:j,port:q,...this.tlsOptions.servername?{servername:this.tlsOptions.servername}:{}});else this.conn=await Deno.connect({hostname:j,port:q});this._connected=!0}async startTLS(j){if(!this.conn||this._secure)throw Error("Cannot STARTTLS: no plain connection available");let q={...this.tlsOptions,...j};this.conn=await Deno.startTls(this.conn,{...q.servername?{hostname:q.servername}:{}}),this._secure=!0}async write(j){if(!this.conn)throw Error("Socket not connected");await this.conn.write(j)}async*read(){if(!this.conn)throw Error("Socket not connected");let j=new Uint8Array(8192);while(!0){let q=await this.conn.read(j);if(q===null)break;yield j.slice(0,q)}}async close(){this.conn?.close(),this.conn=null,this._connected=!1}}export{v as DenoAdapter};
2
2
 
3
- // src/adapters/deno.ts
4
- class DenoAdapter {
5
- conn = null;
6
- _secure;
7
- _connected = false;
8
- tlsOptions;
9
- constructor(options = {}) {
10
- if (typeof Deno === "undefined") {
11
- throw new Error("DenoAdapter requires the Deno runtime");
12
- }
13
- this._secure = options.secure ?? false;
14
- this.tlsOptions = options.tls ?? {};
15
- }
16
- get secure() {
17
- return this._secure;
18
- }
19
- get connected() {
20
- return this._connected;
21
- }
22
- async connect(host, port) {
23
- if (this._secure) {
24
- this.conn = await Deno.connectTls({
25
- hostname: host,
26
- port,
27
- ...this.tlsOptions.servername ? { servername: this.tlsOptions.servername } : {}
28
- });
29
- } else {
30
- this.conn = await Deno.connect({ hostname: host, port });
31
- }
32
- this._connected = true;
33
- }
34
- async startTLS(options) {
35
- if (!this.conn || this._secure) {
36
- throw new Error("Cannot STARTTLS: no plain connection available");
37
- }
38
- const merged = { ...this.tlsOptions, ...options };
39
- this.conn = await Deno.startTls(this.conn, {
40
- ...merged.servername ? { hostname: merged.servername } : {}
41
- });
42
- this._secure = true;
43
- }
44
- async write(data) {
45
- if (!this.conn) {
46
- throw new Error("Socket not connected");
47
- }
48
- await this.conn.write(data);
49
- }
50
- async* read() {
51
- if (!this.conn) {
52
- throw new Error("Socket not connected");
53
- }
54
- const buffer = new Uint8Array(8192);
55
- while (true) {
56
- const n = await this.conn.read(buffer);
57
- if (n === null) {
58
- break;
59
- }
60
- yield buffer.slice(0, n);
61
- }
62
- }
63
- async close() {
64
- this.conn?.close();
65
- this.conn = null;
66
- this._connected = false;
67
- }
68
- }
69
- export {
70
- DenoAdapter
71
- };
72
-
73
- //# debugId=871B95B1C9304E4564756E2164756E21
3
+ //# debugId=433F0358DDA6910C64756E2164756E21
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "/**\n * @module\n * Deno socket adapter for SMTP connections via Deno.connect and Deno.startTls.\n *\n * @example\n * ```ts\n * import { DenoAdapter } from \"sently/adapters/deno\";\n * import { createMailer } from \"sently\";\n *\n * const mailer = await createMailer({\n * host: \"smtp.example.com\",\n * adapter: new DenoAdapter(),\n * auth: { user: \"you@example.com\", pass: \"secret\" },\n * });\n * ```\n */\nimport type { SocketAdapter, TLSOptions } from \"../core/types.js\";\n\ndeclare const Deno: {\n connect(options: { hostname: string; port: number }): Promise<DenoTcpConn>;\n connectTls(options: {\n hostname: string;\n port: number;\n [key: string]: unknown;\n }): Promise<DenoTlsConn>;\n startTls(conn: DenoTcpConn, options?: { hostname?: string }): Promise<DenoTlsConn>;\n};\n\ninterface DenoConn {\n read(p: Uint8Array): Promise<number | null>;\n write(p: Uint8Array): Promise<number>;\n close(): void;\n}\n\ninterface DenoTcpConn extends DenoConn {}\ninterface DenoTlsConn extends DenoConn {}\n\n/** Configuration options for {@link DenoAdapter}. */\nexport interface DenoAdapterOptions {\n /** Use implicit TLS on connect (port 465). Default: false. */\n secure?: boolean;\n /** Socket connect timeout in milliseconds. Default: 30_000. */\n connectionTimeout?: number;\n /** TLS options passed to Deno.startTls / Deno.connectTls. */\n tls?: TLSOptions;\n}\n\n/**\n * Deno socket adapter using Deno.connect / Deno.startTls.\n */\nexport class DenoAdapter implements SocketAdapter {\n /** Active Deno TCP or TLS connection. */\n private conn: DenoConn | null = null;\n /** Whether the connection is currently encrypted. */\n private _secure: boolean;\n /** Whether the socket is connected. */\n private _connected = false;\n /** TLS options for direct TLS and STARTTLS upgrades. */\n private readonly tlsOptions: TLSOptions;\n\n /** Creates a Deno socket adapter (requires the Deno runtime). */\n constructor(options: DenoAdapterOptions = {}) {\n if (typeof Deno === \"undefined\") {\n throw new Error(\"DenoAdapter requires the Deno runtime\");\n }\n this._secure = options.secure ?? false;\n this.tlsOptions = options.tls ?? {};\n }\n\n /** Whether the connection uses TLS. */\n get secure(): boolean {\n return this._secure;\n }\n\n /** Whether the socket is currently connected. */\n get connected(): boolean {\n return this._connected;\n }\n\n /** Opens a TCP or TLS connection to the given host and port. */\n async connect(host: string, port: number): Promise<void> {\n if (this._secure) {\n this.conn = await Deno.connectTls({\n hostname: host,\n port,\n ...(this.tlsOptions.servername ? { servername: this.tlsOptions.servername } : {}),\n });\n } else {\n this.conn = await Deno.connect({ hostname: host, port });\n }\n this._connected = true;\n }\n\n /** Upgrades a plain connection to TLS via STARTTLS. */\n async startTLS(options?: TLSOptions): Promise<void> {\n if (!this.conn || this._secure) {\n throw new Error(\"Cannot STARTTLS: no plain connection available\");\n }\n\n const merged = { ...this.tlsOptions, ...options };\n this.conn = await Deno.startTls(this.conn as DenoTcpConn, {\n ...(merged.servername ? { hostname: merged.servername } : {}),\n });\n this._secure = true;\n }\n\n /** Writes raw bytes to the socket. */\n async write(data: Uint8Array): Promise<void> {\n if (!this.conn) {\n throw new Error(\"Socket not connected\");\n }\n await this.conn.write(data);\n }\n\n /** Reads incoming socket data as an async iterable of byte chunks. */\n async *read(): AsyncGenerator<Uint8Array, void, unknown> {\n if (!this.conn) {\n throw new Error(\"Socket not connected\");\n }\n\n const buffer = new Uint8Array(8192);\n while (true) {\n const n = await this.conn.read(buffer);\n if (n === null) {\n break;\n }\n yield buffer.slice(0, n);\n }\n }\n\n /** Closes the socket connection. */\n async close(): Promise<void> {\n this.conn?.close();\n this.conn = null;\n this._connected = false;\n }\n}\n"
6
6
  ],
7
- "mappings": ";;;AAkDO,MAAM,YAAqC;AAAA,EAExC,OAAwB;AAAA,EAExB;AAAA,EAEA,aAAa;AAAA,EAEJ;AAAA,EAGjB,WAAW,CAAC,UAA8B,CAAC,GAAG;AAAA,IAC5C,IAAI,OAAO,SAAS,aAAa;AAAA,MAC/B,MAAM,IAAI,MAAM,uCAAuC;AAAA,IACzD;AAAA,IACA,KAAK,UAAU,QAAQ,UAAU;AAAA,IACjC,KAAK,aAAa,QAAQ,OAAO,CAAC;AAAA;AAAA,MAIhC,MAAM,GAAY;AAAA,IACpB,OAAO,KAAK;AAAA;AAAA,MAIV,SAAS,GAAY;AAAA,IACvB,OAAO,KAAK;AAAA;AAAA,OAIR,QAAO,CAAC,MAAc,MAA6B;AAAA,IACvD,IAAI,KAAK,SAAS;AAAA,MAChB,KAAK,OAAO,MAAM,KAAK,WAAW;AAAA,QAChC,UAAU;AAAA,QACV;AAAA,WACI,KAAK,WAAW,aAAa,EAAE,YAAY,KAAK,WAAW,WAAW,IAAI,CAAC;AAAA,MACjF,CAAC;AAAA,IACH,EAAO;AAAA,MACL,KAAK,OAAO,MAAM,KAAK,QAAQ,EAAE,UAAU,MAAM,KAAK,CAAC;AAAA;AAAA,IAEzD,KAAK,aAAa;AAAA;AAAA,OAId,SAAQ,CAAC,SAAqC;AAAA,IAClD,IAAI,CAAC,KAAK,QAAQ,KAAK,SAAS;AAAA,MAC9B,MAAM,IAAI,MAAM,gDAAgD;AAAA,IAClE;AAAA,IAEA,MAAM,SAAS,KAAK,KAAK,eAAe,QAAQ;AAAA,IAChD,KAAK,OAAO,MAAM,KAAK,SAAS,KAAK,MAAqB;AAAA,SACpD,OAAO,aAAa,EAAE,UAAU,OAAO,WAAW,IAAI,CAAC;AAAA,IAC7D,CAAC;AAAA,IACD,KAAK,UAAU;AAAA;AAAA,OAIX,MAAK,CAAC,MAAiC;AAAA,IAC3C,IAAI,CAAC,KAAK,MAAM;AAAA,MACd,MAAM,IAAI,MAAM,sBAAsB;AAAA,IACxC;AAAA,IACA,MAAM,KAAK,KAAK,MAAM,IAAI;AAAA;AAAA,SAIrB,IAAI,GAA8C;AAAA,IACvD,IAAI,CAAC,KAAK,MAAM;AAAA,MACd,MAAM,IAAI,MAAM,sBAAsB;AAAA,IACxC;AAAA,IAEA,MAAM,SAAS,IAAI,WAAW,IAAI;AAAA,IAClC,OAAO,MAAM;AAAA,MACX,MAAM,IAAI,MAAM,KAAK,KAAK,KAAK,MAAM;AAAA,MACrC,IAAI,MAAM,MAAM;AAAA,QACd;AAAA,MACF;AAAA,MACA,MAAM,OAAO,MAAM,GAAG,CAAC;AAAA,IACzB;AAAA;AAAA,OAII,MAAK,GAAkB;AAAA,IAC3B,KAAK,MAAM,MAAM;AAAA,IACjB,KAAK,OAAO;AAAA,IACZ,KAAK,aAAa;AAAA;AAEtB;",
8
- "debugId": "871B95B1C9304E4564756E2164756E21",
7
+ "mappings": "6BAkDO,MAAM,CAAqC,CAExC,KAAwB,KAExB,QAEA,WAAa,GAEJ,WAGjB,WAAW,CAAC,EAA8B,CAAC,EAAG,CAC5C,GAAI,OAAO,KAAS,IAClB,MAAU,MAAM,uCAAuC,EAEzD,KAAK,QAAU,EAAQ,QAAU,GACjC,KAAK,WAAa,EAAQ,KAAO,CAAC,KAIhC,OAAM,EAAY,CACpB,OAAO,KAAK,WAIV,UAAS,EAAY,CACvB,OAAO,KAAK,gBAIR,QAAO,CAAC,EAAc,EAA6B,CACvD,GAAI,KAAK,QACP,KAAK,KAAO,MAAM,KAAK,WAAW,CAChC,SAAU,EACV,UACI,KAAK,WAAW,WAAa,CAAE,WAAY,KAAK,WAAW,UAAW,EAAI,CAAC,CACjF,CAAC,EAED,UAAK,KAAO,MAAM,KAAK,QAAQ,CAAE,SAAU,EAAM,MAAK,CAAC,EAEzD,KAAK,WAAa,QAId,SAAQ,CAAC,EAAqC,CAClD,GAAI,CAAC,KAAK,MAAQ,KAAK,QACrB,MAAU,MAAM,gDAAgD,EAGlE,IAAM,EAAS,IAAK,KAAK,cAAe,CAAQ,EAChD,KAAK,KAAO,MAAM,KAAK,SAAS,KAAK,KAAqB,IACpD,EAAO,WAAa,CAAE,SAAU,EAAO,UAAW,EAAI,CAAC,CAC7D,CAAC,EACD,KAAK,QAAU,QAIX,MAAK,CAAC,EAAiC,CAC3C,GAAI,CAAC,KAAK,KACR,MAAU,MAAM,sBAAsB,EAExC,MAAM,KAAK,KAAK,MAAM,CAAI,QAIrB,IAAI,EAA8C,CACvD,GAAI,CAAC,KAAK,KACR,MAAU,MAAM,sBAAsB,EAGxC,IAAM,EAAS,IAAI,WAAW,IAAI,EAClC,MAAO,GAAM,CACX,IAAM,EAAI,MAAM,KAAK,KAAK,KAAK,CAAM,EACrC,GAAI,IAAM,KACR,MAEF,MAAM,EAAO,MAAM,EAAG,CAAC,QAKrB,MAAK,EAAkB,CAC3B,KAAK,MAAM,MAAM,EACjB,KAAK,KAAO,KACZ,KAAK,WAAa,GAEtB",
8
+ "debugId": "433F0358DDA6910C64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,181 +1,3 @@
1
- import"../chunk-v0bahtg2.js";
1
+ import"../chunk-sqn04kae.js";import W from"node:net";import Q from"node:tls";function V(f){if(f.rejectUnauthorized===!1)console.warn("[sently] TLS certificate verification is disabled. Never use rejectUnauthorized: false in production.")}class X{socket=null;_secure;_connected=!1;connectionTimeout;tlsOptions;constructor(f={}){this._secure=f.secure??!1,this.connectionTimeout=f.connectionTimeout??30000,this.tlsOptions=f.tls??{}}get secure(){return this._secure}get connected(){return this._connected}async connect(f,B){if(this._secure)await this.connectTls(f,B);else await this.connectPlain(f,B);this._connected=!0}async startTLS(f){if(!this.socket||this._secure)throw Error("Cannot STARTTLS: no plain socket available");let B=this.socket,y={...this.tlsOptions,...f};V(y),await new Promise((F,A)=>{let G=Q.connect({socket:B,servername:y.servername,rejectUnauthorized:y.rejectUnauthorized??!0,minVersion:y.minVersion});G.once("secureConnect",()=>{this.socket=G,this._secure=!0,F()}),G.once("error",A)})}async write(f){if(!this.socket)throw Error("Socket not connected");await new Promise((B,y)=>{this.socket?.write(Buffer.from(f),(F)=>{if(F)y(F);else B()})})}async*read(){if(!this.socket)throw Error("Socket not connected");let f=this.socket,B=[],y=null,F=!1,A=null,G=(H)=>{let I=new Uint8Array(H);if(y)y({value:I,done:!1}),y=null;else B.push(I)},J=(H)=>{if(A=H,y)y({value:void 0,done:!0}),y=null;F=!0},K=()=>{if(F=!0,y)y({value:void 0,done:!0}),y=null};f.on("data",G),f.on("error",J),f.on("close",K);try{while(!F||B.length>0){if(A)throw A;if(B.length>0){yield B.shift();continue}if(F)break;let H=await new Promise((I)=>{y=I});if(H.done)break;yield H.value}}finally{f.off("data",G),f.off("error",J),f.off("close",K)}}async close(){if(!this.socket)return;await new Promise((f)=>{this.socket?.end(()=>f())}),this.socket=null,this._connected=!1}connectPlain(f,B){return new Promise((y,F)=>{let A=W.connect({host:f,port:B},()=>y());A.setTimeout(this.connectionTimeout),A.once("timeout",()=>{A.destroy(),F(Error("Connection timeout"))}),A.once("error",F),this.socket=A})}connectTls(f,B){return V(this.tlsOptions),new Promise((y,F)=>{let A=Q.connect({host:f,port:B,servername:this.tlsOptions.servername??f,rejectUnauthorized:this.tlsOptions.rejectUnauthorized??!0,minVersion:this.tlsOptions.minVersion},()=>y());A.setTimeout(this.connectionTimeout),A.once("timeout",()=>{A.destroy(),F(Error("Connection timeout"))}),A.once("error",F),this.socket=A})}}export{X as NodeAdapter};
2
2
 
3
- // src/adapters/node.ts
4
- import net from "node:net";
5
- import tls from "node:tls";
6
- function warnRejectUnauthorizedDisabled(tls2) {
7
- if (tls2.rejectUnauthorized === false) {
8
- console.warn("[sently] TLS certificate verification is disabled. " + "Never use rejectUnauthorized: false in production.");
9
- }
10
- }
11
-
12
- class NodeAdapter {
13
- socket = null;
14
- _secure;
15
- _connected = false;
16
- connectionTimeout;
17
- tlsOptions;
18
- constructor(options = {}) {
19
- this._secure = options.secure ?? false;
20
- this.connectionTimeout = options.connectionTimeout ?? 30000;
21
- this.tlsOptions = options.tls ?? {};
22
- }
23
- get secure() {
24
- return this._secure;
25
- }
26
- get connected() {
27
- return this._connected;
28
- }
29
- async connect(host, port) {
30
- if (this._secure) {
31
- await this.connectTls(host, port);
32
- } else {
33
- await this.connectPlain(host, port);
34
- }
35
- this._connected = true;
36
- }
37
- async startTLS(options) {
38
- if (!this.socket || this._secure) {
39
- throw new Error("Cannot STARTTLS: no plain socket available");
40
- }
41
- const plain = this.socket;
42
- const merged = { ...this.tlsOptions, ...options };
43
- warnRejectUnauthorizedDisabled(merged);
44
- await new Promise((resolve, reject) => {
45
- const tlsSocket = tls.connect({
46
- socket: plain,
47
- servername: merged.servername,
48
- rejectUnauthorized: merged.rejectUnauthorized ?? true,
49
- minVersion: merged.minVersion
50
- });
51
- tlsSocket.once("secureConnect", () => {
52
- this.socket = tlsSocket;
53
- this._secure = true;
54
- resolve();
55
- });
56
- tlsSocket.once("error", reject);
57
- });
58
- }
59
- async write(data) {
60
- if (!this.socket) {
61
- throw new Error("Socket not connected");
62
- }
63
- await new Promise((resolve, reject) => {
64
- this.socket?.write(Buffer.from(data), (err) => {
65
- if (err) {
66
- reject(err);
67
- } else {
68
- resolve();
69
- }
70
- });
71
- });
72
- }
73
- async* read() {
74
- if (!this.socket) {
75
- throw new Error("Socket not connected");
76
- }
77
- const socket = this.socket;
78
- const queue = [];
79
- let resolveNext = null;
80
- let done = false;
81
- let error = null;
82
- const onData = (chunk) => {
83
- const data = new Uint8Array(chunk);
84
- if (resolveNext) {
85
- resolveNext({ value: data, done: false });
86
- resolveNext = null;
87
- } else {
88
- queue.push(data);
89
- }
90
- };
91
- const onError = (err) => {
92
- error = err;
93
- if (resolveNext) {
94
- resolveNext({ value: undefined, done: true });
95
- resolveNext = null;
96
- }
97
- done = true;
98
- };
99
- const onClose = () => {
100
- done = true;
101
- if (resolveNext) {
102
- resolveNext({ value: undefined, done: true });
103
- resolveNext = null;
104
- }
105
- };
106
- socket.on("data", onData);
107
- socket.on("error", onError);
108
- socket.on("close", onClose);
109
- try {
110
- while (!done || queue.length > 0) {
111
- if (error) {
112
- throw error;
113
- }
114
- if (queue.length > 0) {
115
- yield queue.shift();
116
- continue;
117
- }
118
- if (done) {
119
- break;
120
- }
121
- const chunk = await new Promise((resolve) => {
122
- resolveNext = resolve;
123
- });
124
- if (chunk.done) {
125
- break;
126
- }
127
- yield chunk.value;
128
- }
129
- } finally {
130
- socket.off("data", onData);
131
- socket.off("error", onError);
132
- socket.off("close", onClose);
133
- }
134
- }
135
- async close() {
136
- if (!this.socket) {
137
- return;
138
- }
139
- await new Promise((resolve) => {
140
- this.socket?.end(() => resolve());
141
- });
142
- this.socket = null;
143
- this._connected = false;
144
- }
145
- connectPlain(host, port) {
146
- return new Promise((resolve, reject) => {
147
- const socket = net.connect({ host, port }, () => resolve());
148
- socket.setTimeout(this.connectionTimeout);
149
- socket.once("timeout", () => {
150
- socket.destroy();
151
- reject(new Error("Connection timeout"));
152
- });
153
- socket.once("error", reject);
154
- this.socket = socket;
155
- });
156
- }
157
- connectTls(host, port) {
158
- warnRejectUnauthorizedDisabled(this.tlsOptions);
159
- return new Promise((resolve, reject) => {
160
- const socket = tls.connect({
161
- host,
162
- port,
163
- servername: this.tlsOptions.servername ?? host,
164
- rejectUnauthorized: this.tlsOptions.rejectUnauthorized ?? true,
165
- minVersion: this.tlsOptions.minVersion
166
- }, () => resolve());
167
- socket.setTimeout(this.connectionTimeout);
168
- socket.once("timeout", () => {
169
- socket.destroy();
170
- reject(new Error("Connection timeout"));
171
- });
172
- socket.once("error", reject);
173
- this.socket = socket;
174
- });
175
- }
176
- }
177
- export {
178
- NodeAdapter
179
- };
180
-
181
- //# debugId=ECC754A0A0C9909F64756E2164756E21
3
+ //# debugId=81CB75805F76C9AC64756E2164756E21
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "/**\n * @module\n * Node.js socket adapter for SMTP connections via node:net and node:tls.\n *\n * @example\n * ```ts\n * import { NodeAdapter } from \"sently/adapters/node\";\n * import { createMailer } from \"sently\";\n *\n * const mailer = await createMailer({\n * host: \"smtp.example.com\",\n * adapter: new NodeAdapter(),\n * auth: { user: \"you@example.com\", pass: \"secret\" },\n * });\n * ```\n */\nimport net from \"node:net\";\nimport tls from \"node:tls\";\nimport type { SocketAdapter, TLSOptions } from \"../core/types.js\";\n\nfunction warnRejectUnauthorizedDisabled(tls: TLSOptions): void {\n if (tls.rejectUnauthorized === false) {\n console.warn(\n \"[sently] TLS certificate verification is disabled. \" +\n \"Never use rejectUnauthorized: false in production.\",\n );\n }\n}\n\n/** Configuration options for {@link NodeAdapter}. */\nexport interface NodeAdapterOptions {\n /** Use implicit TLS on connect (port 465). Default: false. */\n secure?: boolean;\n /** Socket connect timeout in milliseconds. Default: 30_000. */\n connectionTimeout?: number;\n /** TLS options passed to node:tls. */\n tls?: TLSOptions;\n}\n\n/**\n * Node.js socket adapter using node:net and node:tls.\n */\nexport class NodeAdapter implements SocketAdapter {\n /** Underlying Node.js TCP or TLS socket. */\n private socket: net.Socket | tls.TLSSocket | null = null;\n /** Whether the connection is currently encrypted. */\n private _secure: boolean;\n /** Whether the socket is connected. */\n private _connected = false;\n /** Socket connect timeout in milliseconds. */\n private readonly connectionTimeout: number;\n /** TLS options for direct TLS and STARTTLS upgrades. */\n private readonly tlsOptions: TLSOptions;\n\n /** Creates a Node.js socket adapter. */\n constructor(options: NodeAdapterOptions = {}) {\n this._secure = options.secure ?? false;\n this.connectionTimeout = options.connectionTimeout ?? 30_000;\n this.tlsOptions = options.tls ?? {};\n }\n\n /** Whether the connection uses TLS. */\n get secure(): boolean {\n return this._secure;\n }\n\n /** Whether the socket is currently connected. */\n get connected(): boolean {\n return this._connected;\n }\n\n /** Opens a TCP or TLS connection to the given host and port. */\n async connect(host: string, port: number): Promise<void> {\n if (this._secure) {\n await this.connectTls(host, port);\n } else {\n await this.connectPlain(host, port);\n }\n this._connected = true;\n }\n\n /** Upgrades a plain connection to TLS via STARTTLS. */\n async startTLS(options?: TLSOptions): Promise<void> {\n if (!this.socket || this._secure) {\n throw new Error(\"Cannot STARTTLS: no plain socket available\");\n }\n\n const plain = this.socket;\n const merged = { ...this.tlsOptions, ...options };\n warnRejectUnauthorizedDisabled(merged);\n\n await new Promise<void>((resolve, reject) => {\n const tlsSocket = tls.connect({\n socket: plain,\n servername: merged.servername,\n rejectUnauthorized: merged.rejectUnauthorized ?? true,\n minVersion: merged.minVersion,\n });\n\n tlsSocket.once(\"secureConnect\", () => {\n this.socket = tlsSocket;\n this._secure = true;\n resolve();\n });\n tlsSocket.once(\"error\", reject);\n });\n }\n\n /** Writes raw bytes to the socket. */\n async write(data: Uint8Array): Promise<void> {\n if (!this.socket) {\n throw new Error(\"Socket not connected\");\n }\n\n await new Promise<void>((resolve, reject) => {\n this.socket?.write(Buffer.from(data), (err: Error | null | undefined) => {\n if (err) {\n reject(err);\n } else {\n resolve();\n }\n });\n });\n }\n\n /** Reads incoming socket data as an async iterable of byte chunks. */\n async *read(): AsyncGenerator<Uint8Array, void, unknown> {\n if (!this.socket) {\n throw new Error(\"Socket not connected\");\n }\n\n const socket = this.socket;\n const queue: Uint8Array[] = [];\n let resolveNext: ((value: IteratorResult<Uint8Array>) => void) | null = null;\n let done = false;\n let error: Error | null = null;\n\n const onData = (chunk: Buffer): void => {\n const data = new Uint8Array(chunk);\n if (resolveNext) {\n resolveNext({ value: data, done: false });\n resolveNext = null;\n } else {\n queue.push(data);\n }\n };\n\n const onError = (err: Error): void => {\n error = err;\n if (resolveNext) {\n resolveNext({ value: undefined as unknown as Uint8Array, done: true });\n resolveNext = null;\n }\n done = true;\n };\n\n const onClose = (): void => {\n done = true;\n if (resolveNext) {\n resolveNext({ value: undefined as unknown as Uint8Array, done: true });\n resolveNext = null;\n }\n };\n\n socket.on(\"data\", onData);\n socket.on(\"error\", onError);\n socket.on(\"close\", onClose);\n\n try {\n while (!done || queue.length > 0) {\n if (error) {\n throw error;\n }\n if (queue.length > 0) {\n yield queue.shift() as Uint8Array;\n continue;\n }\n if (done) {\n break;\n }\n const chunk = await new Promise<IteratorResult<Uint8Array>>((resolve) => {\n resolveNext = resolve;\n });\n if (chunk.done) {\n break;\n }\n yield chunk.value;\n }\n } finally {\n socket.off(\"data\", onData);\n socket.off(\"error\", onError);\n socket.off(\"close\", onClose);\n }\n }\n\n /** Closes the socket connection. */\n async close(): Promise<void> {\n if (!this.socket) {\n return;\n }\n\n await new Promise<void>((resolve) => {\n this.socket?.end(() => resolve());\n });\n this.socket = null;\n this._connected = false;\n }\n\n /** Opens a plain TCP connection to the SMTP server. */\n private connectPlain(host: string, port: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const socket = net.connect({ host, port }, () => resolve());\n socket.setTimeout(this.connectionTimeout);\n socket.once(\"timeout\", () => {\n socket.destroy();\n reject(new Error(\"Connection timeout\"));\n });\n socket.once(\"error\", reject);\n this.socket = socket;\n });\n }\n\n /** Opens a direct TLS connection to the SMTP server. */\n private connectTls(host: string, port: number): Promise<void> {\n warnRejectUnauthorizedDisabled(this.tlsOptions);\n return new Promise((resolve, reject) => {\n const socket = tls.connect(\n {\n host,\n port,\n servername: this.tlsOptions.servername ?? host,\n rejectUnauthorized: this.tlsOptions.rejectUnauthorized ?? true,\n minVersion: this.tlsOptions.minVersion,\n },\n () => resolve(),\n );\n socket.setTimeout(this.connectionTimeout);\n socket.once(\"timeout\", () => {\n socket.destroy();\n reject(new Error(\"Connection timeout\"));\n });\n socket.once(\"error\", reject);\n this.socket = socket;\n });\n }\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "ECC754A0A0C9909F64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "81CB75805F76C9AC64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,14 +1,3 @@
1
- import {
2
- GOOGLE_TOKEN_URL,
3
- MICROSOFT_TOKEN_URL,
4
- OAuth2Client
5
- } from "../chunk-ym3zzv8b.js";
6
- import"../chunk-794hc3m4.js";
7
- import"../chunk-v0bahtg2.js";
8
- export {
9
- OAuth2Client,
10
- MICROSOFT_TOKEN_URL,
11
- GOOGLE_TOKEN_URL
12
- };
1
+ import{g as a,h as b,i as c}from"../chunk-dgkh77yp.js";import"../chunk-6yggz45h.js";import"../chunk-sqn04kae.js";export{c as OAuth2Client,b as MICROSOFT_TOKEN_URL,a as GOOGLE_TOKEN_URL};
13
2
 
14
- //# debugId=4C0D32028E4F04FA64756E2164756E21
3
+ //# debugId=8B34C4BC825539BC64756E2164756E21
@@ -4,6 +4,6 @@
4
4
  "sourcesContent": [
5
5
  ],
6
6
  "mappings": "",
7
- "debugId": "4C0D32028E4F04FA64756E2164756E21",
7
+ "debugId": "8B34C4BC825539BC64756E2164756E21",
8
8
  "names": []
9
9
  }
@@ -0,0 +1,4 @@
1
+ async function V(k,z){if(!z||z.length===0)return k;let B=k;for(let A of z)B=await A(B);return B}async function Z(k){return new W(k.transport,k.plugins??[])}class W{transport;plugins;constructor(k,z=[]){this.transport=k;this.plugins=z}async send(k){let z=await V(k,this.plugins);return this.transport.send(z)}async sendBulk(k,z){let B=z?.concurrency??1,A=Array(k.length),J=[...k.entries()],K=0;await new Promise((G)=>{if(k.length===0){G();return}let L=()=>{if(J.length===0&&K===0)G()},U=()=>{if(J.length===0){L();return}let C=J.shift();if(C===void 0){L();return}let[H,Q]=C;K++,this.send(Q).then((F)=>{A[H]={status:"sent",result:F},z?.onSuccess?.(Q,H,F)}).catch((F)=>{A[H]={status:"failed",error:F},z?.onError?.(Q,H,F)}).finally(()=>{K--,U(),L()})};for(let C=0;C<B;C++)U()});let S=0,T=0;for(let G of A)if(G.status==="sent")S++;else T++;return{total:k.length,sent:S,failed:T,results:A}}verify(){if(this.transport.verify)return this.transport.verify();return Promise.resolve({ok:!0,provider:"mailer"})}close(){if(this.transport.close)return this.transport.close();return Promise.resolve()}}
2
+ export{Z as q,W as r};
3
+
4
+ //# debugId=3495BDF6CCDE500D64756E2164756E21
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/core/plugin.ts", "../src/mailer.ts"],
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
+ "/**\n * @module\n * Lightweight mailer factory for custom transports — no SMTP code in the bundle.\n *\n * Use this entry instead of `sently` when you pass a transport explicitly\n * (Resend, SendGrid, etc.) and want the smallest bundle size.\n *\n * @example\n * ```ts\n * import { createMailer } from \"sently/mailer\";\n * import { ResendTransport } from \"sently/transports/resend\";\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 { runPlugins } from \"./core/plugin.js\";\nimport type {\n BulkSendOptions,\n BulkSendResult,\n Mailer,\n MailOptions,\n MailPlugin,\n SendResult,\n Transport,\n TransportMailerOptions,\n VerifyResult,\n} from \"./core/types.js\";\n\nexport type { TransportMailerOptions };\n\n/**\n * Create a mailer that wraps a custom {@link Transport} (HTTP API, preview, retry, etc.).\n */\nexport async function createMailer(options: TransportMailerOptions): Promise<Mailer> {\n return new MailerImpl(options.transport, options.plugins ?? []);\n}\n\n/** Internal mailer implementation shared with the full `sently` entry. */\nexport class 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"
7
+ ],
8
+ "mappings": "AAuBA,eAAsB,CAAU,CAC9B,EACA,EACsB,CACtB,GAAI,CAAC,GAAW,EAAQ,SAAW,EACjC,OAAO,EAGT,IAAI,EAAU,EACd,QAAW,KAAU,EACnB,EAAU,MAAM,EAAO,CAAO,EAEhC,OAAO,ECOT,eAAsB,CAAY,CAAC,EAAkD,CACnF,OAAO,IAAI,EAAW,EAAQ,UAAW,EAAQ,SAAW,CAAC,CAAC,EAIzD,MAAM,CAA6B,CAErB,UACA,QAFnB,WAAW,CACQ,EACA,EAAwB,CAAC,EAC1C,CAFiB,iBACA,oBAGb,KAAI,CAAC,EAA2C,CACpD,IAAM,EAAY,MAAM,EAAW,EAAS,KAAK,OAAO,EACxD,OAAO,KAAK,UAAU,KAAK,CAAS,OAGhC,SAAQ,CAAC,EAAyB,EAAoD,CAC1F,IAAM,EAAc,GAAS,aAAe,EACtC,EAAyC,MAAM,EAAS,MAAM,EAC9D,EAAQ,CAAC,GAAG,EAAS,QAAQ,CAAC,EAChC,EAAS,EAEb,MAAM,IAAI,QAAc,CAAC,IAAY,CACnC,GAAI,EAAS,SAAW,EAAG,CACzB,EAAQ,EACR,OAGF,IAAM,EAAY,IAAY,CAC5B,GAAI,EAAM,SAAW,GAAK,IAAW,EACnC,EAAQ,GAIN,EAAc,IAAY,CAC9B,GAAI,EAAM,SAAW,EAAG,CACtB,EAAU,EACV,OAGF,IAAM,EAAQ,EAAM,MAAM,EAC1B,GAAI,IAAU,OAAW,CACvB,EAAU,EACV,OAGF,IAAO,EAAO,GAAW,EACzB,IAEK,KAAK,KAAK,CAAO,EACnB,KAAK,CAAC,IAAW,CAChB,EAAQ,GAAS,CAAE,OAAQ,OAAQ,QAAO,EAC1C,GAAS,YAAY,EAAS,EAAO,CAAM,EAC5C,EACA,MAAM,CAAC,IAAmB,CACzB,EAAQ,GAAS,CAAE,OAAQ,SAAU,OAAM,EAC3C,GAAS,UAAU,EAAS,EAAO,CAAK,EACzC,EACA,QAAQ,IAAM,CACb,IACA,EAAY,EACZ,EAAU,EACX,GAGL,QAAS,EAAI,EAAG,EAAI,EAAa,IAC/B,EAAY,EAEf,EAED,IAAI,EAAO,EACP,EAAS,EACb,QAAW,KAAU,EACnB,GAAI,EAAO,SAAW,OACpB,IAEA,SAIJ,MAAO,CACL,MAAO,EAAS,OAChB,OACA,SACA,SACF,EAGF,MAAM,EAA0B,CAC9B,GAAI,KAAK,UAAU,OACjB,OAAO,KAAK,UAAU,OAAO,EAE/B,OAAO,QAAQ,QAAQ,CAAE,GAAI,GAAM,SAAU,QAAS,CAAC,EAGzD,KAAK,EAAkB,CACrB,GAAI,KAAK,UAAU,MACjB,OAAO,KAAK,UAAU,MAAM,EAE9B,OAAO,QAAQ,QAAQ,EAE3B",
9
+ "debugId": "3495BDF6CCDE500D64756E2164756E21",
10
+ "names": []
11
+ }
@@ -0,0 +1,5 @@
1
+ import{k as v,l as j,m as D,n as T,o as y}from"./chunk-va2awz12.js";import{E as F,G as M,H as P}from"./chunk-6yggz45h.js";import{I as b}from"./chunk-sqn04kae.js";function N(q){return q.replace(/\r\n?|\n/g," ").trim()}function w(q){if(v(q.address,"address"),q.name!==void 0)v(q.name,"display name");let O=q.address.trim();if(!y(O))throw Error(`Invalid email address: ${JSON.stringify(q.address)}`);let G={address:O};if(q.name)G.name=N(q.name);return G}var Q=`\r
2
+ `;async function c(q,O){let G=q.messageId??f(),X=(q.date??new Date).toUTCString(),Y=j(q.from),Z=j(q.to),K=q.cc?j(q.cc):[];if(Y.length===0)throw Error("Missing from address");if(Z.length===0)throw Error("Missing to address");let H={from:Y[0]?.address??"",to:[...T(q.to),...q.cc?T(q.cc):[],...q.bcc?T(q.bcc):[]]},E=q.attachments??[],V=E.filter((J)=>J.inline||J.contentId),I=E.filter((J)=>!J.inline&&!J.contentId),W=k(q);if(V.length>0){let J=S();W={contentType:`multipart/related; boundary="${J}"`,content:x(J,[L(k(q)),...V.map(R)])}}if(I.length>0){let J=S();W={contentType:`multipart/mixed; boundary="${J}"`,content:x(J,[L(W),...I.map(R)])}}let _=[$("From",Y.map((J)=>D(w(J))).join(", ")),$("To",Z.map((J)=>D(w(J))).join(", "))];if(K.length>0)_.push($("Cc",K.map((J)=>D(w(J))).join(", ")));if(q.replyTo)_.push($("Reply-To",j(q.replyTo).map((J)=>D(w(J))).join(", ")));if(_.push($("Subject",M(N(q.subject))),$("Date",X),$("Message-ID",G),"MIME-Version: 1.0"),q.priority==="high")_.push("X-Priority: 1","Importance: high");else if(q.priority==="low")_.push("X-Priority: 5","Importance: low");if(q.headers)for(let[J,B]of Object.entries(q.headers))_.push($(N(J),N(B)));if(_.push(`Content-Type: ${W.contentType}`),W.contentTransferEncoding)_.push(`Content-Transfer-Encoding: ${W.contentTransferEncoding}`);let z=`${_.join(Q)}${Q}${Q}${W.content}`,U=P(z);if(O){let{signDKIM:J}=await import("./dkim.js"),{header:B}=await J(U,O),g=`${B}${Q}${z}`;U=P(g)}return{raw:U,envelope:H,messageId:G,size:U.length}}function k(q){let O=Boolean(q.text),G=Boolean(q.html);if(O&&G){let X=S();return{contentType:`multipart/alternative; boundary="${X}"`,content:x(X,[C({contentType:"text/plain; charset=utf-8",contentTransferEncoding:"8bit",content:q.text??""}),C({contentType:"text/html; charset=utf-8",contentTransferEncoding:"8bit",content:q.html??""})])}}if(G)return{contentType:"text/html; charset=utf-8",contentTransferEncoding:"8bit",content:q.html??""};return{contentType:"text/plain; charset=utf-8",contentTransferEncoding:"8bit",content:q.text??""}}function C(q){let O=[`Content-Type: ${q.contentType}`];if(q.contentTransferEncoding)O.push(`Content-Transfer-Encoding: ${q.contentTransferEncoding}`);return`${O.join(Q)}${Q}${Q}${q.content}`}function L(q){let O=[`Content-Type: ${q.contentType}`];if(q.contentTransferEncoding)O.push(`Content-Transfer-Encoding: ${q.contentTransferEncoding}`);return`${O.join(Q)}${Q}${Q}${q.content}`}function R(q){if(!q.content||typeof q.content==="string")throw Error(`Attachment "${q.filename}" requires Uint8Array content`);let O=N(q.filename??""),G=[`Content-Type: ${q.contentType??"application/octet-stream"}`,"Content-Transfer-Encoding: base64",`Content-Disposition: ${q.inline?"inline":"attachment"}; filename="${O}"`];if(q.contentId)G.push(`Content-ID: <${q.contentId}>`);if(q.headers)for(let[X,Y]of Object.entries(q.headers)){let Z=N(X),K=N(Y);G.push(`${Z}: ${K}`)}return`${G.join(Q)}${Q}${Q}${F(q.content)}`}function x(q,O){let G=O.map((X)=>`--${q}${Q}${X}`);return G.push(`--${q}--`),G.join(Q)}function f(){let q=crypto.getRandomValues(new Uint8Array(8)),O=Array.from(q,(G)=>G.toString(16).padStart(2,"0")).join("");return`<${Date.now()}.${O}@sently>`}function S(){let q=crypto.getRandomValues(new Uint8Array(12));return`----sently_${Array.from(q,(G)=>G.toString(16).padStart(2,"0")).join("")}`}function $(q,O){let G=`${q}: ${O}`;if(G.length<=76)return G;let X=[],Y=G;while(Y.length>76){let Z=Y.lastIndexOf(" ",76);if(Z<=q.length+1)Z=76;X.push(Y.slice(0,Z)),Y=` ${Y.slice(Z).trimStart()}`}return X.push(Y),X.join(`${Q} `)}
3
+ export{c as j};
4
+
5
+ //# debugId=E85475C2074C263364756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/core/mime.ts"],
4
+ "sourcesContent": [
5
+ "// src/core/mime.ts\nimport {\n assertSafeAddress,\n extractEmails,\n isValidEmail,\n parseAddresses,\n toMIMEHeader,\n} from \"./address.js\";\nimport { encodeBase64, encodeHeader, encodeUtf8 } from \"./base64.js\";\nimport type { Address, Attachment, DKIMConfig, Envelope, MailOptions } from \"./types.js\";\n\nfunction sanitizeHeaderValue(value: string): string {\n return value.replace(/\\r\\n?|\\n/g, \" \").trim();\n}\n\nfunction sanitizeAddress(addr: Address): Address {\n // Security check runs on the raw value FIRST and fails closed: any control\n // character (CR/LF/NUL/…) is rejected outright rather than stripped and\n // accepted. parseAddresses() already enforces this upstream; re-asserting\n // here keeps the function safe if it is ever called directly.\n assertSafeAddress(addr.address, \"address\");\n if (addr.name !== undefined) {\n assertSafeAddress(addr.name, \"display name\");\n }\n\n // Only ordinary surrounding whitespace is trimmed — the address identity is\n // never altered (no CR/LF-to-space repair).\n const address = addr.address.trim();\n if (!isValidEmail(address)) {\n throw new Error(`Invalid email address: ${JSON.stringify(addr.address)}`);\n }\n\n const sanitized: Address = { address };\n if (addr.name) {\n sanitized.name = sanitizeHeaderValue(addr.name);\n }\n return sanitized;\n}\n\n/** Result of building a complete MIME message. */\nexport interface MIMEBuildResult {\n /** Complete raw MIME message bytes ready to send. */\n raw: Uint8Array;\n /** SMTP envelope derived from From/To/Cc/Bcc. */\n envelope: Envelope;\n /** Message-ID assigned or supplied for the message. */\n messageId: string;\n /** Size of the raw MIME message in bytes. */\n size: number;\n}\n\nconst CRLF = \"\\r\\n\";\n\n/**\n * Build a complete MIME message as a Uint8Array ready for SMTP DATA.\n * When `dkim` is provided, signs the message and prepends the DKIM-Signature header.\n */\nexport async function buildMIME(options: MailOptions, dkim?: DKIMConfig): Promise<MIMEBuildResult> {\n const messageId = options.messageId ?? generateMessageId();\n const date = (options.date ?? new Date()).toUTCString();\n const fromAddrs = parseAddresses(options.from);\n const toAddrs = parseAddresses(options.to);\n const ccAddrs = options.cc ? parseAddresses(options.cc) : [];\n\n if (fromAddrs.length === 0) {\n throw new Error(\"Missing from address\");\n }\n if (toAddrs.length === 0) {\n throw new Error(\"Missing to address\");\n }\n\n const envelope: Envelope = {\n from: fromAddrs[0]?.address ?? \"\",\n to: [\n ...extractEmails(options.to),\n ...(options.cc ? extractEmails(options.cc) : []),\n ...(options.bcc ? extractEmails(options.bcc) : []),\n ],\n };\n\n const attachments = options.attachments ?? [];\n const inlineAttachments = attachments.filter((a) => a.inline || a.contentId);\n const regularAttachments = attachments.filter((a) => !a.inline && !a.contentId);\n\n let root = buildSimpleBody(options);\n\n if (inlineAttachments.length > 0) {\n const boundary = generateBoundary();\n root = {\n contentType: `multipart/related; boundary=\"${boundary}\"`,\n content: assembleMultipart(boundary, [\n formatNestedPart(buildSimpleBody(options)),\n ...inlineAttachments.map(formatAttachmentPart),\n ]),\n };\n }\n\n if (regularAttachments.length > 0) {\n const boundary = generateBoundary();\n root = {\n contentType: `multipart/mixed; boundary=\"${boundary}\"`,\n content: assembleMultipart(boundary, [\n formatNestedPart(root),\n ...regularAttachments.map(formatAttachmentPart),\n ]),\n };\n }\n\n const headers: string[] = [\n foldHeader(\"From\", fromAddrs.map((a) => toMIMEHeader(sanitizeAddress(a))).join(\", \")),\n foldHeader(\"To\", toAddrs.map((a) => toMIMEHeader(sanitizeAddress(a))).join(\", \")),\n ];\n\n if (ccAddrs.length > 0) {\n headers.push(foldHeader(\"Cc\", ccAddrs.map((a) => toMIMEHeader(sanitizeAddress(a))).join(\", \")));\n }\n\n if (options.replyTo) {\n headers.push(\n foldHeader(\n \"Reply-To\",\n parseAddresses(options.replyTo)\n .map((a) => toMIMEHeader(sanitizeAddress(a)))\n .join(\", \"),\n ),\n );\n }\n\n headers.push(\n foldHeader(\"Subject\", encodeHeader(sanitizeHeaderValue(options.subject))),\n foldHeader(\"Date\", date),\n foldHeader(\"Message-ID\", messageId),\n \"MIME-Version: 1.0\",\n );\n\n if (options.priority === \"high\") {\n headers.push(\"X-Priority: 1\", \"Importance: high\");\n } else if (options.priority === \"low\") {\n headers.push(\"X-Priority: 5\", \"Importance: low\");\n }\n\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n headers.push(foldHeader(sanitizeHeaderValue(key), sanitizeHeaderValue(value)));\n }\n }\n\n headers.push(`Content-Type: ${root.contentType}`);\n if (root.contentTransferEncoding) {\n headers.push(`Content-Transfer-Encoding: ${root.contentTransferEncoding}`);\n }\n\n const rawText = `${headers.join(CRLF)}${CRLF}${CRLF}${root.content}`;\n let raw = encodeUtf8(rawText);\n\n if (dkim) {\n const { signDKIM } = await import(\"../dkim.js\");\n const { header } = await signDKIM(raw, dkim);\n const signedText = `${header}${CRLF}${rawText}`;\n raw = encodeUtf8(signedText);\n }\n\n return { raw, envelope, messageId, size: raw.length };\n}\n\ninterface SimpleBody {\n contentType: string;\n contentTransferEncoding?: string;\n content: string;\n}\n\nfunction buildSimpleBody(options: MailOptions): SimpleBody {\n const hasText = Boolean(options.text);\n const hasHtml = Boolean(options.html);\n\n if (hasText && hasHtml) {\n const boundary = generateBoundary();\n return {\n contentType: `multipart/alternative; boundary=\"${boundary}\"`,\n content: assembleMultipart(boundary, [\n formatSimplePart({\n contentType: \"text/plain; charset=utf-8\",\n contentTransferEncoding: \"8bit\",\n content: options.text ?? \"\",\n }),\n formatSimplePart({\n contentType: \"text/html; charset=utf-8\",\n contentTransferEncoding: \"8bit\",\n content: options.html ?? \"\",\n }),\n ]),\n };\n }\n\n if (hasHtml) {\n return {\n contentType: \"text/html; charset=utf-8\",\n contentTransferEncoding: \"8bit\",\n content: options.html ?? \"\",\n };\n }\n\n return {\n contentType: \"text/plain; charset=utf-8\",\n contentTransferEncoding: \"8bit\",\n content: options.text ?? \"\",\n };\n}\n\nfunction formatSimplePart(part: SimpleBody): string {\n const headers = [`Content-Type: ${part.contentType}`];\n if (part.contentTransferEncoding) {\n headers.push(`Content-Transfer-Encoding: ${part.contentTransferEncoding}`);\n }\n return `${headers.join(CRLF)}${CRLF}${CRLF}${part.content}`;\n}\n\nfunction formatNestedPart(part: SimpleBody): string {\n const headers = [`Content-Type: ${part.contentType}`];\n if (part.contentTransferEncoding) {\n headers.push(`Content-Transfer-Encoding: ${part.contentTransferEncoding}`);\n }\n return `${headers.join(CRLF)}${CRLF}${CRLF}${part.content}`;\n}\n\nfunction formatAttachmentPart(attachment: Attachment): string {\n if (!attachment.content || typeof attachment.content === \"string\") {\n throw new Error(`Attachment \"${attachment.filename}\" requires Uint8Array content`);\n }\n\n const safeFilename = sanitizeHeaderValue(attachment.filename ?? \"\");\n const headers = [\n `Content-Type: ${attachment.contentType ?? \"application/octet-stream\"}`,\n \"Content-Transfer-Encoding: base64\",\n `Content-Disposition: ${attachment.inline ? \"inline\" : \"attachment\"}; filename=\"${safeFilename}\"`,\n ];\n\n if (attachment.contentId) {\n headers.push(`Content-ID: <${attachment.contentId}>`);\n }\n\n if (attachment.headers) {\n for (const [key, value] of Object.entries(attachment.headers)) {\n const safeKey = sanitizeHeaderValue(key);\n const safeValue = sanitizeHeaderValue(value);\n headers.push(`${safeKey}: ${safeValue}`);\n }\n }\n\n return `${headers.join(CRLF)}${CRLF}${CRLF}${encodeBase64(attachment.content)}`;\n}\n\nfunction assembleMultipart(boundary: string, parts: string[]): string {\n const segments = parts.map((part) => `--${boundary}${CRLF}${part}`);\n segments.push(`--${boundary}--`);\n return segments.join(CRLF);\n}\n\nfunction generateMessageId(): string {\n const random = crypto.getRandomValues(new Uint8Array(8));\n const hex = Array.from(random, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `<${Date.now()}.${hex}@sently>`;\n}\n\nfunction generateBoundary(): string {\n const random = crypto.getRandomValues(new Uint8Array(12));\n const hex = Array.from(random, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `----sently_${hex}`;\n}\n\nfunction foldHeader(name: string, value: string): string {\n const line = `${name}: ${value}`;\n if (line.length <= 76) {\n return line;\n }\n\n const chunks: string[] = [];\n let remaining = line;\n\n while (remaining.length > 76) {\n let breakAt = remaining.lastIndexOf(\" \", 76);\n if (breakAt <= name.length + 1) {\n breakAt = 76;\n }\n chunks.push(remaining.slice(0, breakAt));\n remaining = ` ${remaining.slice(breakAt).trimStart()}`;\n }\n chunks.push(remaining);\n\n return chunks.join(`${CRLF} `);\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "E85475C2074C263364756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,5 @@
1
+ var J=new TextEncoder;function P(k){let f=typeof k==="string"?J.encode(k):k,j="",A=0;while(A<f.length){let m=f[A]??0,q=f[A+1],z=f[A+2];if(q===void 0){j+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[m>>2],j+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(m&3)<<4],j+="==";break}if(z===void 0){j+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[m>>2],j+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(m&3)<<4|q>>4],j+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(q&15)<<2],j+="=";break}j+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[m>>2],j+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(m&3)<<4|q>>4],j+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(q&15)<<2|z>>6],j+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[z&63],A+=3}return R(j)}function S(k){let f=k.replace(/\s/g,""),j=f.length;if(j===0)return new Uint8Array(0);if(j%4!==0)throw Error("Invalid base64 string length");let A=f.endsWith("==")?2:f.endsWith("=")?1:0,m=j*3/4-A,q=new Uint8Array(m),z=0;for(let D=0;D<j;D+=4){let K=G(f[D]??"="),M=G(f[D+1]??"="),N=G(f[D+2]??"="),O=G(f[D+3]??"="),H=K<<18|M<<12|N<<6|O;if(z<m)q[z++]=H>>16&255;if(z<m)q[z++]=H>>8&255;if(z<m)q[z++]=H&255}return q}function W(k){if(!Q(k))return k;return`=?UTF-8?B?${P(k).replace(/\r\n/g,"")}?=`}function Q(k){for(let f=0;f<k.length;f++)if(k.charCodeAt(f)>127)return!0;return!1}function G(k){if(k==="=")return 0;let f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(k);if(f===-1)throw Error(`Invalid base64 character: ${k}`);return f}function R(k){let f=[];for(let j=0;j<k.length;j+=76)f.push(k.slice(j,j+76));return f.join(`\r
2
+ `)}function X(k){return J.encode(k)}
3
+ export{P as E,S as F,W as G,X as H};
4
+
5
+ //# debugId=CA1328BCB199FC6564756E2164756E21
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "// src/core/base64.ts\n\nconst BASE64_CHARS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nconst BASE64_LINE_LENGTH = 76;\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * Encode a Uint8Array or string to Base64.\n * Uses TextEncoder + manual base64 to support binary data correctly.\n */\nexport function encodeBase64(data: Uint8Array | string): string {\n const bytes = typeof data === \"string\" ? encoder.encode(data) : data;\n let result = \"\";\n let i = 0;\n\n while (i < bytes.length) {\n const b0 = bytes[i] ?? 0;\n const b1 = bytes[i + 1];\n const b2 = bytes[i + 2];\n\n if (b1 === undefined) {\n result += BASE64_CHARS[b0 >> 2];\n result += BASE64_CHARS[(b0 & 0x03) << 4];\n result += \"==\";\n break;\n }\n\n if (b2 === undefined) {\n result += BASE64_CHARS[b0 >> 2];\n result += BASE64_CHARS[((b0 & 0x03) << 4) | (b1 >> 4)];\n result += BASE64_CHARS[(b1 & 0x0f) << 2];\n result += \"=\";\n break;\n }\n\n result += BASE64_CHARS[b0 >> 2];\n result += BASE64_CHARS[((b0 & 0x03) << 4) | (b1 >> 4)];\n result += BASE64_CHARS[((b1 & 0x0f) << 2) | (b2 >> 6)];\n result += BASE64_CHARS[b2 & 0x3f];\n i += 3;\n }\n\n return wrapBase64Lines(result);\n}\n\n/**\n * Decode a Base64 string to Uint8Array.\n */\nexport function decodeBase64(data: string): Uint8Array {\n const cleaned = data.replace(/\\s/g, \"\");\n const len = cleaned.length;\n\n if (len === 0) {\n return new Uint8Array(0);\n }\n\n if (len % 4 !== 0) {\n throw new Error(\"Invalid base64 string length\");\n }\n\n const padding = cleaned.endsWith(\"==\") ? 2 : cleaned.endsWith(\"=\") ? 1 : 0;\n const outputLen = (len * 3) / 4 - padding;\n const output = new Uint8Array(outputLen);\n\n let outIndex = 0;\n for (let i = 0; i < len; i += 4) {\n const c0 = base64CharToValue(cleaned[i] ?? \"=\");\n const c1 = base64CharToValue(cleaned[i + 1] ?? \"=\");\n const c2 = base64CharToValue(cleaned[i + 2] ?? \"=\");\n const c3 = base64CharToValue(cleaned[i + 3] ?? \"=\");\n const triple = (c0 << 18) | (c1 << 12) | (c2 << 6) | c3;\n\n if (outIndex < outputLen) {\n output[outIndex++] = (triple >> 16) & 0xff;\n }\n if (outIndex < outputLen) {\n output[outIndex++] = (triple >> 8) & 0xff;\n }\n if (outIndex < outputLen) {\n output[outIndex++] = triple & 0xff;\n }\n }\n\n return output;\n}\n\n/**\n * Encode text using Quoted-Printable (RFC 2045).\n */\nexport function encodeQP(text: string): string {\n const bytes = encoder.encode(text);\n const lines: string[] = [];\n let line = \"\";\n\n for (let i = 0; i < bytes.length; i++) {\n const byte = bytes[i] ?? 0;\n\n if (byte === 0x0a) {\n lines.push(line);\n line = \"\";\n continue;\n }\n\n if (byte === 0x0d) {\n continue;\n }\n\n let encoded: string;\n if (\n (byte >= 33 && byte <= 60) ||\n (byte >= 62 && byte <= 126) ||\n byte === 0x09 ||\n byte === 0x20\n ) {\n encoded = String.fromCharCode(byte);\n } else {\n encoded = `=${byte.toString(16).toUpperCase().padStart(2, \"0\")}`;\n }\n\n if (line.length + encoded.length > 75) {\n lines.push(`${line}=`);\n line = encoded;\n } else {\n line += encoded;\n }\n }\n\n if (line.length > 0) {\n lines.push(line);\n }\n\n return lines.join(\"\\r\\n\");\n}\n\n/**\n * Encode an email header value per RFC 2047.\n * Non-ASCII values become: =?UTF-8?B?<base64>?=\n */\nexport function encodeHeader(value: string): string {\n if (!needsEncoding(value)) {\n return value;\n }\n\n const encoded = encodeBase64(value).replace(/\\r\\n/g, \"\");\n return `=?UTF-8?B?${encoded}?=`;\n}\n\n/**\n * Returns true if the string contains non-ASCII characters\n * and therefore requires RFC 2047 encoding in headers.\n */\nexport function needsEncoding(text: string): boolean {\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) > 127) {\n return true;\n }\n }\n return false;\n}\n\nfunction base64CharToValue(char: string): number {\n if (char === \"=\") {\n return 0;\n }\n const index = BASE64_CHARS.indexOf(char);\n if (index === -1) {\n throw new Error(`Invalid base64 character: ${char}`);\n }\n return index;\n}\n\nfunction wrapBase64Lines(base64: string): string {\n const lines: string[] = [];\n for (let i = 0; i < base64.length; i += BASE64_LINE_LENGTH) {\n lines.push(base64.slice(i, i + BASE64_LINE_LENGTH));\n }\n return lines.join(\"\\r\\n\");\n}\n\n/** Decode bytes to UTF-8 string. */\nexport function decodeUtf8(bytes: Uint8Array): string {\n return decoder.decode(bytes);\n}\n\n/** Encode string to UTF-8 bytes. */\nexport function encodeUtf8(text: string): Uint8Array {\n return encoder.encode(text);\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "93C9FABDDF825C4864756E2164756E21",
7
+ "mappings": "AAKA,IAAM,EAAU,IAAI,YAOb,SAAS,CAAY,CAAC,EAAmC,CAC9D,IAAM,EAAQ,OAAO,IAAS,SAAW,EAAQ,OAAO,CAAI,EAAI,EAC5D,EAAS,GACT,EAAI,EAER,MAAO,EAAI,EAAM,OAAQ,CACvB,IAAM,EAAK,EAAM,IAAM,EACjB,EAAK,EAAM,EAAI,GACf,EAAK,EAAM,EAAI,GAErB,GAAI,IAAO,OAAW,CACpB,GArBe,mEAqBQ,GAAM,GAC7B,GAtBe,mEAsBS,GAAK,IAAS,GACtC,GAAU,KACV,MAGF,GAAI,IAAO,OAAW,CACpB,GA5Be,mEA4BQ,GAAM,GAC7B,GA7Be,mEA6BU,GAAK,IAAS,EAAM,GAAM,GACnD,GA9Be,mEA8BS,GAAK,KAAS,GACtC,GAAU,IACV,MAGF,GAnCiB,mEAmCM,GAAM,GAC7B,GApCiB,mEAoCQ,GAAK,IAAS,EAAM,GAAM,GACnD,GArCiB,mEAqCQ,GAAK,KAAS,EAAM,GAAM,GACnD,GAtCiB,mEAsCM,EAAK,IAC5B,GAAK,EAGP,OAAO,EAAgB,CAAM,EAMxB,SAAS,CAAY,CAAC,EAA0B,CACrD,IAAM,EAAU,EAAK,QAAQ,MAAO,EAAE,EAChC,EAAM,EAAQ,OAEpB,GAAI,IAAQ,EACV,OAAO,IAAI,WAAW,CAAC,EAGzB,GAAI,EAAM,IAAM,EACd,MAAU,MAAM,8BAA8B,EAGhD,IAAM,EAAU,EAAQ,SAAS,IAAI,EAAI,EAAI,EAAQ,SAAS,GAAG,EAAI,EAAI,EACnE,EAAa,EAAM,EAAK,EAAI,EAC5B,EAAS,IAAI,WAAW,CAAS,EAEnC,EAAW,EACf,QAAS,EAAI,EAAG,EAAI,EAAK,GAAK,EAAG,CAC/B,IAAM,EAAK,EAAkB,EAAQ,IAAM,GAAG,EACxC,EAAK,EAAkB,EAAQ,EAAI,IAAM,GAAG,EAC5C,EAAK,EAAkB,EAAQ,EAAI,IAAM,GAAG,EAC5C,EAAK,EAAkB,EAAQ,EAAI,IAAM,GAAG,EAC5C,EAAU,GAAM,GAAO,GAAM,GAAO,GAAM,EAAK,EAErD,GAAI,EAAW,EACb,EAAO,KAAe,GAAU,GAAM,IAExC,GAAI,EAAW,EACb,EAAO,KAAe,GAAU,EAAK,IAEvC,GAAI,EAAW,EACb,EAAO,KAAc,EAAS,IAIlC,OAAO,EAuDF,SAAS,CAAY,CAAC,EAAuB,CAClD,GAAI,CAAC,EAAc,CAAK,EACtB,OAAO,EAIT,MAAO,aADS,EAAa,CAAK,EAAE,QAAQ,QAAS,EAAE,MAQlD,SAAS,CAAa,CAAC,EAAuB,CACnD,QAAS,EAAI,EAAG,EAAI,EAAK,OAAQ,IAC/B,GAAI,EAAK,WAAW,CAAC,EAAI,IACvB,MAAO,GAGX,MAAO,GAGT,SAAS,CAAiB,CAAC,EAAsB,CAC/C,GAAI,IAAS,IACX,MAAO,GAET,IAAM,EApKa,mEAoKQ,QAAQ,CAAI,EACvC,GAAI,IAAU,GACZ,MAAU,MAAM,6BAA6B,GAAM,EAErD,OAAO,EAGT,SAAS,CAAe,CAAC,EAAwB,CAC/C,IAAM,EAAkB,CAAC,EACzB,QAAS,EAAI,EAAG,EAAI,EAAO,OAAQ,GA5KV,GA6KvB,EAAM,KAAK,EAAO,MAAM,EAAG,EA7KJ,EA6K0B,CAAC,EAEpD,OAAO,EAAM,KAAK;AAAA,CAAM,EASnB,SAAS,CAAU,CAAC,EAA0B,CACnD,OAAO,EAAQ,OAAO,CAAI",
8
+ "debugId": "CA1328BCB199FC6564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -0,0 +1,4 @@
1
+ import{E as D,H as J}from"./chunk-6yggz45h.js";var Q="https://oauth2.googleapis.com/token",$="https://login.microsoftonline.com/common/oauth2/v2.0/token",V=30000;class W{config;cachedToken=null;expiresAt=0;refreshPromise=null;constructor(m){if(this.config=m,m.accessToken)this.cachedToken=m.accessToken,this.expiresAt=Date.now()+3600000}async getAccessToken(){if(this.config.getToken)return this.config.getToken();if(this.cachedToken&&Date.now()<this.expiresAt-V)return this.cachedToken;if(!this.refreshPromise)this.refreshPromise=this.refreshAccessToken().finally(()=>{this.refreshPromise=null});return this.refreshPromise}async refreshAccessToken(){if(this.config.getToken){let v=await this.config.getToken();return this.cachedToken=v,this.expiresAt=Date.now()+3600000,v}let m=this.config.tokenUrl??Q,z=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,refresh_token:this.config.refreshToken,grant_type:"refresh_token"}),q=await fetch(m,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:z.toString()});if(!q.ok){let v=await q.text();throw Error(`OAuth2 token refresh failed (${q.status}): ${v}`)}let C=await q.json();return this.cachedToken=C.access_token,this.expiresAt=Date.now()+C.expires_in*1000,C.access_token}async buildXOAUTH2(){let m=await this.getAccessToken(),z=`user=${this.config.user}\x01auth=Bearer ${m}\x01\x01`;return D(J(z)).replace(/\r\n/g,"")}}
2
+ export{Q as g,$ as h,W as i};
3
+
4
+ //# debugId=B98629F8950EE32E64756E2164756E21
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "/**\n * @module\n * OAuth2 / XOAUTH2 authentication for SMTP.\n * Supports Gmail, Microsoft 365, and custom OAuth2 providers.\n *\n * @example\n * ```ts\n * import { OAuth2Client } from \"sently/auth/oauth2\";\n * const client = new OAuth2Client({\n * user: \"me@gmail.com\",\n * clientId: \"...\",\n * clientSecret: \"...\",\n * refreshToken: \"...\",\n * });\n * const token = await client.getAccessToken();\n * ```\n */\nimport { encodeBase64, encodeUtf8 } from \"../core/base64.js\";\nimport type { OAuth2Config } from \"../core/types.js\";\n\n/** Default Google OAuth2 token endpoint. */\nexport const GOOGLE_TOKEN_URL = \"https://oauth2.googleapis.com/token\";\n\n/** Microsoft OAuth2 token endpoint (common tenant). */\nexport const MICROSOFT_TOKEN_URL = \"https://login.microsoftonline.com/common/oauth2/v2.0/token\";\n\n/** OAuth2 token endpoint response shape. */\nexport interface TokenResponse {\n /** Bearer access token for API or SMTP XOAUTH2. */\n access_token: string;\n /** Token lifetime in seconds. */\n expires_in: number;\n /** Token type (typically `\"Bearer\"`). */\n token_type: string;\n}\n\nconst EXPIRY_BUFFER_MS = 30_000;\n\n/**\n * OAuth2 client with in-memory token cache and automatic refresh.\n */\nexport class OAuth2Client {\n /** OAuth2 configuration supplied at construction. */\n private readonly config: OAuth2Config;\n /** Cached access token, or null before the first fetch. */\n private cachedToken: string | null = null;\n /** Expiry timestamp (ms) for the cached access token. */\n private expiresAt = 0;\n /** In-flight refresh promise used to deduplicate concurrent refreshes. */\n private refreshPromise: Promise<string> | null = null;\n\n /** Creates an OAuth2 client from configuration. */\n constructor(config: OAuth2Config) {\n this.config = config;\n if (config.accessToken) {\n this.cachedToken = config.accessToken;\n this.expiresAt = Date.now() + 3_600_000;\n }\n }\n\n /**\n * Get a valid access token (cached when still valid, refreshed otherwise).\n */\n async getAccessToken(): Promise<string> {\n if (this.config.getToken) {\n return this.config.getToken();\n }\n\n if (this.cachedToken && Date.now() < this.expiresAt - EXPIRY_BUFFER_MS) {\n return this.cachedToken;\n }\n\n if (!this.refreshPromise) {\n this.refreshPromise = this.refreshAccessToken().finally(() => {\n this.refreshPromise = null;\n });\n }\n return this.refreshPromise;\n }\n\n /**\n * Force-refresh the access token regardless of expiry.\n */\n async refreshAccessToken(): Promise<string> {\n if (this.config.getToken) {\n const token = await this.config.getToken();\n this.cachedToken = token;\n this.expiresAt = Date.now() + 3_600_000;\n return token;\n }\n\n const tokenUrl = this.config.tokenUrl ?? GOOGLE_TOKEN_URL;\n const body = new URLSearchParams({\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n refresh_token: this.config.refreshToken,\n grant_type: \"refresh_token\",\n });\n\n const response = await fetch(tokenUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: body.toString(),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`OAuth2 token refresh failed (${response.status}): ${text}`);\n }\n\n const data = (await response.json()) as TokenResponse;\n this.cachedToken = data.access_token;\n this.expiresAt = Date.now() + data.expires_in * 1000;\n return data.access_token;\n }\n\n /**\n * Build the XOAUTH2 SASL string for SMTP AUTH (base64-encoded).\n */\n async buildXOAUTH2(): Promise<string> {\n const token = await this.getAccessToken();\n const raw = `user=${this.config.user}\\x01auth=Bearer ${token}\\x01\\x01`;\n return encodeBase64(encodeUtf8(raw)).replace(/\\r\\n/g, \"\");\n }\n}\n"
6
6
  ],
7
- "mappings": ";;;;;;AAqBO,IAAM,mBAAmB;AAGzB,IAAM,sBAAsB;AAYnC,IAAM,mBAAmB;AAAA;AAKlB,MAAM,aAAa;AAAA,EAEP;AAAA,EAET,cAA6B;AAAA,EAE7B,YAAY;AAAA,EAEZ,iBAAyC;AAAA,EAGjD,WAAW,CAAC,QAAsB;AAAA,IAChC,KAAK,SAAS;AAAA,IACd,IAAI,OAAO,aAAa;AAAA,MACtB,KAAK,cAAc,OAAO;AAAA,MAC1B,KAAK,YAAY,KAAK,IAAI,IAAI;AAAA,IAChC;AAAA;AAAA,OAMI,eAAc,GAAoB;AAAA,IACtC,IAAI,KAAK,OAAO,UAAU;AAAA,MACxB,OAAO,KAAK,OAAO,SAAS;AAAA,IAC9B;AAAA,IAEA,IAAI,KAAK,eAAe,KAAK,IAAI,IAAI,KAAK,YAAY,kBAAkB;AAAA,MACtE,OAAO,KAAK;AAAA,IACd;AAAA,IAEA,IAAI,CAAC,KAAK,gBAAgB;AAAA,MACxB,KAAK,iBAAiB,KAAK,mBAAmB,EAAE,QAAQ,MAAM;AAAA,QAC5D,KAAK,iBAAiB;AAAA,OACvB;AAAA,IACH;AAAA,IACA,OAAO,KAAK;AAAA;AAAA,OAMR,mBAAkB,GAAoB;AAAA,IAC1C,IAAI,KAAK,OAAO,UAAU;AAAA,MACxB,MAAM,QAAQ,MAAM,KAAK,OAAO,SAAS;AAAA,MACzC,KAAK,cAAc;AAAA,MACnB,KAAK,YAAY,KAAK,IAAI,IAAI;AAAA,MAC9B,OAAO;AAAA,IACT;AAAA,IAEA,MAAM,WAAW,KAAK,OAAO,YAAY;AAAA,IACzC,MAAM,OAAO,IAAI,gBAAgB;AAAA,MAC/B,WAAW,KAAK,OAAO;AAAA,MACvB,eAAe,KAAK,OAAO;AAAA,MAC3B,eAAe,KAAK,OAAO;AAAA,MAC3B,YAAY;AAAA,IACd,CAAC;AAAA,IAED,MAAM,WAAW,MAAM,MAAM,UAAU;AAAA,MACrC,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,MAC/D,MAAM,KAAK,SAAS;AAAA,IACtB,CAAC;AAAA,IAED,IAAI,CAAC,SAAS,IAAI;AAAA,MAChB,MAAM,OAAO,MAAM,SAAS,KAAK;AAAA,MACjC,MAAM,IAAI,MAAM,gCAAgC,SAAS,YAAY,MAAM;AAAA,IAC7E;AAAA,IAEA,MAAM,OAAQ,MAAM,SAAS,KAAK;AAAA,IAClC,KAAK,cAAc,KAAK;AAAA,IACxB,KAAK,YAAY,KAAK,IAAI,IAAI,KAAK,aAAa;AAAA,IAChD,OAAO,KAAK;AAAA;AAAA,OAMR,aAAY,GAAoB;AAAA,IACpC,MAAM,QAAQ,MAAM,KAAK,eAAe;AAAA,IACxC,MAAM,MAAM,QAAQ,KAAK,OAAO,uBAAuB;AAAA,IACvD,OAAO,aAAa,WAAW,GAAG,CAAC,EAAE,QAAQ,SAAS,EAAE;AAAA;AAE5D;",
8
- "debugId": "3609E75C0C54F13D64756E2164756E21",
7
+ "mappings": "+CAqBO,IAAM,EAAmB,sCAGnB,EAAsB,6DAY7B,EAAmB,MAKlB,MAAM,CAAa,CAEP,OAET,YAA6B,KAE7B,UAAY,EAEZ,eAAyC,KAGjD,WAAW,CAAC,EAAsB,CAEhC,GADA,KAAK,OAAS,EACV,EAAO,YACT,KAAK,YAAc,EAAO,YAC1B,KAAK,UAAY,KAAK,IAAI,EAAI,aAO5B,eAAc,EAAoB,CACtC,GAAI,KAAK,OAAO,SACd,OAAO,KAAK,OAAO,SAAS,EAG9B,GAAI,KAAK,aAAe,KAAK,IAAI,EAAI,KAAK,UAAY,EACpD,OAAO,KAAK,YAGd,GAAI,CAAC,KAAK,eACR,KAAK,eAAiB,KAAK,mBAAmB,EAAE,QAAQ,IAAM,CAC5D,KAAK,eAAiB,KACvB,EAEH,OAAO,KAAK,oBAMR,mBAAkB,EAAoB,CAC1C,GAAI,KAAK,OAAO,SAAU,CACxB,IAAM,EAAQ,MAAM,KAAK,OAAO,SAAS,EAGzC,OAFA,KAAK,YAAc,EACnB,KAAK,UAAY,KAAK,IAAI,EAAI,QACvB,EAGT,IAAM,EAAW,KAAK,OAAO,UAAY,EACnC,EAAO,IAAI,gBAAgB,CAC/B,UAAW,KAAK,OAAO,SACvB,cAAe,KAAK,OAAO,aAC3B,cAAe,KAAK,OAAO,aAC3B,WAAY,eACd,CAAC,EAEK,EAAW,MAAM,MAAM,EAAU,CACrC,OAAQ,OACR,QAAS,CAAE,eAAgB,mCAAoC,EAC/D,KAAM,EAAK,SAAS,CACtB,CAAC,EAED,GAAI,CAAC,EAAS,GAAI,CAChB,IAAM,EAAO,MAAM,EAAS,KAAK,EACjC,MAAU,MAAM,gCAAgC,EAAS,YAAY,GAAM,EAG7E,IAAM,EAAQ,MAAM,EAAS,KAAK,EAGlC,OAFA,KAAK,YAAc,EAAK,aACxB,KAAK,UAAY,KAAK,IAAI,EAAI,EAAK,WAAa,KACzC,EAAK,kBAMR,aAAY,EAAoB,CACpC,IAAM,EAAQ,MAAM,KAAK,eAAe,EAClC,EAAM,QAAQ,KAAK,OAAO,uBAAuB,YACvD,OAAO,EAAa,EAAW,CAAG,CAAC,EAAE,QAAQ,QAAS,EAAE,EAE5D",
8
+ "debugId": "B98629F8950EE32E64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -0,0 +1,3 @@
1
+ import{i as U}from"./chunk-dgkh77yp.js";import{j as X}from"./chunk-2t6hjer3.js";import{p as b}from"./chunk-va2awz12.js";import{A as v,B as A,D as E,s as k,t as x,u as Z,v as O,w as q,x as L,y as j,z as N}from"./chunk-wgtbr6ge.js";import{I as C}from"./chunk-sqn04kae.js";class T{config;adapter=null;constructor(z){this.config=P(z)}async send(z){let B={...z,attachments:await b(z.attachments)},G=await X(B,this.config.dkim),F=await this.getAdapter(),W=this.config.direct?await M(G.envelope.from.split("@")[1]??this.config.host):this.config.host;await F.connect(W,this.config.port),this.adapter=F;try{return await D(F,this.config),await S(F,G)}finally{await H(F),this.adapter=null}}async verify(){try{let z=await this.getAdapter();await z.connect(this.config.host,this.config.port);try{return await D(z,this.config),{ok:!0,provider:"smtp"}}finally{await H(z)}}catch(z){return{ok:!1,provider:"smtp",message:z instanceof Error?z.message:String(z)}}}async close(){if(this.adapter)await this.adapter.close(),this.adapter=null}async getAdapter(){if(!this.config.adapter)throw new x("No socket adapter configured",0,"CONNECT","");return this.config.adapter}}function P(z){let B=z.secure??!1;return{host:z.host,port:z.port??(B?465:587),secure:B,...z.auth!==void 0?{auth:z.auth}:{},...z.requireTLS!==void 0?{requireTLS:z.requireTLS}:{},...z.dkim!==void 0?{dkim:z.dkim}:{},...z.tls!==void 0?{tls:z.tls}:{},...z.connectionTimeout!==void 0?{connectionTimeout:z.connectionTimeout}:{},...z.greetingTimeout!==void 0?{greetingTimeout:z.greetingTimeout}:{},...z.socketTimeout!==void 0?{socketTimeout:z.socketTimeout}:{},...z.direct!==void 0?{direct:z.direct}:{},...z.adapter!==void 0?{adapter:z.adapter}:{}}}async function D(z,B){let G=await J(z);N(G,[220],"greeting");let F=await I(z,B.host),W=F.some((Q)=>Q.toUpperCase()==="STARTTLS");if(!B.secure&&!z.secure&&W){await Y(z,Z({type:"STARTTLS"}));let Q=await J(z);N(Q,[220],"STARTTLS"),await z.startTLS(B.tls),F=await I(z,B.host)}if(B.auth){let Q=B.requireTLS??!0,V=z.secure||B.secure;if(Q&&!V)throw new x("Refusing to authenticate over unencrypted connection. Set requireTLS: false to disable this check (not recommended).",0,"AUTH","");await l(z,B.auth,F)}}async function S(z,B){await _(z,{type:"MAIL_FROM",address:B.envelope.from});let G=await J(z);N(G,[250],"MAIL FROM");let F=[],W=[];for(let K of B.envelope.to)if(await Y(z,Z({type:"RCPT_TO",address:K})),(await J(z)).isSuccess)F.push(K);else W.push(K);await _(z,{type:"DATA"});let Q=await J(z);N(Q,[354],"DATA");let V;try{await Y(z,Z({type:"DATA_BODY",content:B.raw})),V=await J(z)}catch(K){if(await Y(z,Z({type:"DATA_BODY",content:B.raw})),V=await J(z),V.isError)throw K}return N(V,[250],"DATA end"),{messageId:B.messageId,accepted:F,rejected:W,response:V.message,envelope:B.envelope}}async function H(z){try{await _(z,{type:"QUIT"}),await J(z)}catch{}finally{await z.close()}}async function I(z,B){await _(z,{type:"EHLO",domain:B});let G=await J(z);return N(G,[250],"EHLO"),j(G)}async function l(z,B,G){if(B.type==="OAUTH2"&&B.oauth2){let K=await new U(B.oauth2).buildXOAUTH2();await _(z,{type:"AUTH_XOAUTH2",xoauth2String:K});let $=await J(z);if($.code===334)await Y(z,E("")),$=await J(z);N($,[235],"AUTH XOAUTH2");return}let F=B.type??L(G);if(F==="CRAM-MD5"){let V=y(B,"CRAM-MD5");await _(z,{type:"AUTH_CRAM_MD5_INIT"});let K=await J(z);N(K,[334],"AUTH CRAM-MD5");let $=K.message.trim(),w=await k($,B.user,V);await _(z,{type:"AUTH_CRAM_MD5_RESPONSE",response:w}),K=await J(z),N(K,[235],"AUTH CRAM-MD5 response");return}if(F==="PLAIN"){let V=y(B,"PLAIN");await Y(z,Z({type:"AUTH_PLAIN",user:B.user,pass:V}));let K=await J(z);N(K,[235],"AUTH PLAIN");return}let W=y(B,"LOGIN");await Y(z,Z({type:"AUTH_LOGIN",user:B.user,pass:W}));let Q=await J(z);N(Q,[334],"AUTH LOGIN"),await Y(z,A(B.user)),Q=await J(z),N(Q,[334],"AUTH LOGIN user"),await Y(z,v(W)),Q=await J(z),N(Q,[235],"AUTH LOGIN pass")}function y(z,B){if(!z.pass)throw new x(`Password required for ${B} authentication`,0,`AUTH ${B}`,"");return z.pass}async function _(z,B){await Y(z,Z(B))}async function Y(z,B){await z.write(B)}async function J(z){let B=[];for await(let G of z.read()){B.push(G);let F=q(B);if(F)return O(F)}throw new x("Connection closed while reading SMTP response",0,"READ","")}async function M(z){let G=await(await import("node:dns/promises")).resolveMx(z);if(G.length===0)throw new x(`No MX records for ${z}`,0,"MX","");return G.sort((F,W)=>F.priority-W.priority),G[0]?.exchange??z}export{T as a,P as b,D as c,S as d,H as e,J as f};
2
+
3
+ //# debugId=812F038BA87E1B8464756E2164756E21