react-native-nitro-net 0.2.0 → 0.3.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.
Files changed (70) hide show
  1. package/README.md +70 -12
  2. package/android/libs/arm64-v8a/librust_c_net.so +0 -0
  3. package/android/libs/armeabi-v7a/librust_c_net.so +0 -0
  4. package/android/libs/x86/librust_c_net.so +0 -0
  5. package/android/libs/x86_64/librust_c_net.so +0 -0
  6. package/cpp/HybridHttpParser.hpp +67 -0
  7. package/cpp/HybridNetDriver.hpp +6 -0
  8. package/cpp/HybridNetServerDriver.hpp +7 -0
  9. package/cpp/HybridNetSocketDriver.hpp +27 -0
  10. package/cpp/NetBindings.hpp +15 -0
  11. package/ios/Frameworks/RustCNet.xcframework/Info.plist +5 -5
  12. package/ios/Frameworks/RustCNet.xcframework/ios-arm64/RustCNet.framework/RustCNet +0 -0
  13. package/ios/Frameworks/RustCNet.xcframework/ios-arm64_x86_64-simulator/RustCNet.framework/RustCNet +0 -0
  14. package/lib/Net.nitro.d.ts +19 -0
  15. package/lib/http.d.ts +203 -0
  16. package/lib/http.js +1138 -0
  17. package/lib/https.d.ts +24 -0
  18. package/lib/https.js +144 -0
  19. package/lib/index.d.ts +46 -8
  20. package/lib/index.js +133 -26
  21. package/lib/tls.d.ts +21 -0
  22. package/lib/tls.js +74 -4
  23. package/nitrogen/generated/android/RustCNet+autolinking.cmake +2 -0
  24. package/nitrogen/generated/android/RustCNetOnLoad.cpp +2 -0
  25. package/nitrogen/generated/android/c++/JHybridHttpParserSpec.cpp +54 -0
  26. package/nitrogen/generated/android/c++/JHybridHttpParserSpec.hpp +65 -0
  27. package/nitrogen/generated/android/c++/JHybridNetDriverSpec.cpp +9 -0
  28. package/nitrogen/generated/android/c++/JHybridNetDriverSpec.hpp +1 -0
  29. package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.cpp +4 -0
  30. package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.hpp +1 -0
  31. package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.cpp +9 -0
  32. package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.hpp +2 -0
  33. package/nitrogen/generated/android/c++/JNetConfig.hpp +7 -3
  34. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridHttpParserSpec.kt +58 -0
  35. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetDriverSpec.kt +4 -0
  36. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetServerDriverSpec.kt +4 -0
  37. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetSocketDriverSpec.kt +8 -0
  38. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/NetConfig.kt +6 -3
  39. package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Bridge.cpp +17 -0
  40. package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Bridge.hpp +26 -0
  41. package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Umbrella.hpp +5 -0
  42. package/nitrogen/generated/ios/c++/HybridHttpParserSpecSwift.cpp +11 -0
  43. package/nitrogen/generated/ios/c++/HybridHttpParserSpecSwift.hpp +79 -0
  44. package/nitrogen/generated/ios/c++/HybridNetDriverSpecSwift.hpp +11 -0
  45. package/nitrogen/generated/ios/c++/HybridNetServerDriverSpecSwift.hpp +6 -0
  46. package/nitrogen/generated/ios/c++/HybridNetSocketDriverSpecSwift.hpp +14 -0
  47. package/nitrogen/generated/ios/swift/HybridHttpParserSpec.swift +56 -0
  48. package/nitrogen/generated/ios/swift/HybridHttpParserSpec_cxx.swift +131 -0
  49. package/nitrogen/generated/ios/swift/HybridNetDriverSpec.swift +1 -0
  50. package/nitrogen/generated/ios/swift/HybridNetDriverSpec_cxx.swift +15 -0
  51. package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec.swift +1 -0
  52. package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec_cxx.swift +11 -0
  53. package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec.swift +2 -0
  54. package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec_cxx.swift +36 -0
  55. package/nitrogen/generated/ios/swift/NetConfig.swift +19 -1
  56. package/nitrogen/generated/shared/c++/HybridHttpParserSpec.cpp +21 -0
  57. package/nitrogen/generated/shared/c++/HybridHttpParserSpec.hpp +63 -0
  58. package/nitrogen/generated/shared/c++/HybridNetDriverSpec.cpp +1 -0
  59. package/nitrogen/generated/shared/c++/HybridNetDriverSpec.hpp +4 -0
  60. package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.cpp +1 -0
  61. package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.hpp +1 -0
  62. package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.cpp +2 -0
  63. package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.hpp +2 -0
  64. package/nitrogen/generated/shared/c++/NetConfig.hpp +6 -2
  65. package/package.json +3 -3
  66. package/src/Net.nitro.ts +17 -0
  67. package/src/http.ts +1304 -0
  68. package/src/https.ts +127 -0
  69. package/src/index.ts +149 -18
  70. package/src/tls.ts +82 -6
