sently 0.4.5 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/README.md +94 -41
- package/dist/adapters/bun.d.ts +7 -0
- package/dist/adapters/bun.js +2 -183
- package/dist/adapters/bun.js.map +3 -3
- package/dist/adapters/cf.d.ts +6 -0
- package/dist/adapters/cf.js +2 -77
- package/dist/adapters/cf.js.map +3 -3
- package/dist/adapters/deno.d.ts +4 -0
- package/dist/adapters/deno.js +2 -72
- package/dist/adapters/deno.js.map +3 -3
- package/dist/adapters/node.d.ts +7 -0
- package/dist/adapters/node.js +2 -180
- package/dist/adapters/node.js.map +3 -3
- package/dist/auth/oauth2.d.ts +4 -0
- package/dist/auth/oauth2.js +2 -13
- package/dist/auth/oauth2.js.map +1 -1
- package/dist/chunk-2kcwa9gt.js +4 -0
- package/dist/chunk-2kcwa9gt.js.map +11 -0
- package/dist/chunk-2t6hjer3.js +5 -0
- package/dist/chunk-2t6hjer3.js.map +10 -0
- package/dist/chunk-6yggz45h.js +5 -0
- package/dist/{chunk-794hc3m4.js.map → chunk-6yggz45h.js.map} +2 -2
- package/dist/chunk-dgkh77yp.js +4 -0
- package/dist/chunk-dgkh77yp.js.map +10 -0
- package/dist/chunk-jfs80vhp.js +3 -0
- package/dist/chunk-jfs80vhp.js.map +10 -0
- package/dist/chunk-sqn04kae.js +4 -0
- package/dist/{chunk-v0bahtg2.js.map → chunk-sqn04kae.js.map} +1 -1
- package/dist/chunk-va2awz12.js +4 -0
- package/dist/{chunk-f4c9ttmr.js.map → chunk-va2awz12.js.map} +2 -2
- package/dist/chunk-wgtbr6ge.js +13 -0
- package/dist/chunk-wgtbr6ge.js.map +11 -0
- package/dist/core/mime.d.ts +4 -0
- package/dist/core/sigv4.d.ts +10 -0
- package/dist/core/smtp.d.ts +5 -0
- package/dist/core/smtp.js +2 -31
- package/dist/core/smtp.js.map +1 -1
- package/dist/core/types.d.ts +7 -0
- package/dist/detect.d.ts +2 -0
- package/dist/detect.js +2 -180
- package/dist/detect.js.map +4 -5
- package/dist/dkim.d.ts +21 -0
- package/dist/dkim.js +9 -0
- package/dist/dkim.js.map +10 -0
- package/dist/index.d.ts +74 -16
- package/dist/index.js +85 -14
- package/dist/mailer.d.ts +16 -0
- package/dist/mailer.js +3 -0
- package/dist/mailer.js.map +9 -0
- package/dist/plugins/template.js +2 -28
- package/dist/plugins/template.js.map +2 -2
- package/dist/pool/connection.d.ts +4 -0
- package/dist/pool/pool.d.ts +20 -0
- package/dist/pool/pool.js +2 -16
- package/dist/pool/pool.js.map +5 -3
- package/dist/transports/brevo.d.ts +1 -0
- package/dist/transports/brevo.js +2 -115
- package/dist/transports/brevo.js.map +3 -3
- package/dist/transports/mailgun.d.ts +3 -0
- package/dist/transports/mailgun.js +2 -119
- package/dist/transports/mailgun.js.map +3 -3
- package/dist/transports/postmark.d.ts +1 -0
- package/dist/transports/postmark.js +2 -113
- package/dist/transports/postmark.js.map +3 -3
- package/dist/transports/preview.d.ts +3 -0
- package/dist/transports/preview.js +2 -72
- package/dist/transports/preview.js.map +3 -3
- package/dist/transports/resend.d.ts +2 -0
- package/dist/transports/resend.js +2 -109
- package/dist/transports/resend.js.map +3 -3
- package/dist/transports/retry.d.ts +12 -1
- package/dist/transports/retry.js +2 -78
- package/dist/transports/retry.js.map +3 -3
- package/dist/transports/sendgrid.d.ts +1 -0
- package/dist/transports/sendgrid.js +2 -132
- package/dist/transports/sendgrid.js.map +3 -3
- package/dist/transports/ses.d.ts +5 -0
- package/dist/transports/ses.js +5 -251
- package/dist/transports/ses.js.map +4 -4
- package/dist/transports/smtp.d.ts +3 -0
- package/dist/transports/smtp.js +2 -26
- package/dist/transports/smtp.js.map +1 -1
- package/package.json +17 -6
- package/dist/chunk-794hc3m4.js +0 -105
- package/dist/chunk-7fqv71z1.js +0 -251
- package/dist/chunk-7fqv71z1.js.map +0 -10
- package/dist/chunk-f4c9ttmr.js +0 -154
- package/dist/chunk-mp5c9bfd.js +0 -270
- package/dist/chunk-mp5c9bfd.js.map +0 -11
- package/dist/chunk-tymfm441.js +0 -405
- package/dist/chunk-tymfm441.js.map +0 -11
- package/dist/chunk-v0bahtg2.js +0 -6
- package/dist/chunk-x3szga4k.js +0 -367
- package/dist/chunk-x3szga4k.js.map +0 -11
- package/dist/chunk-ym3zzv8b.js +0 -74
- package/dist/chunk-ym3zzv8b.js.map +0 -10
package/dist/adapters/cf.js
CHANGED
|
@@ -1,78 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
__require
|
|
3
|
-
} from "../chunk-v0bahtg2.js";
|
|
1
|
+
import{I as q}from"../chunk-sqn04kae.js";class w{socket=null;writer=null;_secure;_connected=!1;directTls;starttls;constructor(b={}){this._secure=b.secure??!1,this.directTls=b.secure??!1,this.starttls=b.starttls??!this.directTls}get secure(){return this._secure}get connected(){return this._connected}async connect(b,g){let{connect:j}=await import("cloudflare:sockets"),m=this.directTls?"on":this.starttls?"starttls":"off";this.socket=j({hostname:b,port:g},{secureTransport:m}),this.writer=this.socket.writable.getWriter(),this._connected=!0,this._secure=m==="on"}async startTLS(b){if(!this.socket||this._secure)throw Error("Cannot STARTTLS: no plain socket available");await this.writer?.close(),this.socket=this.socket.startTls(),this.writer=this.socket.writable.getWriter(),this._secure=!0}async write(b){if(!this.writer)throw Error("Socket not connected");await this.writer.write(b)}async*read(){if(!this.socket)throw Error("Socket not connected");let b=this.socket.readable.getReader();try{while(!0){let{value:g,done:j}=await b.read();if(j)break;if(g)yield g}}finally{b.releaseLock()}}async close(){await this.writer?.close(),await this.socket?.close(),this.writer=null,this.socket=null,this._connected=!1}}export{w as CloudflareAdapter};
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
class CloudflareAdapter {
|
|
7
|
-
socket = null;
|
|
8
|
-
writer = null;
|
|
9
|
-
_secure;
|
|
10
|
-
_connected = false;
|
|
11
|
-
directTls;
|
|
12
|
-
starttls;
|
|
13
|
-
constructor(options = {}) {
|
|
14
|
-
this._secure = options.secure ?? false;
|
|
15
|
-
this.directTls = options.secure ?? false;
|
|
16
|
-
this.starttls = options.starttls ?? !this.directTls;
|
|
17
|
-
}
|
|
18
|
-
get secure() {
|
|
19
|
-
return this._secure;
|
|
20
|
-
}
|
|
21
|
-
get connected() {
|
|
22
|
-
return this._connected;
|
|
23
|
-
}
|
|
24
|
-
async connect(host, port) {
|
|
25
|
-
const { connect } = await import("cloudflare:sockets");
|
|
26
|
-
const secureTransport = this.directTls ? "on" : this.starttls ? "starttls" : "off";
|
|
27
|
-
this.socket = connect({ hostname: host, port }, { secureTransport });
|
|
28
|
-
this.writer = this.socket.writable.getWriter();
|
|
29
|
-
this._connected = true;
|
|
30
|
-
this._secure = secureTransport === "on";
|
|
31
|
-
}
|
|
32
|
-
async startTLS(_options) {
|
|
33
|
-
if (!this.socket || this._secure) {
|
|
34
|
-
throw new Error("Cannot STARTTLS: no plain socket available");
|
|
35
|
-
}
|
|
36
|
-
await this.writer?.close();
|
|
37
|
-
this.socket = this.socket.startTls();
|
|
38
|
-
this.writer = this.socket.writable.getWriter();
|
|
39
|
-
this._secure = true;
|
|
40
|
-
}
|
|
41
|
-
async write(data) {
|
|
42
|
-
if (!this.writer) {
|
|
43
|
-
throw new Error("Socket not connected");
|
|
44
|
-
}
|
|
45
|
-
await this.writer.write(data);
|
|
46
|
-
}
|
|
47
|
-
async* read() {
|
|
48
|
-
if (!this.socket) {
|
|
49
|
-
throw new Error("Socket not connected");
|
|
50
|
-
}
|
|
51
|
-
const reader = this.socket.readable.getReader();
|
|
52
|
-
try {
|
|
53
|
-
while (true) {
|
|
54
|
-
const { value, done } = await reader.read();
|
|
55
|
-
if (done) {
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
if (value) {
|
|
59
|
-
yield value;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
} finally {
|
|
63
|
-
reader.releaseLock();
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
async close() {
|
|
67
|
-
await this.writer?.close();
|
|
68
|
-
await this.socket?.close();
|
|
69
|
-
this.writer = null;
|
|
70
|
-
this.socket = null;
|
|
71
|
-
this._connected = false;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
export {
|
|
75
|
-
CloudflareAdapter
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
//# debugId=035AC57F8987550264756E2164756E21
|
|
3
|
+
//# debugId=698255E287F8C83164756E2164756E21
|
package/dist/adapters/cf.js.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/adapters/cf.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * @module\n * Cloudflare Workers socket adapter for SMTP via cloudflare:sockets.\n *\n * @example\n * ```ts\n * import { CloudflareAdapter } from \"sently/adapters/cf\";\n * import { createMailer } from \"sently\";\n *\n * const mailer = await createMailer({\n * host: \"smtp.example.com\",\n * adapter: new CloudflareAdapter(),\n * auth: { user: \"relay@example.com\", pass: \"secret\" },\n * });\n * ```\n */\nimport type { SocketAdapter, TLSOptions } from \"../core/types.js\";\n\ninterface CFSocket {\n readonly readable: ReadableStream<Uint8Array>;\n readonly writable: WritableStream<Uint8Array>;\n readonly closed: Promise<void>;\n close(): Promise<void>;\n startTls(): CFSocket;\n}\n\ntype CFConnect = (\n address: { hostname: string; port: number },\n options?: { secureTransport?: \"off\" | \"on\" | \"starttls\"; allowHalfOpen?: boolean },\n) => CFSocket;\n\n/** Configuration options for {@link CloudflareAdapter}. */\nexport interface CloudflareAdapterOptions {\n /** Use implicit TLS on connect (secureTransport: \"on\"). Default: false. */\n secure?: boolean;\n /** Enable STARTTLS upgrade after plain connect. Default: true when not secure. */\n starttls?: boolean;\n /** Reserved for future TLS tuning (Workers sockets API). */\n tls?: TLSOptions;\n}\n\n/**\n * Cloudflare Workers socket adapter via cloudflare:sockets.\n *\n * Limitations:\n * - No connection pooling (isolate lifecycle)\n * - No file system access for attachment.path\n * - No DNS MX lookup — explicit SMTP relay host required\n */\nexport class CloudflareAdapter implements SocketAdapter {\n private socket: CFSocket | null = null;\n private writer: WritableStreamDefaultWriter<Uint8Array> | null = null;\n private _secure: boolean;\n private _connected = false;\n private readonly directTls: boolean;\n private readonly starttls: boolean;\n\n /** Creates a Cloudflare Workers socket adapter. */\n constructor(options: CloudflareAdapterOptions = {}) {\n this._secure = options.secure ?? false;\n this.directTls = options.secure ?? false;\n this.starttls = options.starttls ?? !this.directTls;\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 const { connect } = (await import(\"cloudflare:sockets\")) as { connect: CFConnect };\n\n const secureTransport = this.directTls ? \"on\" : this.starttls ? \"starttls\" : \"off\";\n this.socket = connect({ hostname: host, port }, { secureTransport });\n this.writer = this.socket.writable.getWriter();\n this._connected = true;\n this._secure = secureTransport === \"on\";\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 await this.writer?.close();\n this.socket = this.socket.startTls();\n this.writer = this.socket.writable.getWriter();\n this._secure = true;\n }\n\n /** Writes raw bytes to the socket. */\n async write(data: Uint8Array): Promise<void> {\n if (!this.writer) {\n throw new Error(\"Socket not connected\");\n }\n await this.writer.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.socket) {\n throw new Error(\"Socket not connected\");\n }\n\n const reader = this.socket.readable.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n break;\n }\n if (value) {\n yield value;\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n /** Closes the socket connection. */\n async close(): Promise<void> {\n await this.writer?.close();\n await this.socket?.close();\n this.writer = null;\n this.socket = null;\n this._connected = false;\n }\n}\n"
|
|
5
|
+
"/**\n * @module\n * Cloudflare Workers socket adapter for SMTP via cloudflare:sockets.\n *\n * @example\n * ```ts\n * import { CloudflareAdapter } from \"sently/adapters/cf\";\n * import { createMailer } from \"sently\";\n *\n * const mailer = await createMailer({\n * host: \"smtp.example.com\",\n * adapter: new CloudflareAdapter(),\n * auth: { user: \"relay@example.com\", pass: \"secret\" },\n * });\n * ```\n */\nimport type { SocketAdapter, TLSOptions } from \"../core/types.js\";\n\ninterface CFSocket {\n readonly readable: ReadableStream<Uint8Array>;\n readonly writable: WritableStream<Uint8Array>;\n readonly closed: Promise<void>;\n close(): Promise<void>;\n startTls(): CFSocket;\n}\n\ntype CFConnect = (\n address: { hostname: string; port: number },\n options?: { secureTransport?: \"off\" | \"on\" | \"starttls\"; allowHalfOpen?: boolean },\n) => CFSocket;\n\n/** Configuration options for {@link CloudflareAdapter}. */\nexport interface CloudflareAdapterOptions {\n /** Use implicit TLS on connect (secureTransport: \"on\"). Default: false. */\n secure?: boolean;\n /** Enable STARTTLS upgrade after plain connect. Default: true when not secure. */\n starttls?: boolean;\n /** Reserved for future TLS tuning (Workers sockets API). */\n tls?: TLSOptions;\n}\n\n/**\n * Cloudflare Workers socket adapter via cloudflare:sockets.\n *\n * Limitations:\n * - No connection pooling (isolate lifecycle)\n * - No file system access for attachment.path\n * - No DNS MX lookup — explicit SMTP relay host required\n */\nexport class CloudflareAdapter implements SocketAdapter {\n /** Underlying Cloudflare Workers socket. */\n private socket: CFSocket | null = null;\n /** Writable stream writer for outbound bytes. */\n private writer: WritableStreamDefaultWriter<Uint8Array> | null = null;\n /** Whether the connection is currently encrypted. */\n private _secure: boolean;\n /** Whether the socket is connected. */\n private _connected = false;\n /** Whether implicit TLS is used on connect (port 465 style). */\n private readonly directTls: boolean;\n /** Whether STARTTLS upgrade is enabled after plain connect. */\n private readonly starttls: boolean;\n\n /** Creates a Cloudflare Workers socket adapter. */\n constructor(options: CloudflareAdapterOptions = {}) {\n this._secure = options.secure ?? false;\n this.directTls = options.secure ?? false;\n this.starttls = options.starttls ?? !this.directTls;\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 const { connect } = (await import(\"cloudflare:sockets\")) as { connect: CFConnect };\n\n const secureTransport = this.directTls ? \"on\" : this.starttls ? \"starttls\" : \"off\";\n this.socket = connect({ hostname: host, port }, { secureTransport });\n this.writer = this.socket.writable.getWriter();\n this._connected = true;\n this._secure = secureTransport === \"on\";\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 await this.writer?.close();\n this.socket = this.socket.startTls();\n this.writer = this.socket.writable.getWriter();\n this._secure = true;\n }\n\n /** Writes raw bytes to the socket. */\n async write(data: Uint8Array): Promise<void> {\n if (!this.writer) {\n throw new Error(\"Socket not connected\");\n }\n await this.writer.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.socket) {\n throw new Error(\"Socket not connected\");\n }\n\n const reader = this.socket.readable.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n break;\n }\n if (value) {\n yield value;\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n /** Closes the socket connection. */\n async close(): Promise<void> {\n await this.writer?.close();\n await this.socket?.close();\n this.writer = null;\n this.socket = null;\n this._connected = false;\n }\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "yCAiDO,MAAM,CAA2C,CAE9C,OAA0B,KAE1B,OAAyD,KAEzD,QAEA,WAAa,GAEJ,UAEA,SAGjB,WAAW,CAAC,EAAoC,CAAC,EAAG,CAClD,KAAK,QAAU,EAAQ,QAAU,GACjC,KAAK,UAAY,EAAQ,QAAU,GACnC,KAAK,SAAW,EAAQ,UAAY,CAAC,KAAK,aAIxC,OAAM,EAAY,CACpB,OAAO,KAAK,WAIV,UAAS,EAAY,CACvB,OAAO,KAAK,gBAIR,QAAO,CAAC,EAAc,EAA6B,CACvD,IAAQ,WAAa,KAAa,8BAE5B,EAAkB,KAAK,UAAY,KAAO,KAAK,SAAW,WAAa,MAC7E,KAAK,OAAS,EAAQ,CAAE,SAAU,EAAM,MAAK,EAAG,CAAE,iBAAgB,CAAC,EACnE,KAAK,OAAS,KAAK,OAAO,SAAS,UAAU,EAC7C,KAAK,WAAa,GAClB,KAAK,QAAU,IAAoB,UAI/B,SAAQ,CAAC,EAAsC,CACnD,GAAI,CAAC,KAAK,QAAU,KAAK,QACvB,MAAU,MAAM,4CAA4C,EAG9D,MAAM,KAAK,QAAQ,MAAM,EACzB,KAAK,OAAS,KAAK,OAAO,SAAS,EACnC,KAAK,OAAS,KAAK,OAAO,SAAS,UAAU,EAC7C,KAAK,QAAU,QAIX,MAAK,CAAC,EAAiC,CAC3C,GAAI,CAAC,KAAK,OACR,MAAU,MAAM,sBAAsB,EAExC,MAAM,KAAK,OAAO,MAAM,CAAI,QAIvB,IAAI,EAA8C,CACvD,GAAI,CAAC,KAAK,OACR,MAAU,MAAM,sBAAsB,EAGxC,IAAM,EAAS,KAAK,OAAO,SAAS,UAAU,EAC9C,GAAI,CACF,MAAO,GAAM,CACX,IAAQ,QAAO,QAAS,MAAM,EAAO,KAAK,EAC1C,GAAI,EACF,MAEF,GAAI,EACF,MAAM,UAGV,CACA,EAAO,YAAY,QAKjB,MAAK,EAAkB,CAC3B,MAAM,KAAK,QAAQ,MAAM,EACzB,MAAM,KAAK,QAAQ,MAAM,EACzB,KAAK,OAAS,KACd,KAAK,OAAS,KACd,KAAK,WAAa,GAEtB",
|
|
8
|
+
"debugId": "698255E287F8C83164756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/adapters/deno.d.ts
CHANGED
|
@@ -28,9 +28,13 @@ export interface DenoAdapterOptions {
|
|
|
28
28
|
* Deno socket adapter using Deno.connect / Deno.startTls.
|
|
29
29
|
*/
|
|
30
30
|
export declare class DenoAdapter implements SocketAdapter {
|
|
31
|
+
/** Active Deno TCP or TLS connection. */
|
|
31
32
|
private conn;
|
|
33
|
+
/** Whether the connection is currently encrypted. */
|
|
32
34
|
private _secure;
|
|
35
|
+
/** Whether the socket is connected. */
|
|
33
36
|
private _connected;
|
|
37
|
+
/** TLS options for direct TLS and STARTTLS upgrades. */
|
|
34
38
|
private readonly tlsOptions;
|
|
35
39
|
/** Creates a Deno socket adapter (requires the Deno runtime). */
|
|
36
40
|
constructor(options?: DenoAdapterOptions);
|
package/dist/adapters/deno.js
CHANGED
|
@@ -1,73 +1,3 @@
|
|
|
1
|
-
import"../chunk-
|
|
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
|
-
|
|
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
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/adapters/deno.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
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 private conn: DenoConn | null = null;\n private _secure: boolean;\n private _connected = false;\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"
|
|
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": "
|
|
8
|
-
"debugId": "
|
|
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
|
}
|
package/dist/adapters/node.d.ts
CHANGED
|
@@ -12,10 +12,15 @@ export interface NodeAdapterOptions {
|
|
|
12
12
|
* Node.js socket adapter using node:net and node:tls.
|
|
13
13
|
*/
|
|
14
14
|
export declare class NodeAdapter implements SocketAdapter {
|
|
15
|
+
/** Underlying Node.js TCP or TLS socket. */
|
|
15
16
|
private socket;
|
|
17
|
+
/** Whether the connection is currently encrypted. */
|
|
16
18
|
private _secure;
|
|
19
|
+
/** Whether the socket is connected. */
|
|
17
20
|
private _connected;
|
|
21
|
+
/** Socket connect timeout in milliseconds. */
|
|
18
22
|
private readonly connectionTimeout;
|
|
23
|
+
/** TLS options for direct TLS and STARTTLS upgrades. */
|
|
19
24
|
private readonly tlsOptions;
|
|
20
25
|
/** Creates a Node.js socket adapter. */
|
|
21
26
|
constructor(options?: NodeAdapterOptions);
|
|
@@ -33,6 +38,8 @@ export declare class NodeAdapter implements SocketAdapter {
|
|
|
33
38
|
read(): AsyncGenerator<Uint8Array, void, unknown>;
|
|
34
39
|
/** Closes the socket connection. */
|
|
35
40
|
close(): Promise<void>;
|
|
41
|
+
/** Opens a plain TCP connection to the SMTP server. */
|
|
36
42
|
private connectPlain;
|
|
43
|
+
/** Opens a direct TLS connection to the SMTP server. */
|
|
37
44
|
private connectTls;
|
|
38
45
|
}
|
package/dist/adapters/node.js
CHANGED
|
@@ -1,181 +1,3 @@
|
|
|
1
|
-
import"../chunk-
|
|
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
|
-
|
|
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
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/adapters/node.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
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 private socket: net.Socket | tls.TLSSocket | null = null;\n private _secure: boolean;\n private _connected = false;\n private readonly connectionTimeout: number;\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 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 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"
|
|
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": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "6BAgBA,wBACA,wBAGA,SAAS,CAA8B,CAAC,EAAuB,CAC7D,GAAI,EAAI,qBAAuB,GAC7B,QAAQ,KACN,uGAEF,EAiBG,MAAM,CAAqC,CAExC,OAA4C,KAE5C,QAEA,WAAa,GAEJ,kBAEA,WAGjB,WAAW,CAAC,EAA8B,CAAC,EAAG,CAC5C,KAAK,QAAU,EAAQ,QAAU,GACjC,KAAK,kBAAoB,EAAQ,mBAAqB,MACtD,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,MAAM,KAAK,WAAW,EAAM,CAAI,EAEhC,WAAM,KAAK,aAAa,EAAM,CAAI,EAEpC,KAAK,WAAa,QAId,SAAQ,CAAC,EAAqC,CAClD,GAAI,CAAC,KAAK,QAAU,KAAK,QACvB,MAAU,MAAM,4CAA4C,EAG9D,IAAM,EAAQ,KAAK,OACb,EAAS,IAAK,KAAK,cAAe,CAAQ,EAChD,EAA+B,CAAM,EAErC,MAAM,IAAI,QAAc,CAAC,EAAS,IAAW,CAC3C,IAAM,EAAY,EAAI,QAAQ,CAC5B,OAAQ,EACR,WAAY,EAAO,WACnB,mBAAoB,EAAO,oBAAsB,GACjD,WAAY,EAAO,UACrB,CAAC,EAED,EAAU,KAAK,gBAAiB,IAAM,CACpC,KAAK,OAAS,EACd,KAAK,QAAU,GACf,EAAQ,EACT,EACD,EAAU,KAAK,QAAS,CAAM,EAC/B,OAIG,MAAK,CAAC,EAAiC,CAC3C,GAAI,CAAC,KAAK,OACR,MAAU,MAAM,sBAAsB,EAGxC,MAAM,IAAI,QAAc,CAAC,EAAS,IAAW,CAC3C,KAAK,QAAQ,MAAM,OAAO,KAAK,CAAI,EAAG,CAAC,IAAkC,CACvE,GAAI,EACF,EAAO,CAAG,EAEV,OAAQ,EAEX,EACF,QAII,IAAI,EAA8C,CACvD,GAAI,CAAC,KAAK,OACR,MAAU,MAAM,sBAAsB,EAGxC,IAAM,EAAS,KAAK,OACd,EAAsB,CAAC,EACzB,EAAoE,KACpE,EAAO,GACP,EAAsB,KAEpB,EAAS,CAAC,IAAwB,CACtC,IAAM,EAAO,IAAI,WAAW,CAAK,EACjC,GAAI,EACF,EAAY,CAAE,MAAO,EAAM,KAAM,EAAM,CAAC,EACxC,EAAc,KAEd,OAAM,KAAK,CAAI,GAIb,EAAU,CAAC,IAAqB,CAEpC,GADA,EAAQ,EACJ,EACF,EAAY,CAAE,MAAO,OAAoC,KAAM,EAAK,CAAC,EACrE,EAAc,KAEhB,EAAO,IAGH,EAAU,IAAY,CAE1B,GADA,EAAO,GACH,EACF,EAAY,CAAE,MAAO,OAAoC,KAAM,EAAK,CAAC,EACrE,EAAc,MAIlB,EAAO,GAAG,OAAQ,CAAM,EACxB,EAAO,GAAG,QAAS,CAAO,EAC1B,EAAO,GAAG,QAAS,CAAO,EAE1B,GAAI,CACF,MAAO,CAAC,GAAQ,EAAM,OAAS,EAAG,CAChC,GAAI,EACF,MAAM,EAER,GAAI,EAAM,OAAS,EAAG,CACpB,MAAM,EAAM,MAAM,EAClB,SAEF,GAAI,EACF,MAEF,IAAM,EAAQ,MAAM,IAAI,QAAoC,CAAC,IAAY,CACvE,EAAc,EACf,EACD,GAAI,EAAM,KACR,MAEF,MAAM,EAAM,cAEd,CACA,EAAO,IAAI,OAAQ,CAAM,EACzB,EAAO,IAAI,QAAS,CAAO,EAC3B,EAAO,IAAI,QAAS,CAAO,QAKzB,MAAK,EAAkB,CAC3B,GAAI,CAAC,KAAK,OACR,OAGF,MAAM,IAAI,QAAc,CAAC,IAAY,CACnC,KAAK,QAAQ,IAAI,IAAM,EAAQ,CAAC,EACjC,EACD,KAAK,OAAS,KACd,KAAK,WAAa,GAIZ,YAAY,CAAC,EAAc,EAA6B,CAC9D,OAAO,IAAI,QAAQ,CAAC,EAAS,IAAW,CACtC,IAAM,EAAS,EAAI,QAAQ,CAAE,OAAM,MAAK,EAAG,IAAM,EAAQ,CAAC,EAC1D,EAAO,WAAW,KAAK,iBAAiB,EACxC,EAAO,KAAK,UAAW,IAAM,CAC3B,EAAO,QAAQ,EACf,EAAW,MAAM,oBAAoB,CAAC,EACvC,EACD,EAAO,KAAK,QAAS,CAAM,EAC3B,KAAK,OAAS,EACf,EAIK,UAAU,CAAC,EAAc,EAA6B,CAE5D,OADA,EAA+B,KAAK,UAAU,EACvC,IAAI,QAAQ,CAAC,EAAS,IAAW,CACtC,IAAM,EAAS,EAAI,QACjB,CACE,OACA,OACA,WAAY,KAAK,WAAW,YAAc,EAC1C,mBAAoB,KAAK,WAAW,oBAAsB,GAC1D,WAAY,KAAK,WAAW,UAC9B,EACA,IAAM,EAAQ,CAChB,EACA,EAAO,WAAW,KAAK,iBAAiB,EACxC,EAAO,KAAK,UAAW,IAAM,CAC3B,EAAO,QAAQ,EACf,EAAW,MAAM,oBAAoB,CAAC,EACvC,EACD,EAAO,KAAK,QAAS,CAAM,EAC3B,KAAK,OAAS,EACf,EAEL",
|
|
8
|
+
"debugId": "81CB75805F76C9AC64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/auth/oauth2.d.ts
CHANGED
|
@@ -16,9 +16,13 @@ export interface TokenResponse {
|
|
|
16
16
|
* OAuth2 client with in-memory token cache and automatic refresh.
|
|
17
17
|
*/
|
|
18
18
|
export declare class OAuth2Client {
|
|
19
|
+
/** OAuth2 configuration supplied at construction. */
|
|
19
20
|
private readonly config;
|
|
21
|
+
/** Cached access token, or null before the first fetch. */
|
|
20
22
|
private cachedToken;
|
|
23
|
+
/** Expiry timestamp (ms) for the cached access token. */
|
|
21
24
|
private expiresAt;
|
|
25
|
+
/** In-flight refresh promise used to deduplicate concurrent refreshes. */
|
|
22
26
|
private refreshPromise;
|
|
23
27
|
/** Creates an OAuth2 client from configuration. */
|
|
24
28
|
constructor(config: OAuth2Config);
|
package/dist/auth/oauth2.js
CHANGED
|
@@ -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=
|
|
3
|
+
//# debugId=8B34C4BC825539BC64756E2164756E21
|
package/dist/auth/oauth2.js.map
CHANGED
|
@@ -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
|