@fuman/net 0.0.4 → 0.0.8
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/errors.d.cts +6 -0
- package/fake.d.cts +16 -0
- package/index.d.cts +7 -0
- package/ip/bundle.d.cts +3 -0
- package/ip/index.d.cts +8 -0
- package/ip/parse.d.cts +5 -0
- package/ip/types.d.cts +10 -0
- package/ip/v4.bench.d.cts +1 -0
- package/ip/v4.d.cts +4 -0
- package/ip/v6.bench.d.cts +1 -0
- package/ip/v6.d.cts +18 -0
- package/package.json +2 -2
- package/proxy/http/_protocol.d.cts +3 -0
- package/proxy/http/connect.d.cts +4 -0
- package/proxy/http/index.d.cts +5 -0
- package/proxy/http/types.d.cts +32 -0
- package/proxy/index.d.cts +2 -0
- package/proxy/socks/_protocol.d.cts +7 -0
- package/proxy/socks/connect.d.cts +4 -0
- package/proxy/socks/index.d.cts +5 -0
- package/proxy/socks/types.d.cts +34 -0
- package/reconnection.d.cts +82 -0
- package/types.d.cts +57 -0
- package/websocket.d.cts +43 -0
package/errors.d.cts
ADDED
package/fake.d.cts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IConnection } from './types.js';
|
|
2
|
+
export declare class FakeConnection<Address = string> implements IConnection<Address, Address> {
|
|
3
|
+
readonly address: Address;
|
|
4
|
+
constructor(address: Address);
|
|
5
|
+
private rx;
|
|
6
|
+
private tx;
|
|
7
|
+
private closed;
|
|
8
|
+
private cv;
|
|
9
|
+
get localAddress(): Address;
|
|
10
|
+
get remoteAddress(): Address;
|
|
11
|
+
close(): void;
|
|
12
|
+
read(into: Uint8Array): Promise<number>;
|
|
13
|
+
write(bytes: Uint8Array): Promise<void>;
|
|
14
|
+
writeIntoRx(bytes: Uint8Array): void;
|
|
15
|
+
getTx(): Uint8Array;
|
|
16
|
+
}
|
package/index.d.cts
ADDED
package/ip/bundle.d.cts
ADDED
package/ip/index.d.cts
ADDED
package/ip/parse.d.cts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Ipv4Address, Ipv6Address } from './types.js';
|
|
2
|
+
export declare function parse(ip: string): Ipv4Address | Ipv6Address;
|
|
3
|
+
export declare function parseWithPort(ip: string): [Ipv4Address | Ipv6Address, number];
|
|
4
|
+
export declare function stringify(parsed: Ipv4Address | Ipv6Address): string;
|
|
5
|
+
export declare function stringifyWithPort(parsed: Ipv4Address | Ipv6Address, port: number): string;
|
package/ip/types.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/ip/v4.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/ip/v6.d.cts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ISyncReadable, ISyncWritable } from '@fuman/io';
|
|
2
|
+
import { Ipv6Address } from './types.js';
|
|
3
|
+
export declare function parseV6(string: string): Ipv6Address;
|
|
4
|
+
export interface StringifyV6Options {
|
|
5
|
+
/**
|
|
6
|
+
* Whether to compress consecutive zeroes
|
|
7
|
+
* (according to [RFC 5952](https://datatracker.ietf.org/doc/html/rfc5952#section-4))
|
|
8
|
+
*/
|
|
9
|
+
zeroCompression?: boolean;
|
|
10
|
+
/** Whether to pad each part to 4 characters */
|
|
11
|
+
fixedLength?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function stringifyV6(parsed: Ipv6Address, options?: StringifyV6Options): string;
|
|
14
|
+
export declare function expandV6(string: string): string;
|
|
15
|
+
export declare function fromBytesV6(bytes: Uint8Array): Ipv6Address;
|
|
16
|
+
export declare function readV6(reader: ISyncReadable): Ipv6Address;
|
|
17
|
+
export declare function toBytesV6(parsed: Ipv6Address): Uint8Array;
|
|
18
|
+
export declare function writeV6(parsed: Ipv6Address, writer: ISyncWritable): void;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fuman/net",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.8",
|
|
5
5
|
"description": "experimental network abstractions",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"scripts": {},
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@fuman/io": "^0.0.
|
|
9
|
+
"@fuman/io": "^0.0.8",
|
|
10
10
|
"@fuman/utils": "^0.0.4"
|
|
11
11
|
},
|
|
12
12
|
"exports": {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { TcpEndpoint } from '../../types.js';
|
|
2
|
+
import { IReadable, IWritable } from '@fuman/io';
|
|
3
|
+
import { HttpProxySettings } from './types.js';
|
|
4
|
+
export declare function performHttpProxyHandshake(reader: IReadable, writer: IWritable, proxy: HttpProxySettings, destination: TcpEndpoint): Promise<void>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ConnectFunction, ITcpConnection, TcpEndpoint } from '../../types.js';
|
|
2
|
+
import { HttpProxySettings } from './types.js';
|
|
3
|
+
export * from './connect.js';
|
|
4
|
+
export * from './types.js';
|
|
5
|
+
export declare function withHttpProxy<Connection extends ITcpConnection, Connect extends ConnectFunction<TcpEndpoint, Connection>>(connect: Connect, proxy: HttpProxySettings): Connect;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An error has occurred while connecting to an HTTP(s) proxy
|
|
3
|
+
*/
|
|
4
|
+
export declare class HttpProxyConnectionError extends Error {
|
|
5
|
+
readonly proxy: HttpProxySettings;
|
|
6
|
+
constructor(proxy: HttpProxySettings, message: string);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* HTTP(s) proxy settings
|
|
10
|
+
*/
|
|
11
|
+
export interface HttpProxySettings {
|
|
12
|
+
/**
|
|
13
|
+
* Host or IP of the proxy (e.g. `proxy.example.com`, `1.2.3.4`)
|
|
14
|
+
*/
|
|
15
|
+
host: string;
|
|
16
|
+
/**
|
|
17
|
+
* Port of the proxy (e.g. `8888`)
|
|
18
|
+
*/
|
|
19
|
+
port: number;
|
|
20
|
+
/**
|
|
21
|
+
* Proxy authorization username, if needed
|
|
22
|
+
*/
|
|
23
|
+
user?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Proxy authorization password, if needed
|
|
26
|
+
*/
|
|
27
|
+
password?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Proxy connection headers, if needed
|
|
30
|
+
*/
|
|
31
|
+
headers?: Record<string, string>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TcpEndpoint } from '../../types.js';
|
|
2
|
+
export declare const SOCKS4_ERRORS: Record<number, string>;
|
|
3
|
+
export declare const SOCKS5_ERRORS: Record<number, string>;
|
|
4
|
+
export declare function buildSocks4Connect(dest: TcpEndpoint, username?: string): Uint8Array;
|
|
5
|
+
export declare function buildSocks5Greeting(authAvailable: boolean): Uint8Array;
|
|
6
|
+
export declare function buildSocks5Auth(username: string, password: string): Uint8Array;
|
|
7
|
+
export declare function buildSocks5Connect(dest: TcpEndpoint): Uint8Array;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { IReadable, IWritable } from '@fuman/io';
|
|
2
|
+
import { TcpEndpoint } from '../../types.js';
|
|
3
|
+
import { SocksProxySettings } from './types.js';
|
|
4
|
+
export declare function performSocksHandshake(reader: IReadable, writer: IWritable, proxy: SocksProxySettings, destination: TcpEndpoint): Promise<void>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ConnectFunction, ITcpConnection, TcpEndpoint } from '../../types.js';
|
|
2
|
+
import { SocksProxySettings } from './types.js';
|
|
3
|
+
export * from './connect.js';
|
|
4
|
+
export * from './types.js';
|
|
5
|
+
export declare function withSocksProxy<Connection extends ITcpConnection, Connect extends ConnectFunction<TcpEndpoint, Connection>>(connect: Connect, proxy: SocksProxySettings): Connect;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings for a SOCKS4/5 proxy
|
|
3
|
+
*/
|
|
4
|
+
export interface SocksProxySettings {
|
|
5
|
+
/**
|
|
6
|
+
* Host or IP of the proxy (e.g. `proxy.example.com`, `1.2.3.4`)
|
|
7
|
+
*/
|
|
8
|
+
host: string;
|
|
9
|
+
/**
|
|
10
|
+
* Port of the proxy (e.g. `8888`)
|
|
11
|
+
*/
|
|
12
|
+
port: number;
|
|
13
|
+
/**
|
|
14
|
+
* Proxy authorization username, if needed
|
|
15
|
+
*/
|
|
16
|
+
user?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Proxy authorization password, if needed
|
|
19
|
+
*/
|
|
20
|
+
password?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Version of the SOCKS proxy (4 or 5)
|
|
23
|
+
*
|
|
24
|
+
* @default `5`
|
|
25
|
+
*/
|
|
26
|
+
version?: 4 | 5;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* An error has occurred while connecting to an SOCKS proxy
|
|
30
|
+
*/
|
|
31
|
+
export declare class SocksProxyConnectionError extends Error {
|
|
32
|
+
readonly proxy: SocksProxySettings;
|
|
33
|
+
constructor(proxy: SocksProxySettings, message: string);
|
|
34
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { IClosable } from '@fuman/io';
|
|
2
|
+
import { MaybePromise } from '@fuman/utils';
|
|
3
|
+
interface ReconnectionState {
|
|
4
|
+
readonly previousWait: number | null;
|
|
5
|
+
readonly consequentFails: number;
|
|
6
|
+
readonly lastError: Error | null;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Declares a strategy to handle reconnection.
|
|
10
|
+
* When a number is returned, that number of MS will be waited before trying to reconnect.
|
|
11
|
+
* When `false` is returned, connection is not reconnected
|
|
12
|
+
*/
|
|
13
|
+
export type ReconnectionStrategy = (state: ReconnectionState) => number | false;
|
|
14
|
+
/**
|
|
15
|
+
* Declares an action to take when an error occurs.
|
|
16
|
+
*
|
|
17
|
+
* - `reconnect` - reconnect using the current strategy
|
|
18
|
+
* - `reconnect-now` - reconnect immediately, ignoring the current strategy
|
|
19
|
+
* - `close` - close the connection
|
|
20
|
+
*/
|
|
21
|
+
export type OnErrorAction = 'reconnect' | 'reconnect-now' | 'close';
|
|
22
|
+
/**
|
|
23
|
+
* default reconnection strategy: first - immediate reconnection,
|
|
24
|
+
* then 1s with linear increase up to 5s (with 1s step)
|
|
25
|
+
*/
|
|
26
|
+
export declare const defaultReconnectionStrategy: ReconnectionStrategy;
|
|
27
|
+
export declare class PersistentConnection<ConnectAddress, Connection extends IClosable> {
|
|
28
|
+
#private;
|
|
29
|
+
readonly params: {
|
|
30
|
+
connect: (address: ConnectAddress) => Promise<Connection>;
|
|
31
|
+
strategy?: ReconnectionStrategy;
|
|
32
|
+
/**
|
|
33
|
+
* Function to call once the connection is open
|
|
34
|
+
*
|
|
35
|
+
* As soon as the promise is resolved the connection will be closed (and will *not*
|
|
36
|
+
* be re-opened automatically), so this is the best place to put your recv loop
|
|
37
|
+
*/
|
|
38
|
+
onOpen: (connection: Connection) => Promise<void>;
|
|
39
|
+
onClose?: () => MaybePromise<void>;
|
|
40
|
+
onWait?: (wait: number) => void;
|
|
41
|
+
/**
|
|
42
|
+
* Function that will be called whenever an error happens while connecting
|
|
43
|
+
* (in which case `connection` will be null) or inside `onOpen`.
|
|
44
|
+
*
|
|
45
|
+
* @default `(err) => err instanceof ConnectionClosedError ? 'reconnect' : 'close'`
|
|
46
|
+
*/
|
|
47
|
+
onError?: (error: Error, connection: Connection | null, state: ReconnectionState) => MaybePromise<OnErrorAction>;
|
|
48
|
+
};
|
|
49
|
+
constructor(params: {
|
|
50
|
+
connect: (address: ConnectAddress) => Promise<Connection>;
|
|
51
|
+
strategy?: ReconnectionStrategy;
|
|
52
|
+
/**
|
|
53
|
+
* Function to call once the connection is open
|
|
54
|
+
*
|
|
55
|
+
* As soon as the promise is resolved the connection will be closed (and will *not*
|
|
56
|
+
* be re-opened automatically), so this is the best place to put your recv loop
|
|
57
|
+
*/
|
|
58
|
+
onOpen: (connection: Connection) => Promise<void>;
|
|
59
|
+
onClose?: () => MaybePromise<void>;
|
|
60
|
+
onWait?: (wait: number) => void;
|
|
61
|
+
/**
|
|
62
|
+
* Function that will be called whenever an error happens while connecting
|
|
63
|
+
* (in which case `connection` will be null) or inside `onOpen`.
|
|
64
|
+
*
|
|
65
|
+
* @default `(err) => err instanceof ConnectionClosedError ? 'reconnect' : 'close'`
|
|
66
|
+
*/
|
|
67
|
+
onError?: (error: Error, connection: Connection | null, state: ReconnectionState) => MaybePromise<OnErrorAction>;
|
|
68
|
+
});
|
|
69
|
+
get isConnected(): boolean;
|
|
70
|
+
get isConnecting(): boolean;
|
|
71
|
+
get isWaiting(): boolean;
|
|
72
|
+
get connection(): Connection | null;
|
|
73
|
+
get state(): ReconnectionState;
|
|
74
|
+
connect(address: ConnectAddress): void;
|
|
75
|
+
/**
|
|
76
|
+
* @param force Whether to close the existing connection if there is one
|
|
77
|
+
*/
|
|
78
|
+
reconnect(force: boolean): void;
|
|
79
|
+
close(): Promise<void>;
|
|
80
|
+
changeTransport(connect: (address: ConnectAddress) => Promise<Connection>): Promise<void>;
|
|
81
|
+
}
|
|
82
|
+
export {};
|
package/types.d.cts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { IClosable, IReadable, IWritable } from '@fuman/io';
|
|
2
|
+
export interface IConnection<Address, LocalAddress = Address> extends IReadable, IWritable, IClosable {
|
|
3
|
+
/** local address of the connection (if available) */
|
|
4
|
+
readonly localAddress: LocalAddress | null;
|
|
5
|
+
/** remote address of the connection (if available) */
|
|
6
|
+
readonly remoteAddress: Address | null;
|
|
7
|
+
}
|
|
8
|
+
/** a TCP endpoint */
|
|
9
|
+
export interface TcpEndpoint {
|
|
10
|
+
/** address of the endpoint */
|
|
11
|
+
readonly address: string;
|
|
12
|
+
/** port of the endpoint */
|
|
13
|
+
readonly port: number;
|
|
14
|
+
}
|
|
15
|
+
/** common TLS options */
|
|
16
|
+
export interface TlsOptions {
|
|
17
|
+
/**
|
|
18
|
+
* List of CA certificates to use.
|
|
19
|
+
* Will replace whatever is in the default platform CA store.
|
|
20
|
+
*/
|
|
21
|
+
readonly caCerts?: string[];
|
|
22
|
+
/** List of ALPN protocols to accept/offer */
|
|
23
|
+
readonly alpnProtocols?: string[];
|
|
24
|
+
/** Hostname to use for SNI */
|
|
25
|
+
readonly sni?: string;
|
|
26
|
+
}
|
|
27
|
+
/** TLS options for connecting to an endpoint */
|
|
28
|
+
export interface TlsConnectOptions extends TcpEndpoint, TlsOptions {
|
|
29
|
+
}
|
|
30
|
+
/** TLS options for listening on an endpoint */
|
|
31
|
+
export interface TlsListenOptions extends TcpEndpoint, TlsOptions {
|
|
32
|
+
readonly key?: string;
|
|
33
|
+
readonly cert?: string;
|
|
34
|
+
readonly hosts?: Omit<this, 'hosts' | 'address' | 'port'>[];
|
|
35
|
+
}
|
|
36
|
+
/** a TCP connection */
|
|
37
|
+
export interface ITcpConnection extends IConnection<TcpEndpoint> {
|
|
38
|
+
/** set no-delay flag on the connection */
|
|
39
|
+
setNoDelay: (noDelay: boolean) => void;
|
|
40
|
+
/** set keep-alive flag on the connection */
|
|
41
|
+
setKeepAlive: (keepAlive: boolean) => void;
|
|
42
|
+
}
|
|
43
|
+
/** a TLS connection */
|
|
44
|
+
export interface ITlsConnection extends ITcpConnection {
|
|
45
|
+
/** get the ALPN protocol that was negotiated in the handshake */
|
|
46
|
+
getAlpnProtocol: () => string | null;
|
|
47
|
+
}
|
|
48
|
+
/** a listener for connections */
|
|
49
|
+
export interface IListener<Address, Connection extends IConnection<Address> = IConnection<Address>> extends IClosable {
|
|
50
|
+
/** address of the listener (if available) */
|
|
51
|
+
readonly address: Address | null;
|
|
52
|
+
/** accept a new connection */
|
|
53
|
+
accept: () => Promise<Connection>;
|
|
54
|
+
}
|
|
55
|
+
export type ListenFunction<Options, Listener extends IListener<unknown>> = (options: Options) => Promise<Listener>;
|
|
56
|
+
export type ConnectFunction<Options, Connection extends IConnection<unknown>> = (options: Options) => Promise<Connection>;
|
|
57
|
+
export type TlsUpgradeFunction<Options, TcpConnection extends ITcpConnection, TlsConnection extends ITlsConnection> = (tcpConn: TcpConnection, options: Options) => Promise<TlsConnection>;
|
package/websocket.d.cts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { IClosable } from '@fuman/io';
|
|
2
|
+
import { ConnectFunction, IConnection } from './types.js';
|
|
3
|
+
import { ConditionVariable } from '@fuman/utils';
|
|
4
|
+
import { ConnectionClosedError } from './errors.js';
|
|
5
|
+
export declare class WebSocketConnectionClosedError extends ConnectionClosedError {
|
|
6
|
+
readonly code: number;
|
|
7
|
+
readonly reason: string;
|
|
8
|
+
constructor(code: number, reason: string);
|
|
9
|
+
}
|
|
10
|
+
declare abstract class WebSocketConnectionBase implements IClosable {
|
|
11
|
+
readonly socket: WebSocket;
|
|
12
|
+
protected _error: Error | null;
|
|
13
|
+
protected _cv: ConditionVariable;
|
|
14
|
+
constructor(socket: WebSocket);
|
|
15
|
+
get remoteAddress(): string | null;
|
|
16
|
+
get localAddress(): never;
|
|
17
|
+
close(): void;
|
|
18
|
+
closeWithCode(code: number, reason?: string): void;
|
|
19
|
+
abstract onMessage(event: MessageEvent): void;
|
|
20
|
+
}
|
|
21
|
+
export declare class WebSocketConnection extends WebSocketConnectionBase implements IConnection<string, never> {
|
|
22
|
+
#private;
|
|
23
|
+
onMessage(event: MessageEvent): void;
|
|
24
|
+
read(into: Uint8Array): Promise<number>;
|
|
25
|
+
write(bytes: Uint8Array): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
export declare class WebSocketConnectionFramed extends WebSocketConnectionBase {
|
|
28
|
+
#private;
|
|
29
|
+
onMessage(event: MessageEvent): void;
|
|
30
|
+
readFrame(): Promise<Uint8Array | string>;
|
|
31
|
+
writeFrame(data: Uint8Array | string): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
export interface WebSocketConstructor {
|
|
34
|
+
new (url: string | URL, protocols?: string | string[]): WebSocket;
|
|
35
|
+
}
|
|
36
|
+
export interface WebSocketEndpoint {
|
|
37
|
+
readonly url: string | URL;
|
|
38
|
+
readonly implementation?: WebSocketConstructor;
|
|
39
|
+
readonly protocols?: string | string[];
|
|
40
|
+
}
|
|
41
|
+
export declare const connectWs: ConnectFunction<WebSocketEndpoint, WebSocketConnection>;
|
|
42
|
+
export declare function connectWsFramed(endpoint: WebSocketEndpoint): Promise<WebSocketConnectionFramed>;
|
|
43
|
+
export {};
|