@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 ADDED
@@ -0,0 +1,6 @@
1
+ export declare class ConnectionClosedError extends Error {
2
+ constructor(message?: string);
3
+ }
4
+ export declare class ListenerClosedError extends Error {
5
+ constructor();
6
+ }
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
@@ -0,0 +1,7 @@
1
+ export * from './errors.js';
2
+ export * from './fake.js';
3
+ export * from './ip/index.js';
4
+ export * from './proxy/index.js';
5
+ export * from './reconnection.js';
6
+ export * from './types.js';
7
+ export * from './websocket.js';
@@ -0,0 +1,3 @@
1
+ export * from './parse.js';
2
+ export * from './v4.js';
3
+ export * from './v6.js';
package/ip/index.d.cts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Utilities for parsing and manipulating IP addresses.
3
+ *
4
+ * @module
5
+ */
6
+ import * as ip from './bundle.js';
7
+ export * from './types.js';
8
+ export { ip };
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,10 @@
1
+ export interface Ipv4Address {
2
+ type: 'ipv4';
3
+ parts: Uint8Array;
4
+ }
5
+ export interface Ipv6Address {
6
+ type: 'ipv6';
7
+ parts: Uint16Array;
8
+ zoneId?: string;
9
+ }
10
+ export type IpAddress = Ipv4Address | Ipv6Address;
@@ -0,0 +1 @@
1
+ export {};
package/ip/v4.d.cts ADDED
@@ -0,0 +1,4 @@
1
+ import { Ipv4Address } from './types.js';
2
+ export declare function parseV4(input: string): Ipv4Address;
3
+ export declare function stringifyV4(ip: Ipv4Address): string;
4
+ export declare function normalizeV4(input: string): string;
@@ -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",
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.4",
9
+ "@fuman/io": "^0.0.8",
10
10
  "@fuman/utils": "^0.0.4"
11
11
  },
12
12
  "exports": {
@@ -0,0 +1,3 @@
1
+ import { TcpEndpoint } from '../../types.js';
2
+ import { HttpProxySettings } from './types.js';
3
+ export declare function buildConnectRequest(options: HttpProxySettings, dest: TcpEndpoint): Uint8Array;
@@ -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,2 @@
1
+ export * from './http/index.js';
2
+ export * from './socks/index.js';
@@ -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>;
@@ -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 {};