@ac-kit/node 0.1.0 → 0.2.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/CHANGELOG.md +55 -0
- package/README.md +2 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/net/connection-closed-error.d.ts +12 -0
- package/dist/net/connection-closed-error.d.ts.map +1 -0
- package/dist/net/connection-closed-error.js +15 -0
- package/dist/net/connection-closed-error.js.map +1 -0
- package/dist/net/dgram-socket.d.ts +2 -2
- package/dist/net/dgram-socket.d.ts.map +1 -1
- package/dist/net/dgram-socket.js +35 -35
- package/dist/net/dgram-socket.js.map +1 -1
- package/dist/net/inet-socket.d.ts +64 -0
- package/dist/net/inet-socket.d.ts.map +1 -0
- package/dist/net/inet-socket.js +103 -0
- package/dist/net/inet-socket.js.map +1 -0
- package/dist/net/ipc-server.d.ts +63 -0
- package/dist/net/ipc-server.d.ts.map +1 -0
- package/dist/net/ipc-server.js +75 -0
- package/dist/net/ipc-server.js.map +1 -0
- package/dist/net/ipc-socket.d.ts +55 -22
- package/dist/net/ipc-socket.d.ts.map +1 -1
- package/dist/net/ipc-socket.js +50 -46
- package/dist/net/ipc-socket.js.map +1 -1
- package/dist/net/stream-server.d.ts +80 -0
- package/dist/net/stream-server.d.ts.map +1 -0
- package/dist/net/stream-server.js +129 -0
- package/dist/net/stream-server.js.map +1 -0
- package/dist/net/stream-socket.d.ts +37 -8
- package/dist/net/stream-socket.d.ts.map +1 -1
- package/dist/net/stream-socket.js +80 -27
- package/dist/net/stream-socket.js.map +1 -1
- package/dist/net/tcp-server.d.ts +31 -73
- package/dist/net/tcp-server.d.ts.map +1 -1
- package/dist/net/tcp-server.js +41 -147
- package/dist/net/tcp-server.js.map +1 -1
- package/dist/net/tcp-socket.d.ts +21 -61
- package/dist/net/tcp-socket.d.ts.map +1 -1
- package/dist/net/tcp-socket.js +23 -126
- package/dist/net/tcp-socket.js.map +1 -1
- package/dist/net/tls-server.d.ts +87 -0
- package/dist/net/tls-server.d.ts.map +1 -0
- package/dist/net/tls-server.js +103 -0
- package/dist/net/tls-server.js.map +1 -0
- package/dist/net/tls-socket.d.ts +235 -14
- package/dist/net/tls-socket.d.ts.map +1 -1
- package/dist/net/tls-socket.js +241 -91
- package/dist/net/tls-socket.js.map +1 -1
- package/package.json +4 -4
- package/dist/shell/escape-command-arg.d.ts +0 -9
- package/dist/shell/escape-command-arg.d.ts.map +0 -1
- package/dist/shell/escape-command-arg.js +0 -13
- package/dist/shell/escape-command-arg.js.map +0 -1
- package/dist/shell/escape-command.d.ts +0 -10
- package/dist/shell/escape-command.d.ts.map +0 -1
- package/dist/shell/escape-command.js +0 -12
- package/dist/shell/escape-command.js.map +0 -1
package/dist/net/tcp-server.js
CHANGED
|
@@ -1,196 +1,90 @@
|
|
|
1
1
|
import * as net from "node:net";
|
|
2
|
-
import { EventDispatcherMapBase } from "@ac-kit/async";
|
|
3
2
|
import { composeInetAddress, UnsupportedError, } from "@ac-kit/core";
|
|
3
|
+
import { StreamServer } from "./stream-server.js";
|
|
4
4
|
import { TcpSocket } from "./tcp-socket.js";
|
|
5
5
|
/**
|
|
6
|
-
* TCP server
|
|
6
|
+
* TCP server accepting incoming connections.
|
|
7
7
|
*
|
|
8
8
|
* Example usage:
|
|
9
9
|
*
|
|
10
10
|
* ```ts
|
|
11
11
|
* const server = TcpServer.from();
|
|
12
|
-
* server.
|
|
13
|
-
*
|
|
14
|
-
* client.stream.on("data", (data) => {
|
|
12
|
+
* server.subscribe("connection", (socket) => {
|
|
13
|
+
* socket.stream.on("data", (data) => {
|
|
15
14
|
* console.log("Received:", data.toString());
|
|
16
15
|
* });
|
|
17
16
|
* });
|
|
18
|
-
* await server.listen(8080, "0.0.0.0");
|
|
17
|
+
* await server.listen(8080, { host: "0.0.0.0" });
|
|
19
18
|
* // ... later
|
|
20
19
|
* await server.close();
|
|
21
20
|
* ```
|
|
22
21
|
*/
|
|
23
|
-
export class TcpServer extends
|
|
24
|
-
srv;
|
|
22
|
+
export class TcpServer extends StreamServer {
|
|
25
23
|
/**
|
|
26
|
-
* Creates a new
|
|
24
|
+
* Creates a new {@link TcpServer} instance.
|
|
27
25
|
*
|
|
28
|
-
* @param options Options for creating the
|
|
26
|
+
* @param options Options for creating the underlying Node.js server.
|
|
29
27
|
* @returns A new `TcpServer` instance.
|
|
30
28
|
*/
|
|
31
29
|
static from(options) {
|
|
32
30
|
return new TcpServer(net.createServer(options));
|
|
33
31
|
}
|
|
34
|
-
handledErrorEvents = new Set();
|
|
35
|
-
constructor(srv) {
|
|
36
|
-
super();
|
|
37
|
-
this.srv = srv;
|
|
38
|
-
this.setupEventForwarding();
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Gets the current number of concurrent connections on the server.
|
|
42
|
-
*
|
|
43
|
-
* @returns A promise that resolves with the connection count.
|
|
44
|
-
*/
|
|
45
|
-
getConnections() {
|
|
46
|
-
return new Promise((resolve, reject) => {
|
|
47
|
-
this.srv.getConnections((error, count) => {
|
|
48
|
-
if (error) {
|
|
49
|
-
reject(error);
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
resolve(count);
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
/** Gets whether the server is currently listening for connections. */
|
|
58
|
-
get listening() {
|
|
59
|
-
return this.srv.listening;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Sets the maximum number of queued pending connections.
|
|
63
|
-
*
|
|
64
|
-
* @param maxConnections The maximum number of connections to queue.
|
|
65
|
-
*/
|
|
66
|
-
set maxConnections(maxConnections) {
|
|
67
|
-
this.srv.maxConnections = maxConnections;
|
|
68
|
-
}
|
|
69
|
-
/** Gets the maximum number of queued pending connections. */
|
|
70
|
-
get maxConnections() {
|
|
71
|
-
return this.srv.maxConnections;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* References the server, preventing the process from exiting while the server
|
|
75
|
-
* is active.
|
|
76
|
-
*/
|
|
77
|
-
ref() {
|
|
78
|
-
this.srv.ref();
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Unreferences the server, allowing the process from exiting even if the
|
|
82
|
-
* server is active.
|
|
83
|
-
*/
|
|
84
|
-
unref() {
|
|
85
|
-
this.srv.unref();
|
|
86
|
-
}
|
|
87
32
|
/**
|
|
88
|
-
*
|
|
33
|
+
* Binds the server and resolves once it is listening.
|
|
89
34
|
*
|
|
90
|
-
* @param port The port to listen on.
|
|
91
|
-
* assigned.
|
|
92
|
-
* @param host The host/interface to bind to. Defaults to '::' (IPv6) or
|
|
93
|
-
* '0.0.0.0' (IPv4).
|
|
35
|
+
* @param port The port to listen on. Use `0` to let the system assign one.
|
|
94
36
|
* @param options Additional listen options.
|
|
95
|
-
* @returns A promise that resolves
|
|
96
|
-
|
|
97
|
-
listen(port, host, options) {
|
|
98
|
-
return new Promise((resolve, reject) => {
|
|
99
|
-
const handleError = (error) => {
|
|
100
|
-
this.handledErrorEvents.add(error);
|
|
101
|
-
reject(error);
|
|
102
|
-
};
|
|
103
|
-
this.srv.prependOnceListener("error", handleError);
|
|
104
|
-
this.srv.listen({
|
|
105
|
-
...options,
|
|
106
|
-
port,
|
|
107
|
-
host,
|
|
108
|
-
}, () => {
|
|
109
|
-
this.srv.removeListener("error", handleError);
|
|
110
|
-
resolve();
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Closes the TCP server, stopping it from accepting new connections. Existing
|
|
116
|
-
* connections are not automatically closed.
|
|
117
|
-
*
|
|
118
|
-
* @returns A promise that resolves when the server is fully closed.
|
|
37
|
+
* @returns A promise that resolves once the server is listening.
|
|
38
|
+
* @throws When the address is already in use or cannot be bound.
|
|
119
39
|
*/
|
|
120
|
-
|
|
121
|
-
return
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
reject(error);
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
resolve();
|
|
128
|
-
}
|
|
129
|
-
});
|
|
40
|
+
listen(port, options) {
|
|
41
|
+
return this.listenOn({
|
|
42
|
+
...options,
|
|
43
|
+
port,
|
|
130
44
|
});
|
|
131
45
|
}
|
|
132
46
|
/**
|
|
133
|
-
*
|
|
47
|
+
* Returns the endpoint the server is bound to.
|
|
134
48
|
*
|
|
135
|
-
* @returns The
|
|
136
|
-
*
|
|
49
|
+
* @returns The bound endpoint, or `null` when the server is not listening.
|
|
50
|
+
* @throws {UnsupportedError} When the server is bound to a path rather than
|
|
51
|
+
* an IP endpoint. Use {@link IpcServer} for those.
|
|
137
52
|
*/
|
|
138
53
|
address() {
|
|
139
|
-
const
|
|
140
|
-
if (
|
|
54
|
+
const address = this.server.address();
|
|
55
|
+
if (address === null) {
|
|
141
56
|
return null;
|
|
142
57
|
}
|
|
143
|
-
if (typeof
|
|
58
|
+
if (typeof address === "string") {
|
|
144
59
|
throw new UnsupportedError(`Unsupported address type: string. Expected AddressInfo object.`);
|
|
145
60
|
}
|
|
146
61
|
return {
|
|
147
|
-
...composeInetAddress(
|
|
148
|
-
port:
|
|
62
|
+
...composeInetAddress(address.family, address.address),
|
|
63
|
+
port: address.port,
|
|
149
64
|
};
|
|
150
65
|
}
|
|
151
66
|
setupEventForwarding() {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
this.dispatch("connection", [
|
|
155
|
-
});
|
|
156
|
-
this.srv.on("close", () => {
|
|
157
|
-
this.dispatch("close", []);
|
|
67
|
+
super.setupEventForwarding();
|
|
68
|
+
this.server.on("connection", (socket) => {
|
|
69
|
+
this.dispatch("connection", [new TcpSocket(socket)]);
|
|
158
70
|
});
|
|
159
|
-
this.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
this.dispatch("error", [err]);
|
|
165
|
-
});
|
|
166
|
-
this.srv.on("listening", () => {
|
|
167
|
-
this.dispatch("listening", []);
|
|
168
|
-
});
|
|
169
|
-
this.srv.on("drop", (data) => {
|
|
170
|
-
let localEndpoint;
|
|
171
|
-
if (data?.localAddress !== undefined &&
|
|
172
|
-
data?.localPort !== undefined &&
|
|
173
|
-
data?.localFamily !== undefined) {
|
|
174
|
-
localEndpoint = {
|
|
71
|
+
this.server.on("drop", (data) => {
|
|
72
|
+
const localEndpoint = data?.localAddress !== undefined &&
|
|
73
|
+
data.localPort !== undefined &&
|
|
74
|
+
data.localFamily !== undefined
|
|
75
|
+
? {
|
|
175
76
|
...composeInetAddress(data.localFamily, data.localAddress),
|
|
176
77
|
port: data.localPort,
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (data?.remoteAddress !== undefined &&
|
|
184
|
-
data?.remotePort !== undefined &&
|
|
185
|
-
data?.remoteFamily !== undefined) {
|
|
186
|
-
remoteEndpoint = {
|
|
78
|
+
}
|
|
79
|
+
: null;
|
|
80
|
+
const remoteEndpoint = data?.remoteAddress !== undefined &&
|
|
81
|
+
data.remotePort !== undefined &&
|
|
82
|
+
data.remoteFamily !== undefined
|
|
83
|
+
? {
|
|
187
84
|
...composeInetAddress(data.remoteFamily, data.remoteAddress),
|
|
188
85
|
port: data.remotePort,
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
else {
|
|
192
|
-
remoteEndpoint = null;
|
|
193
|
-
}
|
|
86
|
+
}
|
|
87
|
+
: null;
|
|
194
88
|
this.dispatch("drop", [localEndpoint, remoteEndpoint]);
|
|
195
89
|
});
|
|
196
90
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tcp-server.js","sourceRoot":"","sources":["../../src/net/tcp-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,OAAO,
|
|
1
|
+
{"version":3,"file":"tcp-server.js","sourceRoot":"","sources":["../../src/net/tcp-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,OAAO,EACN,kBAAkB,EAElB,gBAAgB,GAChB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,YAAY,EAA2B,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AA2B5C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,SAGX,SAAQ,YAA8B;IACvC;;;;;OAKG;IACH,MAAM,CAAC,IAAI,CAAC,OAA0B;QACrC,OAAO,IAAI,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,IAAY,EAAE,OAAgC;QACpD,OAAO,IAAI,CAAC,QAAQ,CAAC;YACpB,GAAG,OAAO;YACV,IAAI;SACJ,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,OAAO;QACN,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAEtC,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QACb,CAAC;QAED,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YACjC,MAAM,IAAI,gBAAgB,CACzB,gEAAgE,CAChE,CAAC;QACH,CAAC;QAED,OAAO;YACN,GAAG,kBAAkB,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC;YACtD,IAAI,EAAE,OAAO,CAAC,IAAI;SAClB,CAAC;IACH,CAAC;IAEkB,oBAAoB;QACtC,KAAK,CAAC,oBAAoB,EAAE,CAAC;QAE7B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;YACvC,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC/B,MAAM,aAAa,GAClB,IAAI,EAAE,YAAY,KAAK,SAAS;gBAChC,IAAI,CAAC,SAAS,KAAK,SAAS;gBAC5B,IAAI,CAAC,WAAW,KAAK,SAAS;gBAC7B,CAAC,CAAC;oBACA,GAAG,kBAAkB,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC;oBAC1D,IAAI,EAAE,IAAI,CAAC,SAAS;iBACpB;gBACF,CAAC,CAAC,IAAI,CAAC;YAET,MAAM,cAAc,GACnB,IAAI,EAAE,aAAa,KAAK,SAAS;gBACjC,IAAI,CAAC,UAAU,KAAK,SAAS;gBAC7B,IAAI,CAAC,YAAY,KAAK,SAAS;gBAC9B,CAAC,CAAC;oBACA,GAAG,kBAAkB,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,aAAa,CAAC;oBAC5D,IAAI,EAAE,IAAI,CAAC,UAAU;iBACrB;gBACF,CAAC,CAAC,IAAI,CAAC;YAET,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;IACJ,CAAC;CACD"}
|
package/dist/net/tcp-socket.d.ts
CHANGED
|
@@ -1,28 +1,13 @@
|
|
|
1
1
|
import * as net from "node:net";
|
|
2
|
-
import { InetAddress, InetEndpoint } from "@ac-kit/core";
|
|
3
2
|
import type { Except } from "type-fest";
|
|
4
|
-
import {
|
|
5
|
-
/** Event map for TcpSocket
|
|
6
|
-
export type TcpSocketEvents =
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
*/
|
|
11
|
-
connectionAttempt: [endpoint: InetEndpoint];
|
|
12
|
-
/**
|
|
13
|
-
* Emitted when a connection attempt failed. May be emitted multiple times if
|
|
14
|
-
* family autoselection is enabled.
|
|
15
|
-
*/
|
|
16
|
-
connectionAttemptFailed: [endpoint: InetEndpoint, error: Error];
|
|
17
|
-
/**
|
|
18
|
-
* Emitted when a connection attempt timed out. May be emitted multiple times
|
|
19
|
-
* if family autoselection is enabled.
|
|
20
|
-
*/
|
|
21
|
-
connectionAttemptTimeout: [endpoint: InetEndpoint];
|
|
22
|
-
/** Emitted after resolving the host name but before connecting. */
|
|
23
|
-
lookup: [err: Error | null, address: InetAddress, host: string];
|
|
24
|
-
};
|
|
3
|
+
import { InetSocket, type InetSocketEvents } from "./inet-socket.js";
|
|
4
|
+
/** Event map for {@link TcpSocket}. */
|
|
5
|
+
export type TcpSocketEvents = InetSocketEvents;
|
|
6
|
+
/** Options accepted by {@link TcpSocket.from}. */
|
|
7
|
+
export type TcpSocketOptions = Except<net.SocketConstructorOpts, "fd">;
|
|
8
|
+
/** Options accepted by {@link TcpSocket.connect}. */
|
|
25
9
|
export type TcpSocketConnectOptions = Except<net.TcpSocketConnectOpts, "port"> & {
|
|
10
|
+
/** Aborts the connection attempt and destroys the socket. */
|
|
26
11
|
signal?: AbortSignal;
|
|
27
12
|
};
|
|
28
13
|
/**
|
|
@@ -31,57 +16,32 @@ export type TcpSocketConnectOptions = Except<net.TcpSocketConnectOpts, "port"> &
|
|
|
31
16
|
* Example usage:
|
|
32
17
|
*
|
|
33
18
|
* ```ts
|
|
34
|
-
* const
|
|
35
|
-
* await
|
|
36
|
-
* await
|
|
37
|
-
*
|
|
19
|
+
* const socket = TcpSocket.from();
|
|
20
|
+
* await socket.connect(80, { host: "example.com" });
|
|
21
|
+
* await socket.write(
|
|
22
|
+
* Buffer.from("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"),
|
|
23
|
+
* );
|
|
24
|
+
* await socket.end({ waitForClose: true });
|
|
38
25
|
* ```
|
|
39
26
|
*/
|
|
40
|
-
export declare class TcpSocket<
|
|
27
|
+
export declare class TcpSocket<TSocket extends net.Socket = net.Socket, TEvents extends TcpSocketEvents = TcpSocketEvents> extends InetSocket<TSocket, TEvents> {
|
|
41
28
|
/**
|
|
42
29
|
* Creates a new {@link TcpSocket} instance.
|
|
43
30
|
*
|
|
44
31
|
* @param options Options for creating the underlying Node.js socket.
|
|
45
32
|
* @returns A new `TcpSocket` instance.
|
|
46
33
|
*/
|
|
47
|
-
static from(options?:
|
|
48
|
-
constructor(sock: TSock);
|
|
49
|
-
/**
|
|
50
|
-
* Returns the remote endpoint information of the socket.
|
|
51
|
-
*
|
|
52
|
-
* @throws {UnsupportedError} If the socket family is not IPv4 or IPv6.
|
|
53
|
-
*/
|
|
54
|
-
get remoteEndpoint(): InetEndpoint | null;
|
|
55
|
-
/**
|
|
56
|
-
* Returns the local endpoint information of the socket.
|
|
57
|
-
*
|
|
58
|
-
* @throws {UnsupportedError} If the socket family is not IPv4 or IPv6.
|
|
59
|
-
*/
|
|
60
|
-
get localEndpoint(): InetEndpoint | null;
|
|
61
|
-
/**
|
|
62
|
-
* Sets the keep-alive option for the socket.
|
|
63
|
-
*
|
|
64
|
-
* @param enable Whether to enable keep-alive.
|
|
65
|
-
* @param initialDelay The initial delay in milliseconds before the first
|
|
66
|
-
* keep-alive probe.
|
|
67
|
-
*/
|
|
68
|
-
setKeepAlive(enable: boolean, initialDelay?: number): void;
|
|
69
|
-
/**
|
|
70
|
-
* Disables the Nagle algorithm for the socket.
|
|
71
|
-
*
|
|
72
|
-
* @param noDelay Whether to disable the Nagle algorithm.
|
|
73
|
-
*/
|
|
74
|
-
setNoDelay(noDelay: boolean): void;
|
|
34
|
+
static from(options?: TcpSocketOptions): TcpSocket;
|
|
75
35
|
/**
|
|
76
|
-
* Establishes a TCP connection to the specified port
|
|
36
|
+
* Establishes a TCP connection to the specified port.
|
|
77
37
|
*
|
|
78
38
|
* @param port The port to connect to.
|
|
79
|
-
* @param
|
|
80
|
-
*
|
|
81
|
-
* @returns A promise that resolves when the connection is
|
|
82
|
-
*
|
|
39
|
+
* @param options Connection options, including the host (defaults to
|
|
40
|
+
* `localhost`) and an optional abort signal.
|
|
41
|
+
* @returns A promise that resolves when the connection is established.
|
|
42
|
+
* @throws When the connection fails, when the socket closes before
|
|
43
|
+
* connecting, or when the signal is aborted.
|
|
83
44
|
*/
|
|
84
45
|
connect(port: number, options?: TcpSocketConnectOptions): Promise<void>;
|
|
85
|
-
protected setupEventForwarding(): void;
|
|
86
46
|
}
|
|
87
47
|
//# sourceMappingURL=tcp-socket.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tcp-socket.d.ts","sourceRoot":"","sources":["../../src/net/tcp-socket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,OAAO,
|
|
1
|
+
{"version":3,"file":"tcp-socket.d.ts","sourceRoot":"","sources":["../../src/net/tcp-socket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAErE,uCAAuC;AACvC,MAAM,MAAM,eAAe,GAAG,gBAAgB,CAAC;AAE/C,kDAAkD;AAClD,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC;AAEvE,qDAAqD;AACrD,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAC3C,GAAG,CAAC,oBAAoB,EACxB,MAAM,CACN,GAAG;IACH,6DAA6D;IAC7D,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,qBAAa,SAAS,CACrB,OAAO,SAAS,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,EACvC,OAAO,SAAS,eAAe,GAAG,eAAe,CAChD,SAAQ,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC;IACrC;;;;;OAKG;IACH,OAAgB,IAAI,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAE1D;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAYtE;CACD"}
|
package/dist/net/tcp-socket.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import * as net from "node:net";
|
|
2
|
-
import {
|
|
3
|
-
import { StreamSocket } from "./stream-socket.js";
|
|
2
|
+
import { InetSocket } from "./inet-socket.js";
|
|
4
3
|
/**
|
|
5
4
|
* TCP socket for establishing connections to TCP servers.
|
|
6
5
|
*
|
|
7
6
|
* Example usage:
|
|
8
7
|
*
|
|
9
8
|
* ```ts
|
|
10
|
-
* const
|
|
11
|
-
* await
|
|
12
|
-
* await
|
|
13
|
-
*
|
|
9
|
+
* const socket = TcpSocket.from();
|
|
10
|
+
* await socket.connect(80, { host: "example.com" });
|
|
11
|
+
* await socket.write(
|
|
12
|
+
* Buffer.from("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"),
|
|
13
|
+
* );
|
|
14
|
+
* await socket.end({ waitForClose: true });
|
|
14
15
|
* ```
|
|
15
16
|
*/
|
|
16
|
-
export class TcpSocket extends
|
|
17
|
+
export class TcpSocket extends InetSocket {
|
|
17
18
|
/**
|
|
18
19
|
* Creates a new {@link TcpSocket} instance.
|
|
19
20
|
*
|
|
@@ -23,130 +24,26 @@ export class TcpSocket extends StreamSocket {
|
|
|
23
24
|
static from(options) {
|
|
24
25
|
return new TcpSocket(new net.Socket(options));
|
|
25
26
|
}
|
|
26
|
-
constructor(sock) {
|
|
27
|
-
super(sock);
|
|
28
|
-
this.setupEventForwarding();
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Returns the remote endpoint information of the socket.
|
|
32
|
-
*
|
|
33
|
-
* @throws {UnsupportedError} If the socket family is not IPv4 or IPv6.
|
|
34
|
-
*/
|
|
35
|
-
get remoteEndpoint() {
|
|
36
|
-
const address = this.sock.remoteAddress;
|
|
37
|
-
const port = this.sock.remotePort;
|
|
38
|
-
const familyStr = this.sock.remoteFamily;
|
|
39
|
-
if (address === undefined ||
|
|
40
|
-
port === undefined ||
|
|
41
|
-
familyStr === undefined) {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
return {
|
|
45
|
-
...composeInetAddress(familyStr, address),
|
|
46
|
-
port,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Returns the local endpoint information of the socket.
|
|
51
|
-
*
|
|
52
|
-
* @throws {UnsupportedError} If the socket family is not IPv4 or IPv6.
|
|
53
|
-
*/
|
|
54
|
-
get localEndpoint() {
|
|
55
|
-
const address = this.sock.localAddress;
|
|
56
|
-
const port = this.sock.localPort;
|
|
57
|
-
const familyStr = this.sock.localFamily;
|
|
58
|
-
if (address === undefined ||
|
|
59
|
-
port === undefined ||
|
|
60
|
-
familyStr === undefined) {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
return {
|
|
64
|
-
...composeInetAddress(familyStr, address),
|
|
65
|
-
port,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Sets the keep-alive option for the socket.
|
|
70
|
-
*
|
|
71
|
-
* @param enable Whether to enable keep-alive.
|
|
72
|
-
* @param initialDelay The initial delay in milliseconds before the first
|
|
73
|
-
* keep-alive probe.
|
|
74
|
-
*/
|
|
75
|
-
setKeepAlive(enable, initialDelay) {
|
|
76
|
-
this.sock.setKeepAlive(enable, initialDelay);
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Disables the Nagle algorithm for the socket.
|
|
80
|
-
*
|
|
81
|
-
* @param noDelay Whether to disable the Nagle algorithm.
|
|
82
|
-
*/
|
|
83
|
-
setNoDelay(noDelay) {
|
|
84
|
-
this.sock.setNoDelay(noDelay);
|
|
85
|
-
}
|
|
86
27
|
/**
|
|
87
|
-
* Establishes a TCP connection to the specified port
|
|
28
|
+
* Establishes a TCP connection to the specified port.
|
|
88
29
|
*
|
|
89
30
|
* @param port The port to connect to.
|
|
90
|
-
* @param
|
|
91
|
-
*
|
|
92
|
-
* @returns A promise that resolves when the connection is
|
|
93
|
-
*
|
|
31
|
+
* @param options Connection options, including the host (defaults to
|
|
32
|
+
* `localhost`) and an optional abort signal.
|
|
33
|
+
* @returns A promise that resolves when the connection is established.
|
|
34
|
+
* @throws When the connection fails, when the socket closes before
|
|
35
|
+
* connecting, or when the signal is aborted.
|
|
94
36
|
*/
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
signal
|
|
99
|
-
|
|
100
|
-
this.
|
|
101
|
-
|
|
102
|
-
reject(error);
|
|
103
|
-
};
|
|
104
|
-
this.sock.prependOnceListener("error", handleError);
|
|
105
|
-
const handleAbort = () => {
|
|
106
|
-
this.sock.removeListener("error", handleError);
|
|
107
|
-
this.sock.destroy();
|
|
108
|
-
reject(signal?.reason);
|
|
109
|
-
};
|
|
110
|
-
signal?.addEventListener("abort", handleAbort, { once: true });
|
|
111
|
-
this.sock.connect({
|
|
112
|
-
...connectOptions,
|
|
113
|
-
port,
|
|
114
|
-
}, () => {
|
|
115
|
-
this.sock.removeListener("error", handleError);
|
|
116
|
-
signal?.removeEventListener("abort", handleAbort);
|
|
117
|
-
resolve();
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
setupEventForwarding() {
|
|
122
|
-
super.setupEventForwarding();
|
|
123
|
-
this.sock.on("connectionAttempt", (ip, port, family) => {
|
|
124
|
-
this.dispatch("connectionAttempt", [
|
|
125
|
-
{
|
|
126
|
-
...composeInetAddress(family, ip),
|
|
127
|
-
port,
|
|
128
|
-
},
|
|
129
|
-
]);
|
|
130
|
-
});
|
|
131
|
-
this.sock.on("connectionAttemptFailed", (ip, port, family, error) => {
|
|
132
|
-
this.dispatch("connectionAttemptFailed", [
|
|
133
|
-
{
|
|
134
|
-
...composeInetAddress(family, ip),
|
|
37
|
+
connect(port, options) {
|
|
38
|
+
const { signal, ...connectOptions } = options ?? {};
|
|
39
|
+
return this.awaitReady("connect", {
|
|
40
|
+
signal,
|
|
41
|
+
start: () => {
|
|
42
|
+
this.socket.connect({
|
|
43
|
+
...connectOptions,
|
|
135
44
|
port,
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
]);
|
|
139
|
-
});
|
|
140
|
-
this.sock.on("connectionAttemptTimeout", (ip, port, family) => {
|
|
141
|
-
this.dispatch("connectionAttemptTimeout", [
|
|
142
|
-
{
|
|
143
|
-
...composeInetAddress(family, ip),
|
|
144
|
-
port,
|
|
145
|
-
},
|
|
146
|
-
]);
|
|
147
|
-
});
|
|
148
|
-
this.sock.on("lookup", (err, address, family, host) => {
|
|
149
|
-
this.dispatch("lookup", [err, composeInetAddress(family, address), host]);
|
|
45
|
+
});
|
|
46
|
+
},
|
|
150
47
|
});
|
|
151
48
|
}
|
|
152
49
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tcp-socket.js","sourceRoot":"","sources":["../../src/net/tcp-socket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"tcp-socket.js","sourceRoot":"","sources":["../../src/net/tcp-socket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAIhC,OAAO,EAAE,UAAU,EAAyB,MAAM,kBAAkB,CAAC;AAiBrE;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,SAGX,SAAQ,UAA4B;IACrC;;;;;OAKG;IACH,MAAM,CAAU,IAAI,CAAC,OAA0B;QAC9C,OAAO,IAAI,SAAS,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,IAAY,EAAE,OAAiC;QACtD,MAAM,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;QAEpD,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE;YACjC,MAAM;YACN,KAAK,EAAE,GAAG,EAAE;gBACX,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;oBACnB,GAAG,cAAc;oBACjB,IAAI;iBACJ,CAAC,CAAC;YACJ,CAAC;SACD,CAAC,CAAC;IACJ,CAAC;CACD"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import * as tls from "node:tls";
|
|
2
|
+
import { type IError } from "@ac-kit/core";
|
|
3
|
+
import { TcpServer, type TcpServerEvents } from "./tcp-server.js";
|
|
4
|
+
import { TlsSocket, type TlsSecureContext } from "./tls-socket.js";
|
|
5
|
+
/** Event map for {@link TlsServer}. */
|
|
6
|
+
export type TlsServerEvents = TcpServerEvents & {
|
|
7
|
+
/** Emitted once a connection completed its TLS handshake. */
|
|
8
|
+
secureConnection: [socket: TlsSocket];
|
|
9
|
+
/**
|
|
10
|
+
* Emitted when a connection failed its TLS handshake. The socket is already
|
|
11
|
+
* unusable; the event only reports why the client was rejected.
|
|
12
|
+
*/
|
|
13
|
+
tlsClientError: [error: IError, socket: TlsSocket];
|
|
14
|
+
/** Emitted with each line of TLS key material, for traffic decryption. */
|
|
15
|
+
keylog: [line: Buffer, socket: TlsSocket];
|
|
16
|
+
};
|
|
17
|
+
/** Options accepted by {@link TlsServer.from}. */
|
|
18
|
+
export type TlsServerOptions = tls.TlsOptions;
|
|
19
|
+
/**
|
|
20
|
+
* TLS server accepting encrypted incoming connections.
|
|
21
|
+
*
|
|
22
|
+
* Example usage:
|
|
23
|
+
*
|
|
24
|
+
* ```ts
|
|
25
|
+
* const server = TlsServer.from({ key, cert });
|
|
26
|
+
* server.subscribe("secureConnection", (socket) => {
|
|
27
|
+
* console.log("Client cipher:", socket.getCipher().name);
|
|
28
|
+
* });
|
|
29
|
+
* await server.listen(8443, "0.0.0.0");
|
|
30
|
+
* // ... later
|
|
31
|
+
* await server.close();
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* Every event of {@link TcpServer} is still emitted, so
|
|
35
|
+
* {@link TcpServerEvents.connection} reports the plaintext socket accepted
|
|
36
|
+
* _before_ the handshake. Wait for {@link TlsServerEvents.secureConnection} to
|
|
37
|
+
* read or write application data.
|
|
38
|
+
*
|
|
39
|
+
* The session-resumption events Node.js exposes with a completion callback
|
|
40
|
+
* (`newSession`, `resumeSession` and `OCSPRequest`) are deliberately not
|
|
41
|
+
* forwarded: Node.js falls back to its default behaviour only while no listener
|
|
42
|
+
* is attached, so forwarding them would stall every handshake that nobody
|
|
43
|
+
* subscribed to.
|
|
44
|
+
*/
|
|
45
|
+
export declare class TlsServer extends TcpServer<tls.Server, TlsServerEvents> {
|
|
46
|
+
/**
|
|
47
|
+
* Creates a new {@link TlsServer} instance.
|
|
48
|
+
*
|
|
49
|
+
* @param options Options for creating the underlying Node.js server,
|
|
50
|
+
* including the certificate chain and private key to serve.
|
|
51
|
+
* @returns A new `TlsServer` instance.
|
|
52
|
+
*/
|
|
53
|
+
static from(options?: TlsServerOptions): TlsServer;
|
|
54
|
+
/**
|
|
55
|
+
* Adds a secure context to serve when a client requests `hostname` through
|
|
56
|
+
* SNI.
|
|
57
|
+
*
|
|
58
|
+
* @param hostname The server name to match, which may contain wildcards.
|
|
59
|
+
* @param context The secure context or the options to build one from.
|
|
60
|
+
*/
|
|
61
|
+
addContext(hostname: string, context: TlsSecureContext): void;
|
|
62
|
+
/**
|
|
63
|
+
* Replaces the default secure context, affecting connections established
|
|
64
|
+
* after the call.
|
|
65
|
+
*
|
|
66
|
+
* @param context The options to build the secure context from.
|
|
67
|
+
*/
|
|
68
|
+
setSecureContext(context: tls.SecureContextOptions): void;
|
|
69
|
+
/**
|
|
70
|
+
* Returns the keys used to encrypt session tickets.
|
|
71
|
+
*
|
|
72
|
+
* Sharing them across server instances lets clients resume a session on any
|
|
73
|
+
* of them; they are sensitive key material and must be handled as secrets.
|
|
74
|
+
*
|
|
75
|
+
* @returns The 48-byte session ticket keys.
|
|
76
|
+
*/
|
|
77
|
+
getTicketKeys(): Buffer;
|
|
78
|
+
/**
|
|
79
|
+
* Sets the keys used to encrypt session tickets, affecting connections
|
|
80
|
+
* established after the call.
|
|
81
|
+
*
|
|
82
|
+
* @param keys The 48-byte session ticket keys.
|
|
83
|
+
*/
|
|
84
|
+
setTicketKeys(keys: Buffer): void;
|
|
85
|
+
protected setupEventForwarding(): void;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=tls-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tls-server.d.ts","sourceRoot":"","sources":["../../src/net/tls-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnE,uCAAuC;AACvC,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG;IAC/C,6DAA6D;IAC7D,gBAAgB,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAEtC;;;OAGG;IACH,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IAEnD,0EAA0E;IAC1E,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;CAC1C,CAAC;AAEF,kDAAkD;AAClD,MAAM,MAAM,gBAAgB,GAAG,GAAG,CAAC,UAAU,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,SAAU,SAAQ,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC;IACpE;;;;;;OAMG;IACH,OAAgB,IAAI,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAE1D;IAED;;;;;;OAMG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAE5D;IAED;;;;;OAKG;IACH,gBAAgB,CAAC,OAAO,EAAE,GAAG,CAAC,oBAAoB,GAAG,IAAI,CAExD;IAED;;;;;;;OAOG;IACH,aAAa,IAAI,MAAM,CAEtB;IAED;;;;;OAKG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEhC;IAED,UAAmB,oBAAoB,IAAI,IAAI,CAc9C;CACD"}
|