package/lib/https.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ import * as http from './http';
2
+ import * as tls from './tls';
3
+ import { IncomingMessage } from './http';
4
+ export declare class Server extends tls.Server {
5
+ private _httpConnections;
6
+ maxHeaderSize: number;
7
+ maxRequestsPerSocket: number;
8
+ headersTimeout: number;
9
+ requestTimeout: number;
10
+ keepAliveTimeout: number;
11
+ constructor(options?: any, requestListener?: (req: http.IncomingMessage, res: http.ServerResponse) => void);
12
+ setTimeout(ms: number, callback?: () => void): this;
13
+ }
14
+ export declare function createServer(options?: any, requestListener?: (req: http.IncomingMessage, res: http.ServerResponse) => void): Server;
15
+ export declare class ClientRequest extends http.ClientRequest {
16
+ constructor(options: any, callback?: (res: http.IncomingMessage) => void);
17
+ }
18
+ export declare function request(urlOrOptions: string | URL | http.RequestOptions, optionsOrCallback?: http.RequestOptions | ((res: http.IncomingMessage) => void), callback?: (res: http.IncomingMessage) => void): ClientRequest;
19
+ export declare function get(urlOrOptions: string | URL | http.RequestOptions, optionsOrCallback?: http.RequestOptions | ((res: http.IncomingMessage) => void), callback?: (res: http.IncomingMessage) => void): ClientRequest;
20
+ export declare class Agent extends http.Agent {
21
+ constructor(options?: any);
22
+ }
23
+ export declare const globalAgent: Agent;
24
+ export { IncomingMessage };
package/lib/https.js ADDED
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.IncomingMessage = exports.globalAgent = exports.Agent = exports.ClientRequest = exports.Server = void 0;
37
+ exports.createServer = createServer;
38
+ exports.request = request;
39
+ exports.get = get;
40
+ const http = __importStar(require("./http"));
41
+ const tls = __importStar(require("./tls"));
42
+ const http_1 = require("./http");
43
+ Object.defineProperty(exports, "IncomingMessage", { enumerable: true, get: function () { return http_1.IncomingMessage; } });
44
+ // ========== Server ==========
45
+ class Server extends tls.Server {
46
+ constructor(options, requestListener) {
47
+ if (typeof options === 'function') {
48
+ requestListener = options;
49
+ options = {};
50
+ }
51
+ super(options);
52
+ this._httpConnections = new Set();
53
+ this.maxHeaderSize = 16384;
54
+ this.maxRequestsPerSocket = 0;
55
+ this.headersTimeout = 60000;
56
+ this.requestTimeout = 300000;
57
+ this.keepAliveTimeout = 5000;
58
+ if (requestListener) {
59
+ this.on('request', requestListener);
60
+ }
61
+ // Initialize HTTP connection setup for secure connections
62
+ this.on('secureConnection', (socket) => {
63
+ // @ts-ignore - access internal http logic
64
+ http.Server.prototype._setupHttpConnection.call(this, socket);
65
+ });
66
+ }
67
+ setTimeout(ms, callback) {
68
+ // @ts-ignore - access netServer via super's internal or cast
69
+ this._netServer.setTimeout(ms, callback);
70
+ return this;
71
+ }
72
+ }
73
+ exports.Server = Server;
74
+ function createServer(options, requestListener) {
75
+ return new Server(options, requestListener);
76
+ }
77
+ // ========== ClientRequest ==========
78
+ class ClientRequest extends http.ClientRequest {
79
+ constructor(options, callback) {
80
+ if (typeof options === 'string') {
81
+ options = new URL(options);
82
+ }
83
+ if (options instanceof URL) {
84
+ options = {
85
+ protocol: options.protocol,
86
+ hostname: options.hostname,
87
+ path: options.pathname + options.search,
88
+ port: options.port ? parseInt(options.port) : 443
89
+ };
90
+ }
91
+ options.protocol = 'https:';
92
+ super(options, callback);
93
+ }
94
+ }
95
+ exports.ClientRequest = ClientRequest;
96
+ function request(urlOrOptions, optionsOrCallback, callback) {
97
+ let opts = {};
98
+ let cb = callback;
99
+ if (typeof urlOrOptions === 'string') {
100
+ const url = new URL(urlOrOptions);
101
+ opts = {
102
+ protocol: url.protocol,
103
+ hostname: url.hostname,
104
+ path: url.pathname + url.search,
105
+ port: url.port ? parseInt(url.port) : 443
106
+ };
107
+ }
108
+ else if (urlOrOptions instanceof URL) {
109
+ opts = {
110
+ protocol: urlOrOptions.protocol,
111
+ hostname: urlOrOptions.hostname,
112
+ path: urlOrOptions.pathname + urlOrOptions.search,
113
+ port: urlOrOptions.port ? parseInt(urlOrOptions.port) : 443
114
+ };
115
+ }
116
+ else {
117
+ opts = { ...urlOrOptions };
118
+ }
119
+ if (typeof optionsOrCallback === 'function') {
120
+ cb = optionsOrCallback;
121
+ }
122
+ else if (optionsOrCallback) {
123
+ opts = { ...opts, ...optionsOrCallback };
124
+ }
125
+ opts.protocol = 'https:';
126
+ return new ClientRequest(opts, cb);
127
+ }
128
+ function get(urlOrOptions, optionsOrCallback, callback) {
129
+ const req = request(urlOrOptions, optionsOrCallback, callback);
130
+ req.end();
131
+ return req;
132
+ }
133
+ // ========== Agent ==========
134
+ class Agent extends http.Agent {
135
+ constructor(options) {
136
+ super(options);
137
+ }
138
+ }
139
+ exports.Agent = Agent;
140
+ exports.globalAgent = new Agent({
141
+ keepAlive: true,
142
+ scheduling: 'lifo',
143
+ timeout: 5000,
144
+ });
package/lib/index.d.ts CHANGED
@@ -4,6 +4,7 @@ import type { NetSocketDriver, NetConfig } from './Net.nitro';
4
4
  declare function isIP(input: string): number;
