@bumail/smtp 0.4.0 → 0.6.0
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/README.md +64 -5
- package/dist/chunks/{index-753q702a.js → index-n4xwep5m.js} +3 -3
- package/dist/chunks/{index-753q702a.js.map → index-n4xwep5m.js.map} +3 -3
- package/dist/client/index.js +1 -1
- package/dist/errors.d.ts +3 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +617 -71
- package/dist/index.js.map +15 -8
- package/dist/server/admission.d.ts +37 -0
- package/dist/server/admission.d.ts.map +1 -0
- package/dist/server/listener.d.ts +17 -8
- package/dist/server/listener.d.ts.map +1 -1
- package/dist/server/options.d.ts +21 -1
- package/dist/server/options.d.ts.map +1 -1
- package/dist/server/proxy/address.d.ts +17 -0
- package/dist/server/proxy/address.d.ts.map +1 -0
- package/dist/server/proxy/header.d.ts +26 -0
- package/dist/server/proxy/header.d.ts.map +1 -0
- package/dist/server/proxy/reader.d.ts +15 -0
- package/dist/server/proxy/reader.d.ts.map +1 -0
- package/dist/server/proxy/tls.d.ts +50 -0
- package/dist/server/proxy/tls.d.ts.map +1 -0
- package/dist/server/proxy/trusted.d.ts +9 -0
- package/dist/server/proxy/trusted.d.ts.map +1 -0
- package/dist/server/raw-socket.d.ts +9 -0
- package/dist/server/raw-socket.d.ts.map +1 -0
- package/dist/server/received.d.ts +2 -0
- package/dist/server/received.d.ts.map +1 -1
- package/dist/server/server.d.ts +9 -1
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/settings.d.ts +5 -0
- package/dist/server/settings.d.ts.map +1 -1
- package/dist/server/tls-context.d.ts +46 -0
- package/dist/server/tls-context.d.ts.map +1 -0
- package/dist/server/transport.d.ts +2 -2
- package/dist/server/transport.d.ts.map +1 -1
- package/docs/README.md +2 -2
- package/docs/guide.md +417 -13
- package/docs/roadmap.md +19 -0
- package/docs/troubleshooting.md +368 -1
- package/package.json +1 -1
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import type { Socket, SocketHandler } from 'bun';
|
|
2
|
-
import { Connection } from './connection';
|
|
2
|
+
import type { Connection } from './connection';
|
|
3
|
+
import type { HeaderReader } from './proxy/reader';
|
|
4
|
+
import type { ProxiedTls } from './proxy/tls';
|
|
5
|
+
import type { RawSocket } from './raw-socket';
|
|
3
6
|
import type { Settings } from './settings';
|
|
4
7
|
import type { Slots } from './slots';
|
|
5
8
|
import { SocketTransport } from './transport';
|
|
6
9
|
/**
|
|
7
10
|
* What a socket of the SMTP server does: the handlers the clear socket and
|
|
8
|
-
* the TLS one share, the STARTTLS upgrade
|
|
9
|
-
* `handshake` and `close
|
|
11
|
+
* the TLS one share, and the STARTTLS upgrade. The listener's own `open`,
|
|
12
|
+
* `handshake` and `close` are in `admission.ts`.
|
|
10
13
|
*/
|
|
11
14
|
export interface SocketState {
|
|
12
15
|
connection?: Connection;
|
|
@@ -20,18 +23,24 @@ export interface SocketState {
|
|
|
20
23
|
handshaking?: boolean;
|
|
21
24
|
/** What the server does once the handshake completes: greet, or turn away. */
|
|
22
25
|
start?: () => void;
|
|
26
|
+
/** A trusted proxy's PROXY header, still coming: nothing else is read meanwhile. */
|
|
27
|
+
header?: HeaderReader;
|
|
28
|
+
/** Implicit TLS behind a PROXY header, over this raw socket. */
|
|
29
|
+
tls?: ProxiedTls;
|
|
23
30
|
}
|
|
31
|
+
/** Bytes from the client, in clear or decrypted: they start the idle time again. */
|
|
32
|
+
export declare function received(socket: Socket<SocketState>, settings: Settings, chunk: Uint8Array): void;
|
|
24
33
|
/**
|
|
25
34
|
* The handlers both the clear socket and the TLS one share: input, drain,
|
|
26
35
|
* idle time. `socket.data` is read with `?.` throughout: Bun may report an
|
|
27
36
|
* error or a close on a socket whose `open` never ran.
|
|
28
37
|
*/
|
|
29
38
|
export declare function handlers(settings: Settings): SocketHandler<SocketState>;
|
|
39
|
+
/** Writes one reply and hangs up, through a transport so the hang-up is bounded as every other is. */
|
|
40
|
+
export declare function turnAway(socket: Socket<SocketState>, raw: RawSocket, secure: boolean, line: string): void;
|
|
30
41
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* frees the slot. `handshaking` holds the sockets still in their
|
|
34
|
-
* handshake, for `stop(true)`.
|
|
42
|
+
* Wraps a socket — Bun's, or `ProxiedTls` over it — for the client at
|
|
43
|
+
* `address`; STARTTLS swaps it for the encrypted one.
|
|
35
44
|
*/
|
|
36
|
-
export declare function
|
|
45
|
+
export declare function transportOf(socket: Socket<SocketState>, raw: RawSocket, address: string, settings: Settings, secure: boolean, slots: Slots<Connection>): SocketTransport;
|
|
37
46
|
//# sourceMappingURL=listener.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../../src/server/listener.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../../src/server/listener.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;GAIG;AAEH,MAAM,WAAW,WAAW;IAC3B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,iFAAiF;IACjF,QAAQ,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,oFAAoF;IACpF,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,gEAAgE;IAChE,GAAG,CAAC,EAAE,UAAU,CAAC;CACjB;AAED,oFAAoF;AACpF,wBAAgB,QAAQ,CACvB,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,EAC3B,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,UAAU,GACf,IAAI,CAMN;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,aAAa,CAAC,WAAW,CAAC,CAoCvE;AAED,sGAAsG;AACtG,wBAAgB,QAAQ,CACvB,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,EAC3B,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,MAAM,GACV,IAAI,CAKN;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAC1B,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,EAC3B,GAAG,EAAE,SAAS,EACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,GACtB,eAAe,CAmCjB"}
|
package/dist/server/options.d.ts
CHANGED
|
@@ -95,6 +95,11 @@ export interface TlsOptions {
|
|
|
95
95
|
readonly key: string | Uint8Array | Bun.BunFile;
|
|
96
96
|
readonly cert: string | Uint8Array | Bun.BunFile;
|
|
97
97
|
}
|
|
98
|
+
/** Where the PROXY protocol is read from: see `proxyProtocol`. */
|
|
99
|
+
export interface ProxyProtocolOptions {
|
|
100
|
+
/** The proxies' addresses or CIDRs, IPv4 or IPv6: `['10.0.0.5', '172.16.0.0/12']`. */
|
|
101
|
+
readonly trusted: readonly string[];
|
|
102
|
+
}
|
|
98
103
|
export interface SmtpServerOptions extends SmtpHooks {
|
|
99
104
|
/** The server's own name, in its greeting, its EHLO reply and its Received fields. */
|
|
100
105
|
readonly hostname: string;
|
|
@@ -142,13 +147,28 @@ export interface SmtpServerOptions extends SmtpHooks {
|
|
|
142
147
|
readonly maxErrors?: number;
|
|
143
148
|
/** Idle time before the server hangs up, in seconds; any byte from the client starts it again. Default 300, RFC 5321 §4.5.3.2.7's. */
|
|
144
149
|
readonly timeout?: number;
|
|
150
|
+
/**
|
|
151
|
+
* Reads the PROXY protocol (versions 1 and 2) from the proxies listed in
|
|
152
|
+
* `trusted` — IPv4 and IPv6 addresses and CIDRs — so the server sees
|
|
153
|
+
* the client's address, not the proxy's: in `session.remoteAddress`,
|
|
154
|
+
* `maxConnectionsPerClient`, `onConnect` and the Received field. A
|
|
155
|
+
* trusted peer must send its header first, within `handshakeTimeout`,
|
|
156
|
+
* or it is closed without a word; any other peer is served as without
|
|
157
|
+
* this option, and a header it sends is just bad input. List only the
|
|
158
|
+
* proxies' own addresses: any peer listed can claim any address. Off by
|
|
159
|
+
* default.
|
|
160
|
+
*/
|
|
161
|
+
readonly proxyProtocol?: ProxyProtocolOptions;
|
|
145
162
|
/**
|
|
146
163
|
* Seconds a client on implicit TLS has to complete its handshake, from
|
|
147
164
|
* the TCP connection on; past it, the socket is closed without a word.
|
|
148
165
|
* The socket holds its slot of `maxConnections` and
|
|
149
166
|
* `maxConnectionsPerClient` meanwhile. Bun's socket timer ticks in steps
|
|
150
167
|
* of about 4 s, so the close comes up to that much later. A STARTTLS
|
|
151
|
-
* handshake is bounded by `timeout`.
|
|
168
|
+
* handshake is bounded by `timeout`. With `proxyProtocol`, it also bounds a
|
|
169
|
+
* trusted proxy's PROXY header, from the TCP connection on, to the
|
|
170
|
+
* millisecond; behind the header, implicit TLS has as long again.
|
|
171
|
+
* Default 10.
|
|
152
172
|
*/
|
|
153
173
|
readonly handshakeTimeout?: number;
|
|
154
174
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/server/options.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/server/options.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IP addresses as bytes, for the PROXY protocol: what `trusted` lists and
|
|
3
|
+
* what a header names. An IPv4-mapped IPv6 address (`::ffff:192.0.2.1`)
|
|
4
|
+
* is its IPv4 address, in both: a dual-stack listener reports an IPv4
|
|
5
|
+
* peer that way.
|
|
6
|
+
*/
|
|
7
|
+
/** The 4 or 16 bytes of an IP address, or `undefined` for anything else, a zone included. */
|
|
8
|
+
export declare function addressBytes(text: string): Uint8Array | undefined;
|
|
9
|
+
/** An IPv4-mapped address as its 4 bytes; any other as it is. */
|
|
10
|
+
export declare function unmapped(bytes: Uint8Array): Uint8Array;
|
|
11
|
+
/**
|
|
12
|
+
* An address's text: dotted for IPv4 (an IPv4-mapped address included),
|
|
13
|
+
* RFC 5952's form for IPv6 — lower case, no leading zeros, the longest
|
|
14
|
+
* run of two zero groups or more as `::`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function formatAddress(raw: Uint8Array): string;
|
|
17
|
+
//# sourceMappingURL=address.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../../../src/server/proxy/address.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAOjE;AAyBD,iEAAiE;AACjE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAOtD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAiBrD"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The PROXY protocol header (HAProxy's proxy-protocol.txt, versions 1 and
|
|
3
|
+
* 2) a TCP proxy sends before anything of the client's, read from the
|
|
4
|
+
* bytes received so far. `source` is the client's address, or absent to
|
|
5
|
+
* keep the peer's: a v2 LOCAL (a health check from the proxy itself), an
|
|
6
|
+
* UNSPEC, UNIX or datagram address, a v1 UNKNOWN.
|
|
7
|
+
*/
|
|
8
|
+
export type ProxyHeader = {
|
|
9
|
+
readonly status: 'partial';
|
|
10
|
+
} | {
|
|
11
|
+
readonly status: 'invalid';
|
|
12
|
+
readonly reason: string;
|
|
13
|
+
} | {
|
|
14
|
+
readonly status: 'complete';
|
|
15
|
+
/** Bytes of the header: what follows is the client's. */
|
|
16
|
+
readonly length: number;
|
|
17
|
+
readonly source?: string;
|
|
18
|
+
};
|
|
19
|
+
/** A v1 line, CRLF included, is 107 bytes at most. */
|
|
20
|
+
export declare const MAX_V1_LENGTH = 107;
|
|
21
|
+
/** v2's addresses take 216 bytes at most (two UNIX paths); TLVs past this are refused. */
|
|
22
|
+
export declare const MAX_TLV_BYTES = 2048;
|
|
23
|
+
/** The longest header read: past it, whatever the bytes, the header is refused. */
|
|
24
|
+
export declare const MAX_HEADER_LENGTH: number;
|
|
25
|
+
export declare function readProxyHeader(bytes: Uint8Array): ProxyHeader;
|
|
26
|
+
//# sourceMappingURL=header.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header.d.ts","sourceRoot":"","sources":["../../../src/server/proxy/header.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GACpB;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GAC9B;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvD;IACA,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,yDAAyD;IACzD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEL,sDAAsD;AACtD,eAAO,MAAM,aAAa,MAAM,CAAC;AACjC,0FAA0F;AAC1F,eAAO,MAAM,aAAa,OAAO,CAAC;AAClC,mFAAmF;AACnF,eAAO,MAAM,iBAAiB,QAA2B,CAAC;AAqB1D,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAK9D"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads the PROXY header a trusted proxy sends first, chunk by chunk, within
|
|
3
|
+
* `seconds` from the TCP connection, however slowly it comes. `done` gets
|
|
4
|
+
* the client's address (`undefined` to keep the peer's) and what followed
|
|
5
|
+
* the header; `refuse` is called for a header that is malformed, too long
|
|
6
|
+
* or too late. Either is called once, and the reader then ignores input.
|
|
7
|
+
*/
|
|
8
|
+
export declare class HeaderReader {
|
|
9
|
+
#private;
|
|
10
|
+
constructor(seconds: number, done: (source: string | undefined, rest: Uint8Array) => void, refuse: () => void);
|
|
11
|
+
receive(chunk: Uint8Array): void;
|
|
12
|
+
/** The socket closed first: no timer is left behind. */
|
|
13
|
+
cancel(): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../../src/server/proxy/reader.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,qBAAa,YAAY;;gBAQvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,UAAU,KAAK,IAAI,EAC5D,MAAM,EAAE,MAAM,IAAI;IAQnB,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAkBhC,wDAAwD;IACxD,MAAM,IAAI,IAAI;CAWd"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type SecureContext } from 'node:tls';
|
|
2
|
+
import type { Socket } from 'bun';
|
|
3
|
+
/** What the TLS session tells the listener. */
|
|
4
|
+
export interface TlsEvents {
|
|
5
|
+
/** The handshake completed. */
|
|
6
|
+
secure(): void;
|
|
7
|
+
/** Bytes from the client, decrypted. */
|
|
8
|
+
data(bytes: Uint8Array): void;
|
|
9
|
+
/** What was written has left: the transport may write more. */
|
|
10
|
+
drain(): void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Implicit TLS behind a PROXY header. A listener with `tls` would take the
|
|
14
|
+
* header for a broken ClientHello, so the listener is a clear one, and TLS
|
|
15
|
+
* starts once the header is read. Bun's `socket.upgradeTLS` cannot be
|
|
16
|
+
* used: it reads only what arrives after it, and a proxy sends the
|
|
17
|
+
* client's ClientHello in the same segment as the header as often as not
|
|
18
|
+
* (Bun 1.4.2: the handshake then never completes). So the TLS session is
|
|
19
|
+
* `node:tls` over a stream this class feeds: what followed the header
|
|
20
|
+
* first, then every chunk of the raw socket's `data` (`receive`).
|
|
21
|
+
*
|
|
22
|
+
* It has the shape of the Bun socket a `SocketTransport` drives. `write`
|
|
23
|
+
* takes nothing while TLS holds more than its high-water mark, and
|
|
24
|
+
* `drain` comes once it took it all; the stream under it hands the raw
|
|
25
|
+
* socket what it takes and waits for the raw `drain` for the rest, so a
|
|
26
|
+
* client that reads slowly holds the server back, never its memory.
|
|
27
|
+
*/
|
|
28
|
+
export declare class ProxiedTls {
|
|
29
|
+
#private;
|
|
30
|
+
constructor(raw: Socket<unknown>, context: SecureContext, events: TlsEvents);
|
|
31
|
+
get remoteAddress(): string;
|
|
32
|
+
/** The raw socket's `data`: TLS records from the client. */
|
|
33
|
+
receive(chunk: Uint8Array): void;
|
|
34
|
+
/** The raw socket's `drain`: it can take more of what TLS wrote. */
|
|
35
|
+
rawDrain(): void;
|
|
36
|
+
write(bytes: Uint8Array): number;
|
|
37
|
+
/**
|
|
38
|
+
* Ends TLS — a close_notify after everything written — then the raw
|
|
39
|
+
* socket, as `shutdown(halfClose)` would. Nothing written is lost, so
|
|
40
|
+
* the two differ only in the raw socket's close.
|
|
41
|
+
*/
|
|
42
|
+
shutdown(halfClose?: boolean): void;
|
|
43
|
+
terminate(): void;
|
|
44
|
+
/** The raw socket closed: TLS has nowhere to go. */
|
|
45
|
+
closed(): void;
|
|
46
|
+
pause(): void;
|
|
47
|
+
resume(): void;
|
|
48
|
+
timeout(seconds: number): void;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=tls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tls.d.ts","sourceRoot":"","sources":["../../../src/server/proxy/tls.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,aAAa,EAAa,MAAM,UAAU,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAElC,+CAA+C;AAC/C,MAAM,WAAW,SAAS;IACzB,+BAA+B;IAC/B,MAAM,IAAI,IAAI,CAAC;IACf,wCAAwC;IACxC,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,+DAA+D;IAC/D,KAAK,IAAI,IAAI,CAAC;CACd;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,UAAU;;gBASV,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS;IAqB3E,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,4DAA4D;IAC5D,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAIhC,oEAAoE;IACpE,QAAQ,IAAI,IAAI;IAmBhB,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM;IAMhC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,UAAQ,GAAG,IAAI;IAUjC,SAAS,IAAI,IAAI;IAMjB,oDAAoD;IACpD,MAAM,IAAI,IAAI;IAKd,KAAK,IAAI,IAAI;IAIb,MAAM,IAAI,IAAI;IAId,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAG9B"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `proxyProtocol.trusted` as a test of a peer's address: IPv4 and IPv6
|
|
3
|
+
* addresses and CIDRs, an IPv4-mapped address or peer matched as its IPv4
|
|
4
|
+
* address. An entry that is neither throws, through `invalid`, and so does
|
|
5
|
+
* an empty list (it would trust nobody, which is no proxy at all), a zone
|
|
6
|
+
* (`fe80::1%eth0`) and a prefix of 0, which would trust everyone.
|
|
7
|
+
*/
|
|
8
|
+
export declare function trustedPeers(entries: unknown, invalid: (message: string) => Error): (peer: string) => boolean;
|
|
9
|
+
//# sourceMappingURL=trusted.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trusted.d.ts","sourceRoot":"","sources":["../../../src/server/proxy/trusted.ts"],"names":[],"mappings":"AA8CA;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC3B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,KAAK,GACjC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAoB3B"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Socket } from 'bun';
|
|
2
|
+
/**
|
|
3
|
+
* The socket a transport drives: Bun's, or `ProxiedTls` — implicit TLS
|
|
4
|
+
* behind a PROXY header — which has its shape.
|
|
5
|
+
*/
|
|
6
|
+
export type RawSocket = Pick<Socket<unknown>, 'remoteAddress' | 'shutdown' | 'terminate' | 'pause' | 'resume' | 'timeout'> & {
|
|
7
|
+
write(bytes: Uint8Array): number;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=raw-socket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raw-socket.d.ts","sourceRoot":"","sources":["../../src/server/raw-socket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAElC;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,IAAI,CAC3B,MAAM,CAAC,OAAO,CAAC,EACf,eAAe,GAAG,UAAU,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAC3E,GAAG;IAAE,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAAA;CAAE,CAAC"}
|
|
@@ -3,6 +3,8 @@ import type { Connection } from './connection';
|
|
|
3
3
|
export declare function dateTime(date: Date): string;
|
|
4
4
|
/** RFC 3848: how the message came — SMTP, ESMTP, then S for TLS and A for AUTH. */
|
|
5
5
|
export declare function protocolOf(esmtp: boolean, secure: boolean, authenticated: boolean): string;
|
|
6
|
+
/** The client's address as a domain literal (RFC 5321 §4.1.3): an IPv6 address is tagged `IPv6:`. */
|
|
7
|
+
export declare function addressLiteral(address: string): string;
|
|
6
8
|
/**
|
|
7
9
|
* The Received field the server puts on top (RFC 5321 §4.4): who sent the
|
|
8
10
|
* message, from where, how, to whom when there is one recipient, and when.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"received.d.ts","sourceRoot":"","sources":["../../src/server/received.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"received.d.ts","sourceRoot":"","sources":["../../src/server/received.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAoB/C,0CAA0C;AAC1C,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE3C;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CACzB,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,OAAO,EACf,aAAa,EAAE,OAAO,GACpB,MAAM,CAGR;AAED,qGAAqG;AACrG,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAItD;AAiBD;;;GAGG;AACH,wBAAgB,aAAa,CAC5B,UAAU,EAAE,UAAU,EACtB,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,EAAE,EAAE,MAAM,EACV,GAAG,OAAa,GACd,MAAM,CAYR"}
|
package/dist/server/server.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SmtpServerOptions } from './options';
|
|
1
|
+
import type { SmtpServerOptions, TlsOptions } from './options';
|
|
2
2
|
export interface SmtpServer {
|
|
3
3
|
/** Starts listening; resolves once the port is bound. Once only: a second call throws. */
|
|
4
4
|
listen(options: {
|
|
@@ -8,6 +8,14 @@ export interface SmtpServer {
|
|
|
8
8
|
port: number;
|
|
9
9
|
hostname: string;
|
|
10
10
|
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Uses a renewed key and certificate from the next STARTTLS upgrade or
|
|
13
|
+
* implicit TLS connection on; the sessions open keep the TLS they have.
|
|
14
|
+
* The pair is read and checked first: one that cannot be used throws
|
|
15
|
+
* `INVALID_OPTION` and leaves the one in use. Needs a server made with
|
|
16
|
+
* `tls`.
|
|
17
|
+
*/
|
|
18
|
+
setTls(tls: TlsOptions): Promise<void>;
|
|
11
19
|
/** Stops listening; `closeConnections` hangs up on every client too. */
|
|
12
20
|
stop(closeConnections?: boolean): void;
|
|
13
21
|
/** Open connections. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAiD/D,MAAM,WAAW,UAAU;IAC1B,0FAA0F;IAC1F,MAAM,CAAC,OAAO,EAAE;QACf,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD;;;;;;OAMG;IACH,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,wEAAwE;IACxE,IAAI,CAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACvC,wBAAwB;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CA0EvE"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SmtpServerOptions } from './options';
|
|
2
|
+
import { TlsHolder } from './tls-context';
|
|
2
3
|
/** The options with their defaults, checked once. */
|
|
3
4
|
export interface Settings {
|
|
4
5
|
readonly options: SmtpServerOptions;
|
|
@@ -12,6 +13,10 @@ export interface Settings {
|
|
|
12
13
|
readonly hookTimeout: number;
|
|
13
14
|
readonly handshakeTimeout: number;
|
|
14
15
|
readonly greetingDelay: number;
|
|
16
|
+
/** The key and certificate in use, which `setTls` replaces; with `options.tls`. */
|
|
17
|
+
readonly tls?: TlsHolder;
|
|
18
|
+
/** With `proxyProtocol`: whether a peer is a proxy trusted to send a PROXY header. */
|
|
19
|
+
readonly trusts?: (peer: string) => boolean;
|
|
15
20
|
isLocal(domain: string): boolean | Promise<boolean>;
|
|
16
21
|
}
|
|
17
22
|
export declare function settingsOf(options: SmtpServerOptions): Settings;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/server/settings.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD,qDAAqD;AACrD,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,CAAC;IACnC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACpD;AAkED,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/server/settings.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,qDAAqD;AACrD,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,YAAY,CAAC;IACnC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,mFAAmF;IACnF,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC;IACzB,sFAAsF;IACtF,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5C,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACpD;AAkED,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,QAAQ,CA6D/D"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type SecureContext } from 'node:tls';
|
|
2
|
+
/** `key` or `cert` as `Bun.listen` takes them: text, bytes or a file. */
|
|
3
|
+
type TlsMaterial = string | Uint8Array | Bun.BunFile;
|
|
4
|
+
/** A key and certificate pair, as `Bun.listen` takes it. */
|
|
5
|
+
interface TlsPair {
|
|
6
|
+
readonly key: TlsMaterial;
|
|
7
|
+
readonly cert: TlsMaterial;
|
|
8
|
+
}
|
|
9
|
+
/** `tls` read whole, with the `node:tls` context made from it. */
|
|
10
|
+
interface ReadTls {
|
|
11
|
+
readonly key: string | Buffer;
|
|
12
|
+
readonly cert: string | Buffer;
|
|
13
|
+
readonly context: SecureContext;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* `tls` read whole — a file included — and checked as a `node:tls` context:
|
|
17
|
+
* what implicit TLS behind a proxy runs on, and, without a proxy, the check
|
|
18
|
+
* that makes a key or certificate that cannot be read or used fail
|
|
19
|
+
* `listen()` and `setTls()` the same way. `fail` turns the reason into the
|
|
20
|
+
* package's own error, the `node:tls` or file error as its `cause`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readTls(tls: TlsPair, fail: (message: string, cause: unknown) => Error, caller: string): Promise<ReadTls>;
|
|
23
|
+
/**
|
|
24
|
+
* The key and certificate the server uses now. What `listen()` or `setTls()`
|
|
25
|
+
* read replaces it whole, and only once checked, so a pair that cannot be
|
|
26
|
+
* used leaves the one in use. A STARTTLS server that has read nothing yet
|
|
27
|
+
* serves `tls` as it was given.
|
|
28
|
+
*/
|
|
29
|
+
export declare class TlsHolder {
|
|
30
|
+
#private;
|
|
31
|
+
constructor(given: TlsPair);
|
|
32
|
+
/** What an upgrade to TLS, or a native listener, is given. */
|
|
33
|
+
get options(): TlsPair;
|
|
34
|
+
/** The `node:tls` context of the pair in use: only once `load` or `replace` read one. */
|
|
35
|
+
get context(): SecureContext;
|
|
36
|
+
/** Reads and checks the pair given, unless a read already replaced it. */
|
|
37
|
+
load(fail: (message: string, cause: unknown) => Error, caller: string): Promise<SecureContext>;
|
|
38
|
+
/**
|
|
39
|
+
* Checks `tls`, then uses it from the next connection on. Calls apply in
|
|
40
|
+
* the order they were made, however long each read takes; one that fails
|
|
41
|
+
* does not hold the next.
|
|
42
|
+
*/
|
|
43
|
+
replace(tls: TlsPair, fail: (message: string, cause: unknown) => Error, caller: string): Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=tls-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tls-context.d.ts","sourceRoot":"","sources":["../../src/server/tls-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAEnE,yEAAyE;AACzE,KAAK,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC;AAErD,4DAA4D;AAC5D,UAAU,OAAO;IAChB,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;CAC3B;AAED,kEAAkE;AAClE,UAAU,OAAO;IAChB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;CAChC;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC5B,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,KAAK,EAChD,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC,CAoBlB;AAED;;;;;GAKG;AACH,qBAAa,SAAS;;gBAMT,KAAK,EAAE,OAAO;IAI1B,8DAA8D;IAC9D,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,yFAAyF;IACzF,IAAI,OAAO,IAAI,aAAa,CAG3B;IAED,0EAA0E;IACpE,IAAI,CACT,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,KAAK,EAChD,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,aAAa,CAAC;IAOzB;;;;OAIG;IACH,OAAO,CACN,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,KAAK,EAChD,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC;CAOhB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RawSocket } from './raw-socket';
|
|
2
2
|
/** What a connection needs from its socket: Bun's, or a fake one in specs. */
|
|
3
3
|
export interface Transport {
|
|
4
4
|
readonly remoteAddress: string;
|
|
@@ -52,7 +52,7 @@ export declare class SocketTransport implements Transport {
|
|
|
52
52
|
#private;
|
|
53
53
|
readonly remoteAddress: string;
|
|
54
54
|
readonly secure: boolean;
|
|
55
|
-
constructor(socket:
|
|
55
|
+
constructor(socket: RawSocket, secure: boolean, startTls: () => void, remoteAddress?: string);
|
|
56
56
|
write(text: string): void;
|
|
57
57
|
/** Bun's `drain`: the socket can take more. */
|
|
58
58
|
drain(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/server/transport.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/server/transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,8EAA8E;AAC9E,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,uFAAuF;IACvF,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,iDAAiD;IACjD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB;;;;;OAKG;IACH,GAAG,IAAI,IAAI,CAAC;IACZ;;;;;OAKG;IACH,KAAK,IAAI,IAAI,CAAC;IACd,kEAAkE;IAClE,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,IAAI,CAAC;IACf,uEAAuE;IACvE,QAAQ,IAAI,IAAI,CAAC;IACjB,kEAAkE;IAClE,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,OAAQ,CAAC;AAEpC;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,aAAa,MAAM,CAAC;AAEjC;;;;GAIG;AACH,qBAAa,eAAgB,YAAW,SAAS;;IAEhD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;gBAmBxB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,MAAM,IAAI,EACpB,aAAa,SAAuB;IASrC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKzB,+CAA+C;IAC/C,KAAK,IAAI,IAAI;IAIb,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB;;;;;;OAMG;IACH,QAAQ,IAAI,IAAI;IAQhB,kDAAkD;IAClD,MAAM,IAAI,IAAI;IAOd,0EAA0E;IAC1E,GAAG,IAAI,IAAI;IAOX,KAAK,IAAI,IAAI;IA0Fb,KAAK,IAAI,IAAI;IAKb,MAAM,IAAI,IAAI;IAKd,QAAQ,IAAI,IAAI;IAIhB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAGlC"}
|
package/docs/README.md
CHANGED
|
@@ -5,6 +5,6 @@ long one.
|
|
|
5
5
|
|
|
6
6
|
| Page | Read it when |
|
|
7
7
|
| --- | --- |
|
|
8
|
-
| [Guide](guide.md) | running an MX, a submission server or implicit TLS; reading what a reply means; writing hooks and keeping state in `Session.data`; handling what `onData` receives; delivering into `@bumail/store`; setting TLS, limits and `greetingDelay`; sending mail with `@bumail/smtp/client` and trying it with Mailpit; or checking which RFC a behaviour follows |
|
|
9
|
-
| [Troubleshooting](troubleshooting.md) | `createSmtpServer` threw, the server will not listen, a client reports a reply you did not expect, or `sendMail` rejected |
|
|
8
|
+
| [Guide](guide.md) | running an MX, a submission server or implicit TLS; reading what a reply means; writing hooks and keeping state in `Session.data`; handling what `onData` receives; delivering into `@bumail/store`; setting TLS, limits and `greetingDelay`; running behind a TCP proxy such as Traefik with the PROXY protocol; sending mail with `@bumail/smtp/client` and trying it with Mailpit; or checking which RFC a behaviour follows |
|
|
9
|
+
| [Troubleshooting](troubleshooting.md) | `createSmtpServer` threw, the server will not listen, a client reports a reply you did not expect, connections through a proxy close or show the proxy's address, or `sendMail` rejected |
|
|
10
10
|
| [Roadmap](roadmap.md) | wondering what is coming — connection reuse in the client, DSN, a ready-made delivery into the store — and what is not planned |
|