5
5
  declare function isIPv4(input: string): boolean;
6
6
  declare function isIPv6(input: string): boolean;
7
+ declare function isVerbose(): boolean;
7
8
  declare function setVerbose(enabled: boolean): void;
8
9
  declare function getDefaultAutoSelectFamily(): number;
9
10
  declare function setDefaultAutoSelectFamily(family: number): void;
@@ -23,24 +24,56 @@ declare function setDefaultAutoSelectFamily(family: number): void;
23
24
  * ```
24
25
  */
25
26
  declare function initWithConfig(config: NetConfig): void;
27
+ export interface SocketAddressOptions {
28
+ address?: string;
29
+ family?: 'ipv4' | 'ipv6';
30
+ port?: number;
31
+ flowlabel?: number;
32
+ }
26
33
  export declare class SocketAddress {
27
34
  readonly address: string;
28
35
  readonly family: 'ipv4' | 'ipv6';
29
36
  readonly port: number;
30
37
  readonly flowlabel: number;
31
- constructor(options: {
32
- address: string;
33
- family?: 'ipv4' | 'ipv6';
34
- port: number;
35
- flowlabel?: number;
36
- });
38
+ constructor(options?: SocketAddressOptions);
39
+ /**
40
+ * Attempts to parse a string containing a socket address.
41
+ * Returns a SocketAddress if successful, or undefined if not.
42
+ *
43
+ * Supported formats:
44
+ * - `ip:port` (e.g., `127.0.0.1:8080`, `[::1]:8080`)
45
+ * - `ip` only (port defaults to 0)
46
+ */
47
+ static parse(input: string): SocketAddress | undefined;
48
+ }
49
+ export interface BlockListRule {
50
+ type: 'address' | 'range' | 'subnet';
51
+ address?: string;
52
+ start?: string;
53
+ end?: string;
54
+ prefix?: number;
55
+ family: 'ipv4' | 'ipv6';
37
56
  }
38
57
  export declare class BlockList {
39
58
  private _rules;
59
+ /** Returns an array of rules added to the blocklist. */
60
+ get rules(): BlockListRule[];
40
61
  addAddress(address: string, family?: 'ipv4' | 'ipv6'): void;
41
62
  addRange(start: string, end: string, family?: 'ipv4' | 'ipv6'): void;
42
63
  addSubnet(net: string, prefix: number, family?: 'ipv4' | 'ipv6'): void;
43
64
  check(address: string, family?: 'ipv4' | 'ipv6'): boolean;
65
+ /**
66
+ * Serializes the BlockList to a JSON-compatible format.
67
+ */
68
+ toJSON(): BlockListRule[];
69
+ /**
70
+ * Creates a BlockList from a JSON array of rules.
71
+ */
72
+ static fromJSON(json: BlockListRule[]): BlockList;
73
+ /**
74
+ * Checks if a given value is a BlockList instance.
75
+ */
76
+ static isBlockList(value: unknown): value is BlockList;
44
77
  }
45
78
  export interface SocketOptions extends DuplexOptions {
46
79
  fd?: any;
@@ -65,6 +98,7 @@ export declare class Socket extends Duplex {
65
98
  bytesWritten: number;
66
99
  autoSelectFamilyAttemptedAddresses: string[];
67
100
  private _autoSelectFamily;
101
+ private _timeout;
68
102
  get localFamily(): string;
69
103
  get readyState(): string;
70
104
  get pending(): boolean;
@@ -110,7 +144,7 @@ export declare class Socket extends Duplex {
110
144
  * Use 'utf8', 'hex', etc.
111
145
  */
112
146
  setEncoding(encoding: BufferEncoding): this;
113
- get timeout(): number | undefined;
147
+ get timeout(): number;
114
148
  get bufferSize(): number;
115
149
  resetAndDestroy(): this;
116
150
  }
@@ -142,7 +176,9 @@ export declare function createConnection(options: any, connectionListener?: () =
142
176
  export declare const connect: typeof createConnection;
143
177
  export declare function createServer(options?: any, connectionListener?: (socket: Socket) => void): Server;
144
178
  export * as tls from './tls';
145
- export { isIP, isIPv4, isIPv6, getDefaultAutoSelectFamily, setDefaultAutoSelectFamily, setVerbose, initWithConfig, };
179
+ export * as http from './http';
180
+ export * as https from './https';
181
+ export { isIP, isIPv4, isIPv6, getDefaultAutoSelectFamily, setDefaultAutoSelectFamily, isVerbose, setVerbose, initWithConfig, };
146
182
  export type { NetConfig };
147
183
  declare const _default: {
148
184
  Socket: typeof Socket;
@@ -159,5 +195,7 @@ declare const _default: {
159
195
  setDefaultAutoSelectFamily: typeof setDefaultAutoSelectFamily;
160
196
  setVerbose: typeof setVerbose;
161
197
  initWithConfig: typeof initWithConfig;
198
+ http: any;
199
+ https: any;
162
200
  };
163
201
  export default _default;
package/lib/index.js CHANGED
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.tls = exports.connect = exports.Server = exports.Socket = exports.BlockList = exports.SocketAddress = void 0;
36
+ exports.https = exports.http = exports.tls = exports.connect = exports.Server = exports.Socket = exports.BlockList = exports.SocketAddress = void 0;
37
37
  exports.createConnection = createConnection;
38
38
  exports.createServer = createServer;
39
39
  exports.isIP = isIP;
@@ -41,6 +41,7 @@ exports.isIPv4 = isIPv4;
41
41
  exports.isIPv6 = isIPv6;
42
42
  exports.getDefaultAutoSelectFamily = getDefaultAutoSelectFamily;
43
43
  exports.setDefaultAutoSelectFamily = setDefaultAutoSelectFamily;
44
+ exports.isVerbose = isVerbose;
44
45
  exports.setVerbose = setVerbose;
45
46
  exports.initWithConfig = initWithConfig;
46
47
  const readable_stream_1 = require("readable-stream");
@@ -74,14 +75,18 @@ function isIPv6(input) {
74
75
  let _autoSelectFamilyDefault = 4; // Node default is usually 4/6 independent, but we mock it.
75
76
  let _isVerbose = false;
76
77
  let _isInitialized = false;
77
- function debugLog(message) {
78
- if (_isVerbose) {
79
- console.log(`[NET DEBUG] ${message}`);
80
- }
78
+ function isVerbose() {
79
+ return _isVerbose;
81
80
  }
82
81
  function setVerbose(enabled) {
83
82
  _isVerbose = enabled;
84
83
  }
84
+ function debugLog(message) {
85
+ if (_isVerbose) {
86
+ const timestamp = new Date().toISOString().split('T')[1].split('Z')[0];
87
+ console.log(`[NET DEBUG ${timestamp}] ${message}`);
88
+ }
89
+ }
85
90
  function getDefaultAutoSelectFamily() {
86
91
  return _autoSelectFamilyDefault;
87
92
  }
@@ -116,29 +121,84 @@ function ensureInitialized() {
116
121
  */
117
122
  function initWithConfig(config) {
118
123
  _isInitialized = true;
124
+ if (config.debug !== undefined) {
125
+ setVerbose(config.debug);
126
+ }
119
127
  Driver_1.Driver.initWithConfig(config);
120
128
  }
121
- // -----------------------------------------------------------------------------
122
- // SocketAddress
123
- // -----------------------------------------------------------------------------
124
- // SocketAddress
125
- // -----------------------------------------------------------------------------
126
129
  class SocketAddress {
127
- constructor(options) {
128
- this.address = options.address;
129
- this.family = options.family || (isIPv6(options.address) ? 'ipv6' : 'ipv4');
130
- this.port = options.port;
131
- this.flowlabel = options.flowlabel || 0;
130
+ constructor(options = {}) {
131
+ this.address = options.address ?? (options.family === 'ipv6' ? '::' : '127.0.0.1');
132
+ this.family = options.family || (isIPv6(this.address) ? 'ipv6' : 'ipv4');
133
+ this.port = options.port ?? 0;
134
+ this.flowlabel = options.flowlabel ?? 0;
135
+ }
136
+ /**
137
+ * Attempts to parse a string containing a socket address.
138
+ * Returns a SocketAddress if successful, or undefined if not.
139
+ *
140
+ * Supported formats:
141
+ * - `ip:port` (e.g., `127.0.0.1:8080`, `[::1]:8080`)
142
+ * - `ip` only (port defaults to 0)
143
+ */
144
+ static parse(input) {
145
+ if (!input || typeof input !== 'string')
146
+ return undefined;
147
+ let address;
148
+ let port = 0;
149
+ // Handle IPv6 bracket notation: [::1]:port
150
+ const ipv6Match = input.match(/^\[([^\]]+)\]:?(\d*)$/);
151
+ if (ipv6Match) {
152
+ address = ipv6Match[1];
153
+ port = ipv6Match[2] ? parseInt(ipv6Match[2], 10) : 0;
154
+ if (!isIPv6(address))
155
+ return undefined;
156
+ return new SocketAddress({ address, port, family: 'ipv6' });
157
+ }
158
+ // Handle IPv4 or IPv6 without brackets
159
+ const lastColon = input.lastIndexOf(':');
160
+ if (lastColon === -1) {
161
+ // No port, just IP
162
+ address = input;
163
+ }
164
+ else {
165
+ // Determine if the colon is a port separator or part of IPv6
166
+ const potentialPort = input.slice(lastColon + 1);
167
+ const potentialAddr = input.slice(0, lastColon);
168
+ if (/^\d+$/.test(potentialPort) && (isIPv4(potentialAddr) || isIPv6(potentialAddr))) {
169
+ address = potentialAddr;
170
+ port = parseInt(potentialPort, 10);
171
+ }
172
+ else {
173
+ // It's an IPv6 address without port
174
+ address = input;
175
+ }
176
+ }
177
+ const family = isIPv6(address) ? 'ipv6' : (isIPv4(address) ? 'ipv4' : undefined);
178
+ if (!family)
179
+ return undefined;
180
+ return new SocketAddress({ address, port, family });
132
181
  }
133
182
  }
134
183
  exports.SocketAddress = SocketAddress;
135
- // -----------------------------------------------------------------------------
136
- // BlockList
137
- // -----------------------------------------------------------------------------
138
184
  class BlockList {
139
185
  constructor() {
140
186
  this._rules = [];
141
187
  }
188
+ /** Returns an array of rules added to the blocklist. */
189
+ get rules() {
190
+ return this._rules.map(r => {
191
+ if (r.type === 'address') {
192
+ return { type: 'address', address: r.data.address, family: r.data.family };
193
+ }
194
+ else if (r.type === 'range') {
195
+ return { type: 'range', start: r.data.start, end: r.data.end, family: r.data.family };
196
+ }
197
+ else {
198
+ return { type: 'subnet', address: r.data.net, prefix: r.data.prefix, family: r.data.family };
199
+ }
200
+ });
201
+ }
142
202
  addAddress(address, family) {
143
203
  this._rules.push({ type: 'address', data: { address, family: family || (isIPv6(address) ? 'ipv6' : 'ipv4') } });
144
204
  }
@@ -173,6 +233,36 @@ class BlockList {
173
233
  }
174
234
  return false;
175
235
  }
236
+ /**
237
+ * Serializes the BlockList to a JSON-compatible format.
238
+ */
239
+ toJSON() {
240
+ return this.rules;
241
+ }
242
+ /**
243
+ * Creates a BlockList from a JSON array of rules.
244
+ */
245
+ static fromJSON(json) {
246
+ const list = new BlockList();
247
+ for (const rule of json) {
248
+ if (rule.type === 'address' && rule.address) {
249
+ list.addAddress(rule.address, rule.family);
250
+ }
251
+ else if (rule.type === 'range' && rule.start && rule.end) {
252
+ list.addRange(rule.start, rule.end, rule.family);
253
+ }
254
+ else if (rule.type === 'subnet' && rule.address && rule.prefix !== undefined) {
255
+ list.addSubnet(rule.address, rule.prefix, rule.family);
256
+ }
257
+ }
258
+ return list;
259
+ }
260
+ /**
261
+ * Checks if a given value is a BlockList instance.
262
+ */
263
+ static isBlockList(value) {
264
+ return value instanceof BlockList;
265
+ }
176
266
  }
177
267
  exports.BlockList = BlockList;
178
268
  function ipv4ToLong(ip) {
@@ -205,7 +295,9 @@ class Socket extends readable_stream_1.Duplex {
205
295
  super({
206
296
  allowHalfOpen: options?.allowHalfOpen ?? false,
207
297
  readable: options?.readable ?? true,
208
- writable: options?.writable ?? true
298
+ writable: options?.writable ?? true,
299
+ // @ts-ignore
300
+ autoDestroy: false
209
301
  });
210
302
  this.connecting = false; // Changed from private _connecting
211
303
  this._connected = false;
@@ -214,11 +306,14 @@ class Socket extends readable_stream_1.Duplex {
214
306
  this.bytesWritten = 0;
215
307
  this.autoSelectFamilyAttemptedAddresses = [];
216
308
  this._autoSelectFamily = false;
309
+ this._timeout = 0;
217
310
  if (options?.socketDriver) {
218
311
  // Wrapping existing socket (from Server)
219
312
  this._driver = options.socketDriver;
220
313
  this._connected = true;
221
314
  this._setupEvents();
315
+ // Enable noDelay by default
316
+ this._driver.setNoDelay(true);
222
317
  // Resume the socket since it starts paused on server-accept
223
318
  this.resume();
224
319
  // Emit connect for server-side socket? No, it's already connected.
@@ -228,8 +323,10 @@ class Socket extends readable_stream_1.Duplex {
228
323
  ensureInitialized();
229
324
  this._driver = Driver_1.Driver.createSocket();
230
325
  this._setupEvents();
231
- // Also resume client socket initially so it's ready to receive
232
- this.resume();
326
+ // Enable noDelay by default to match Node.js and reduce latency for small writes
327
+ this._driver.setNoDelay(true);
328
+ // Do NOT resume here - socket is not connected yet!
329
+ // resume() will be called after 'connect' event in _connect()
233
330
  }
234
331
  this.on('finish', () => {
235
332
  // Writable side finished
@@ -268,6 +365,8 @@ class Socket extends readable_stream_1.Duplex {
268
365
  this.connecting = false;
269
366
  this._connected = true;
270
367
  this._updateAddresses();
368
+ // Now that we're connected, start receiving data
369
+ this.resume();
271
370
  this.emit('connect');
272
371
  this.emit('ready');
273
372
  break;
@@ -407,6 +506,7 @@ class Socket extends readable_stream_1.Duplex {
407
506
  else {
408
507
  this._autoSelectFamily = true;
409
508
  }
509
+ debugLog(`Socket.connect: target=${host}:${port}, autoSelectFamily=${this._autoSelectFamily}`);
410
510
  return this._connect(port, host, connectionListener, options.signal);
411
511
  }
412
512
  _connect(port, host, listener, signal) {
@@ -428,6 +528,7 @@ class Socket extends readable_stream_1.Duplex {
428
528
  this.once('connect', () => signal.removeEventListener('abort', abortHandler));
429
529
  this.once('close', () => signal.removeEventListener('abort', abortHandler));
430
530
  }
531
+ debugLog(`Socket._connect: Calling driver.connect(${host}, ${port})`);
431
532
  this._driver?.connect(host, port);
432
533
  return this;
433
534
  }
@@ -499,6 +600,7 @@ class Socket extends readable_stream_1.Duplex {
499
600
  }
500
601
  // Standard net.Socket methods
501
602
  setTimeout(msecs, callback) {
603
+ this._timeout = msecs;
502
604
  if (this._driver) {
503
605
  this._driver.setTimeout(msecs);
504
606
  }
@@ -521,12 +623,13 @@ class Socket extends readable_stream_1.Duplex {
521
623
  * Resume reading after a call to pause().
522
624
  */
523
625
  resume() {
524
- const id = this._driver?.id;
525
- debugLog(`Socket.resume() called, id: ${id}`);
626
+ const driver = this._driver;
627
+ const id = driver?.id;
628
+ debugLog(`Socket.resume() called, id: ${id === undefined ? 'none' : id}, destroyed: ${this.destroyed}`);
526
629
  super.resume();
527
- if (this._driver) {
630
+ if (driver) {
528
631
  debugLog(`Socket.resume() calling driver.resume(), id: ${id}`);
529
- this._driver.resume();
632
+ driver.resume();
530
633
  }
531
634
  return this;
532
635
  }
@@ -552,7 +655,7 @@ class Socket extends readable_stream_1.Duplex {
552
655
  return this;
553
656
  }
554
657
  get timeout() {
555
- return undefined; // Not tracked strictly as a property yet
658
+ return this._timeout;
556
659
  }
557
660
  get bufferSize() {
558
661
  return 0; // Deprecated but often accessed
@@ -804,6 +907,8 @@ function createServer(options, connectionListener) {
804
907
  return new Server(options, connectionListener);
805
908
  }
806
909
  exports.tls = __importStar(require("./tls"));
910
+ exports.http = __importStar(require("./http"));
911
+ exports.https = __importStar(require("./https"));
807
912
  exports.default = {
808
913
  Socket,
809
914
  Server,
@@ -819,4 +924,6 @@ exports.default = {
819
924
  setDefaultAutoSelectFamily,
820
925
  setVerbose,
821
926
  initWithConfig,
927
+ http: require('./http'),
928
+ https: require('./https'),
822
929
  };
package/lib/tls.d.ts CHANGED
@@ -26,6 +26,13 @@ export interface ConnectionOptions extends SocketOptions {
26
26
  pfx?: string | ArrayBuffer;
27
27
  passphrase?: string;
28
28
  keylog?: boolean;
29
+ /**
30
+ * Custom hostname verification function.
31
+ * If provided, it will be called after the TLS handshake to verify the peer certificate.
32
+ * Return `undefined` if valid, or an `Error` if invalid.
33
+ * If not provided, the default `checkServerIdentity` is used.
34
+ */
35
+ checkServerIdentity?: (hostname: string, cert: PeerCertificate) => Error | undefined;
29
36
  }
30
37
  export interface SecureContextOptions {
31
38
  pfx?: string | ArrayBuffer;
@@ -70,6 +77,20 @@ export declare class TLSSocket extends Socket {
70
77
  getSharedSigalgs(): string | undefined;
71
78
  renegotiate(options: any, callback: (err: Error | null) => void): boolean;
72
79
  disableRenegotiation(): void;
80
+ /**
81
+ * Enables trace output for this socket.
82
+ */
83
+ enableTrace(): void;
84
+ /**
85
+ * Exports keying material for use by external protocols.
86
+ *
87
+ * @param length The number of bytes to return.
88
+ * @param label A label identifying the keying material.
89
+ * @param context An optional context.
90
+ * @returns Buffer containing keying material.
91
+ * @throws Error if export fails (e.g., TLS not connected).
92
+ */
93
+ exportKeyingMaterial(length: number, label: string, context?: Buffer): Buffer;
73
94
  constructor(socket: Socket, options?: ConnectionOptions);
74
95
  constructor(options: ConnectionOptions);
75
96
  connect(options: any, connectionListener?: () => void): this;