react-native-nitro-net 0.1.5

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 (83) hide show
  1. package/README.md +133 -0
  2. package/android/CMakeLists.txt +29 -0
  3. package/android/OnLoad.cpp +6 -0
  4. package/android/build.gradle +72 -0
  5. package/android/gradle.properties +6 -0
  6. package/android/libs/arm64-v8a/librust_c_net.so +0 -0
  7. package/android/libs/armeabi-v7a/librust_c_net.so +0 -0
  8. package/android/libs/x86/librust_c_net.so +0 -0
  9. package/android/libs/x86_64/librust_c_net.so +0 -0
  10. package/android/src/main/AndroidManifest.xml +3 -0
  11. package/android/src/main/java/com/margelo/nitro/net/NitroNetPackage.java +32 -0
  12. package/cpp/HybridNetDriver.cpp +5 -0
  13. package/cpp/HybridNetDriver.hpp +42 -0
  14. package/cpp/HybridNetServerDriver.cpp +5 -0
  15. package/cpp/HybridNetServerDriver.hpp +114 -0
  16. package/cpp/HybridNetSocketDriver.cpp +6 -0
  17. package/cpp/HybridNetSocketDriver.hpp +132 -0
  18. package/cpp/NetBindings.hpp +68 -0
  19. package/cpp/NetManager.hpp +160 -0
  20. package/ios/Frameworks/RustCNet.xcframework/Info.plist +44 -0
  21. package/ios/Frameworks/RustCNet.xcframework/ios-arm64/RustCNet.framework/Info.plist +20 -0
  22. package/ios/Frameworks/RustCNet.xcframework/ios-arm64/RustCNet.framework/RustCNet +0 -0
  23. package/ios/Frameworks/RustCNet.xcframework/ios-arm64_x86_64-simulator/RustCNet.framework/Info.plist +20 -0
  24. package/ios/Frameworks/RustCNet.xcframework/ios-arm64_x86_64-simulator/RustCNet.framework/RustCNet +0 -0
  25. package/lib/Driver.d.ts +2 -0
  26. package/lib/Driver.js +5 -0
  27. package/lib/Net.nitro.d.ts +85 -0
  28. package/lib/Net.nitro.js +21 -0
  29. package/lib/index.d.ts +162 -0
  30. package/lib/index.js +781 -0
  31. package/nitrogen/generated/.gitattributes +1 -0
  32. package/nitrogen/generated/android/RustCNet+autolinking.cmake +86 -0
  33. package/nitrogen/generated/android/RustCNet+autolinking.gradle +27 -0
  34. package/nitrogen/generated/android/RustCNetOnLoad.cpp +51 -0
  35. package/nitrogen/generated/android/RustCNetOnLoad.hpp +25 -0
  36. package/nitrogen/generated/android/c++/JFunc_void_double_std__shared_ptr_ArrayBuffer_.hpp +77 -0
  37. package/nitrogen/generated/android/c++/JHybridNetDriverSpec.cpp +74 -0
  38. package/nitrogen/generated/android/c++/JHybridNetDriverSpec.hpp +67 -0
  39. package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.cpp +99 -0
  40. package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.hpp +72 -0
  41. package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.cpp +127 -0
  42. package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.hpp +79 -0
  43. package/nitrogen/generated/android/c++/JNetConfig.hpp +57 -0
  44. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/Func_void_double_std__shared_ptr_ArrayBuffer_.kt +80 -0
  45. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetDriverSpec.kt +65 -0
  46. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetServerDriverSpec.kt +92 -0
  47. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetSocketDriverSpec.kt +122 -0
  48. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/NetConfig.kt +38 -0
  49. package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/RustCNetOnLoad.kt +35 -0
  50. package/nitrogen/generated/ios/RustCNet+autolinking.rb +60 -0
  51. package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Bridge.cpp +75 -0
  52. package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Bridge.hpp +186 -0
  53. package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Umbrella.hpp +60 -0
  54. package/nitrogen/generated/ios/RustCNetAutolinking.mm +35 -0
  55. package/nitrogen/generated/ios/RustCNetAutolinking.swift +12 -0
  56. package/nitrogen/generated/ios/c++/HybridNetDriverSpecSwift.cpp +11 -0
  57. package/nitrogen/generated/ios/c++/HybridNetDriverSpecSwift.hpp +100 -0
  58. package/nitrogen/generated/ios/c++/HybridNetServerDriverSpecSwift.cpp +11 -0
  59. package/nitrogen/generated/ios/c++/HybridNetServerDriverSpecSwift.hpp +117 -0
  60. package/nitrogen/generated/ios/c++/HybridNetSocketDriverSpecSwift.cpp +11 -0
  61. package/nitrogen/generated/ios/c++/HybridNetSocketDriverSpecSwift.hpp +163 -0
  62. package/nitrogen/generated/ios/swift/Func_void_double_std__shared_ptr_ArrayBuffer_.swift +47 -0
  63. package/nitrogen/generated/ios/swift/HybridNetDriverSpec.swift +58 -0
  64. package/nitrogen/generated/ios/swift/HybridNetDriverSpec_cxx.swift +167 -0
  65. package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec.swift +61 -0
  66. package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec_cxx.swift +217 -0
  67. package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec.swift +69 -0
  68. package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec_cxx.swift +288 -0
  69. package/nitrogen/generated/ios/swift/NetConfig.swift +36 -0
  70. package/nitrogen/generated/shared/c++/HybridNetDriverSpec.cpp +23 -0
  71. package/nitrogen/generated/shared/c++/HybridNetDriverSpec.hpp +74 -0
  72. package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.cpp +29 -0
  73. package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.hpp +72 -0
  74. package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.cpp +36 -0
  75. package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.hpp +78 -0
  76. package/nitrogen/generated/shared/c++/HybridNitroBufferSpec.cpp +32 -0
  77. package/nitrogen/generated/shared/c++/HybridNitroBufferSpec.hpp +74 -0
  78. package/nitrogen/generated/shared/c++/NetConfig.hpp +83 -0
  79. package/package.json +59 -0
  80. package/react-native-nitro-net.podspec +47 -0
  81. package/src/Driver.ts +4 -0
  82. package/src/Net.nitro.ts +85 -0
  83. package/src/index.ts +870 -0
package/lib/index.js ADDED
@@ -0,0 +1,781 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.connect = exports.Server = exports.Socket = exports.BlockList = exports.SocketAddress = void 0;
4
+ exports.createConnection = createConnection;
5
+ exports.createServer = createServer;
6
+ exports.isIP = isIP;
7
+ exports.isIPv4 = isIPv4;
8
+ exports.isIPv6 = isIPv6;
9
+ exports.getDefaultAutoSelectFamily = getDefaultAutoSelectFamily;
10
+ exports.setDefaultAutoSelectFamily = setDefaultAutoSelectFamily;
11
+ exports.setVerbose = setVerbose;
12
+ exports.initWithConfig = initWithConfig;
13
+ const readable_stream_1 = require("readable-stream");
14
+ const eventemitter3_1 = require("eventemitter3");
15
+ const Driver_1 = require("./Driver");
16
+ const Net_nitro_1 = require("./Net.nitro");
17
+ const react_native_nitro_buffer_1 = require("react-native-nitro-buffer");
18
+ // -----------------------------------------------------------------------------
19
+ // Utils
20
+ // -----------------------------------------------------------------------------
21
+ function isIP(input) {
22
+ // Simple regex check
23
+ if (/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/.test(input))
24
+ return 4;
25
+ // Basic IPv6 check allowing double colons
26
+ if (/^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/.test(input))
27
+ return 6;
28
+ if (/^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$/.test(input))
29
+ return 6;
30
+ return 0;
31
+ }
32
+ function isIPv4(input) {
33
+ return isIP(input) === 4;
34
+ }
35
+ function isIPv6(input) {
36
+ return isIP(input) === 6;
37
+ }
38
+ // -----------------------------------------------------------------------------
39
+ // Global Configuration
40
+ // -----------------------------------------------------------------------------
41
+ let _autoSelectFamilyDefault = 4; // Node default is usually 4/6 independent, but we mock it.
42
+ let _isVerbose = false;
43
+ let _isInitialized = false;
44
+ function debugLog(message) {
45
+ if (_isVerbose) {
46
+ console.log(`[NET DEBUG] ${message}`);
47
+ }
48
+ }
49
+ function setVerbose(enabled) {
50
+ _isVerbose = enabled;
51
+ }
52
+ function getDefaultAutoSelectFamily() {
53
+ return _autoSelectFamilyDefault;
54
+ }
55
+ function setDefaultAutoSelectFamily(family) {
56
+ if (family !== 4 && family !== 6)
57
+ throw new Error('Family must be 4 or 6');
58
+ _autoSelectFamilyDefault = family;
59
+ }
60
+ /**
61
+ * Ensures that the network module is initialized.
62
+ * If initWithConfig hasn't been called, it will be called with default options.
63
+ */
64
+ function ensureInitialized() {
65
+ if (!_isInitialized) {
66
+ initWithConfig({});
67
+ }
68
+ }
69
+ /**
70
+ * Initialize the network module with custom configuration.
71
+ * Must be called before any socket/server operations, or the config will be ignored.
72
+ *
73
+ * @param config Configuration options
74
+ * @param config.workerThreads Number of worker threads (0 = use CPU core count)
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * import { initWithConfig } from 'react-native-nitro-net';
79
+ *
80
+ * // Initialize with 4 worker threads
81
+ * initWithConfig({ workerThreads: 4 });
82
+ * ```
83
+ */
84
+ function initWithConfig(config) {
85
+ _isInitialized = true;
86
+ Driver_1.Driver.initWithConfig(config);
87
+ }
88
+ // -----------------------------------------------------------------------------
89
+ // SocketAddress
90
+ // -----------------------------------------------------------------------------
91
+ // SocketAddress
92
+ // -----------------------------------------------------------------------------
93
+ class SocketAddress {
94
+ constructor(options) {
95
+ this.address = options.address;
96
+ this.family = options.family || (isIPv6(options.address) ? 'ipv6' : 'ipv4');
97
+ this.port = options.port;
98
+ this.flowlabel = options.flowlabel || 0;
99
+ }
100
+ }
101
+ exports.SocketAddress = SocketAddress;
102
+ // -----------------------------------------------------------------------------
103
+ // BlockList
104
+ // -----------------------------------------------------------------------------
105
+ class BlockList {
106
+ constructor() {
107
+ this._rules = [];
108
+ }
109
+ addAddress(address, family) {
110
+ this._rules.push({ type: 'address', data: { address, family: family || (isIPv6(address) ? 'ipv6' : 'ipv4') } });
111
+ }
112
+ addRange(start, end, family) {
113
+ this._rules.push({ type: 'range', data: { start, end, family: family || (isIPv6(start) ? 'ipv6' : 'ipv4') } });
114
+ }
115
+ addSubnet(net, prefix, family) {
116
+ this._rules.push({ type: 'subnet', data: { net, prefix, family: family || (isIPv6(net) ? 'ipv6' : 'ipv4') } });
117
+ }
118
+ check(address, family) {
119
+ const addrFamily = family || (isIPv6(address) ? 'ipv6' : 'ipv4');
120
+ const addrNum = addrFamily === 'ipv4' ? ipv4ToLong(address) : null;
121
+ for (const rule of this._rules) {
122
+ if (rule.data.family !== addrFamily)
123
+ continue;
124
+ if (rule.type === 'address') {
125
+ if (rule.data.address === address)
126
+ return true;
127
+ }
128
+ else if (rule.type === 'range' && addrNum !== null) {
129
+ const start = ipv4ToLong(rule.data.start);
130
+ const end = ipv4ToLong(rule.data.end);
131
+ if (addrNum >= start && addrNum <= end)
132
+ return true;
133
+ }
134
+ else if (rule.type === 'subnet' && addrNum !== null) {
135
+ const net = ipv4ToLong(rule.data.net);
136
+ const mask = ~(Math.pow(2, 32 - rule.data.prefix) - 1);
137
+ if ((addrNum & mask) === (net & mask))
138
+ return true;
139
+ }
140
+ }
141
+ return false;
142
+ }
143
+ }
144
+ exports.BlockList = BlockList;
145
+ function ipv4ToLong(ip) {
146
+ return ip.split('.').reduce((acc, octet) => (acc << 8) + parseInt(octet, 10), 0) >>> 0;
147
+ }
148
+ class Socket extends readable_stream_1.Duplex {
149
+ get localFamily() {
150
+ return this.localAddress && this.localAddress.includes(':') ? 'IPv6' : 'IPv4';
151
+ }
152
+ get readyState() {
153
+ if (this.connecting)
154
+ return 'opening';
155
+ if (this._connected) {
156
+ // @ts-ignore
157
+ if (this.writable && this.readable)
158
+ return 'open';
159
+ // @ts-ignore
160
+ if (this.writable)
161
+ return 'writeOnly';
162
+ // @ts-ignore
163
+ if (this.readable)
164
+ return 'readOnly';
165
+ }
166
+ return 'closed';
167
+ }
168
+ get pending() {
169
+ return this.connecting;
170
+ }
171
+ constructor(options) {
172
+ super({
173
+ allowHalfOpen: options?.allowHalfOpen ?? false,
174
+ readable: options?.readable ?? true,
175
+ writable: options?.writable ?? true
176
+ });
177
+ this.connecting = false; // Changed from private _connecting
178
+ this._connected = false;
179
+ this._hadError = false; // Added
180
+ this.bytesRead = 0;
181
+ this.bytesWritten = 0;
182
+ this.autoSelectFamilyAttemptedAddresses = [];
183
+ this._autoSelectFamily = false;
184
+ if (options?.socketDriver) {
185
+ // Wrapping existing socket (from Server)
186
+ this._driver = options.socketDriver;
187
+ this._connected = true;
188
+ this._setupEvents();
189
+ // Resume the socket since it starts paused on server-accept
190
+ this.resume();
191
+ // Emit connect for server-side socket? No, it's already connected.
192
+ }
193
+ else {
194
+ // New client socket
195
+ ensureInitialized();
196
+ this._driver = Driver_1.Driver.createSocket();
197
+ this._setupEvents();
198
+ // Also resume client socket initially so it's ready to receive
199
+ this.resume();
200
+ }
201
+ this.on('finish', () => {
202
+ // Writable side finished
203
+ });
204
+ }
205
+ on(event, listener) {
206
+ if (event === 'connect' && this._connected) {
207
+ process.nextTick(listener);
208
+ return this;
209
+ }
210
+ const ret = super.on(event, listener);
211
+ if (event === 'data' && !this.isPaused() && this.readableFlowing !== true) {
212
+ debugLog(`Socket on('data'), flowing: ${this.readableFlowing}`);
213
+ this.resume();
214
+ }
215
+ return ret;
216
+ }
217
+ _setupEvents() {
218
+ if (!this._driver)
219
+ return;
220
+ const id = this._driver.id ?? this._driver._id;
221
+ this._driver.onEvent = (eventType, data) => {
222
+ if (eventType === 3) { // ERROR
223
+ const msg = new TextDecoder().decode(data);
224
+ debugLog(`Socket (id: ${id}) NATIVE ERROR: ${msg}`);
225
+ }
226
+ if (eventType === 9) { // DEBUG
227
+ const msg = new TextDecoder().decode(data);
228
+ debugLog(`Socket (id: ${id}) NATIVE DEBUG: ${msg}`);
229
+ return;
230
+ }
231
+ debugLog(`Socket (id: ${id}, localPort: ${this.localPort}) Event TYPE: ${eventType}, data len: ${data?.byteLength}`);
232
+ switch (eventType) {
233
+ case Net_nitro_1.NetSocketEvent.CONNECT:
234
+ this.connecting = false;
235
+ this._connected = true;
236
+ this._updateAddresses();
237
+ this.emit('connect');
238
+ this.emit('ready');
239
+ break;
240
+ case Net_nitro_1.NetSocketEvent.DATA:
241
+ debugLog(`Socket onEvent(DATA), len: ${data?.byteLength}, flowing: ${this.readableFlowing}`);
242
+ if (data && data.byteLength > 0) {
243
+ const buffer = react_native_nitro_buffer_1.Buffer.from(data);
244
+ this.bytesRead += buffer.length;
245
+ if (!this.push(buffer)) {
246
+ this.pause();
247
+ }
248
+ }
249
+ break;
250
+ case Net_nitro_1.NetSocketEvent.ERROR: {
251
+ this._hadError = true;
252
+ const errorMsg = data ? react_native_nitro_buffer_1.Buffer.from(data).toString() : 'Unknown socket error';
253
+ const error = new Error(errorMsg);
254
+ if (this.connecting && this._autoSelectFamily) {
255
+ // If we were connecting, this is a connection attempt failure
256
+ // We attempt to get the last attempted address if available
257
+ const lastAttempt = this.autoSelectFamilyAttemptedAddresses[this.autoSelectFamilyAttemptedAddresses.length - 1];
258
+ if (lastAttempt) {
259
+ const [ip, port] = lastAttempt.split(':'); // distinct if ipv6?
260
+ // Simple parsing for event emission
261
+ const family = ip.includes(':') ? 6 : 4;
262
+ this.emit('connectionAttemptFailed', ip, parseInt(port || '0', 10), family, error);
263
+ }
264
+ }
265
+ this.emit('error', error);
266
+ this.destroy();
267
+ break;
268
+ }
269
+ case Net_nitro_1.NetSocketEvent.CLOSE:
270
+ this._connected = false;
271
+ this.connecting = false;
272
+ this.push(null); // EOF
273
+ this.emit('close', this._hadError);
274
+ break;
275
+ case Net_nitro_1.NetSocketEvent.DRAIN:
276
+ this.emit('drain');
277
+ break;
278
+ case Net_nitro_1.NetSocketEvent.TIMEOUT:
279
+ if (this.connecting && this._autoSelectFamily) {
280
+ const lastAttempt = this.autoSelectFamilyAttemptedAddresses[this.autoSelectFamilyAttemptedAddresses.length - 1];
281
+ if (lastAttempt) {
282
+ const [ip, port] = lastAttempt.split(':');
283
+ const family = ip.includes(':') ? 6 : 4;
284
+ this.emit('connectionAttemptTimeout', ip, parseInt(port || '0', 10), family);
285
+ }
286
+ }
287
+ this.emit('timeout');
288
+ break;
289
+ case Net_nitro_1.NetSocketEvent.LOOKUP: {
290
+ if (data) {
291
+ const lookupStr = react_native_nitro_buffer_1.Buffer.from(data).toString();
292
+ const parts = lookupStr.split(',');
293
+ if (parts.length >= 2) {
294
+ const [ip, family] = parts;
295
+ this.remoteAddress = ip;
296
+ this.remoteFamily = family === '6' ? 'IPv6' : 'IPv4';
297
+ // Emit connectionAttempt
298
+ // We don't have the port in LOOKUP data usually, but we stored it in this.remotePort (dest)
299
+ // actually remotePort might not be set yet if we used _connect with port arg.
300
+ // But _connect sets this.remotePort = port.
301
+ const port = this.remotePort || 0;
302
+ const fam = family === '6' ? 6 : 4;
303
+ if (this._autoSelectFamily) {
304
+ this.emit('connectionAttempt', ip, port, fam);
305
+ }
306
+ this.autoSelectFamilyAttemptedAddresses.push(`${ip}:${port}`);
307
+ }
308
+ const host = parts.length > 2 ? parts[2] : undefined;
309
+ this.emit('lookup', null, parts[0], parts[1] ? parseInt(parts[1], 10) : undefined, host);
310
+ }
311
+ break;
312
+ }
313
+ }
314
+ };
315
+ }
316
+ _updateAddresses() {
317
+ try {
318
+ const local = this._driver?.getLocalAddress();
319
+ if (local) {
320
+ const parts = local.split(':');
321
+ if (parts.length >= 2) {
322
+ this.localPort = parseInt(parts[parts.length - 1], 10);
323
+ this.localAddress = parts.slice(0, parts.length - 1).join(':').replace(/[\[\]]/g, '');
324
+ }
325
+ }
326
+ const remote = this._driver?.getRemoteAddress();
327
+ if (remote) {
328
+ const parts = remote.split(':');
329
+ if (parts.length >= 2) {
330
+ this.remotePort = parseInt(parts[parts.length - 1], 10);
331
+ this.remoteAddress = parts.slice(0, parts.length - 1).join(':').replace(/[\[\]]/g, '');
332
+ this.remoteFamily = this.remoteAddress.includes(':') ? 'IPv6' : 'IPv4';
333
+ }
334
+ }
335
+ }
336
+ catch (e) {
337
+ // Ignore errors for now
338
+ }
339
+ }
340
+ address() {
341
+ if (!this.localAddress)
342
+ return null;
343
+ return {
344
+ port: this.localPort || 0,
345
+ family: this.localAddress.includes(':') ? 'IPv6' : 'IPv4',
346
+ address: this.localAddress
347
+ };
348
+ }
349
+ connect(options, connectionListener) {
350
+ if (typeof options === 'string') {
351
+ // Path?
352
+ if (isNaN(Number(options))) {
353
+ return this._connectUnix(options, connectionListener);
354
+ }
355
+ }
356
+ if (typeof options === 'number' || typeof options === 'string') {
357
+ const port = Number(options);
358
+ const host = (arguments.length > 1 && typeof arguments[1] === 'string') ? arguments[1] : 'localhost';
359
+ const cb = typeof arguments[1] === 'function' ? arguments[1] : connectionListener;
360
+ // Default: Node 20 defaults autoSelectFamily to true
361
+ this._autoSelectFamily = true;
362
+ return this._connect(port, host, cb || arguments[2]);
363
+ }
364
+ if (options.path) {
365
+ return this._connectUnix(options.path, connectionListener, options.signal);
366
+ }
367
+ const port = options.port;
368
+ const host = options.host || 'localhost';
369
+ // Handle autoSelectFamily option
370
+ if (typeof options.autoSelectFamily === 'boolean') {
371
+ this._autoSelectFamily = options.autoSelectFamily;
372
+ }
373
+ else {
374
+ this._autoSelectFamily = true;
375
+ }
376
+ return this._connect(port, host, connectionListener, options.signal);
377
+ }
378
+ _connect(port, host, listener, signal) {
379
+ this.remotePort = port; // Store intended remote port
380
+ if (this.connecting || this._connected)
381
+ return this;
382
+ if (signal?.aborted) {
383
+ process.nextTick(() => this.emit('error', new Error('The operation was aborted')));
384
+ return this;
385
+ }
386
+ this.connecting = true;
387
+ if (listener)
388
+ this.once('connect', listener);
389
+ if (signal) {
390
+ const abortHandler = () => {
391
+ this.destroy(new Error('The operation was aborted'));
392
+ };
393
+ signal.addEventListener('abort', abortHandler, { once: true });
394
+ this.once('connect', () => signal.removeEventListener('abort', abortHandler));
395
+ this.once('close', () => signal.removeEventListener('abort', abortHandler));
396
+ }
397
+ this._driver?.connect(host, port);
398
+ return this;
399
+ }
400
+ _connectUnix(path, listener, signal) {
401
+ if (this.connecting || this._connected)
402
+ return this;
403
+ if (signal?.aborted) {
404
+ process.nextTick(() => this.emit('error', new Error('The operation was aborted')));
405
+ return this;
406
+ }
407
+ this.connecting = true;
408
+ if (listener)
409
+ this.once('connect', listener);
410
+ if (signal) {
411
+ const abortHandler = () => {
412
+ this.destroy(new Error('The operation was aborted'));
413
+ };
414
+ signal.addEventListener('abort', abortHandler, { once: true });
415
+ this.once('connect', () => signal.removeEventListener('abort', abortHandler));
416
+ this.once('close', () => signal.removeEventListener('abort', abortHandler));
417
+ }
418
+ this._driver?.connectUnix(path);
419
+ return this;
420
+ }
421
+ end(chunk, encoding, cb) {
422
+ debugLog(`Socket (localPort: ${this.localPort}) .end() called`);
423
+ return super.end(chunk, encoding, cb);
424
+ }
425
+ _write(chunk, encoding, callback) {
426
+ if (!this._driver) {
427
+ return callback(new Error('Socket not connected'));
428
+ }
429
+ try {
430
+ const buffer = (chunk instanceof react_native_nitro_buffer_1.Buffer) ? chunk : react_native_nitro_buffer_1.Buffer.from(chunk, encoding);
431
+ this.bytesWritten += buffer.length;
432
+ const ab = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
433
+ debugLog(`Socket _write, len: ${ab.byteLength}`);
434
+ this._driver.write(ab);
435
+ callback(null);
436
+ }
437
+ catch (err) {
438
+ callback(err);
439
+ }
440
+ }
441
+ _read(size) {
442
+ if (this._driver)
443
+ this._driver.resume();
444
+ }
445
+ _final(callback) {
446
+ if (this._driver) {
447
+ this._driver.shutdown();
448
+ }
449
+ callback(null);
450
+ }
451
+ destroy(reason) {
452
+ debugLog(`Socket (localPort: ${this.localPort}) .destroy() called, reason: ${reason?.message}`);
453
+ return super.destroy(reason);
454
+ }
455
+ _destroy(err, callback) {
456
+ debugLog(`Socket (localPort: ${this.localPort}) ._destroy() called`);
457
+ this._connected = false;
458
+ this.connecting = false;
459
+ this.destroyed = true;
460
+ if (this._driver) {
461
+ this._driver.destroy();
462
+ this._driver = undefined;
463
+ }
464
+ callback(err);
465
+ }
466
+ // Standard net.Socket methods
467
+ setTimeout(msecs, callback) {
468
+ if (this._driver) {
469
+ this._driver.setTimeout(msecs);
470
+ }
471
+ if (callback)
472
+ this.once('timeout', callback);
473
+ return this;
474
+ }
475
+ /**
476
+ * Pause the reading of data. That is, 'data' events will not be emitted.
477
+ * Useful to throttle back an upload.
478
+ */
479
+ pause() {
480
+ super.pause();
481
+ if (this._driver) {
482
+ this._driver.pause();
483
+ }
484
+ return this;
485
+ }
486
+ /**
487
+ * Resume reading after a call to pause().
488
+ */
489
+ resume() {
490
+ const id = this._driver?.id;
491
+ debugLog(`Socket.resume() called, id: ${id}`);
492
+ super.resume();
493
+ if (this._driver) {
494
+ debugLog(`Socket.resume() calling driver.resume(), id: ${id}`);
495
+ this._driver.resume();
496
+ }
497
+ return this;
498
+ }
499
+ /**
500
+ * Enable/disable the use of Nagle's algorithm.
501
+ */
502
+ setNoDelay(noDelay) {
503
+ this._driver?.setNoDelay(noDelay !== false);
504
+ return this;
505
+ }
506
+ setKeepAlive(enable, initialDelay) {
507
+ this._driver?.setKeepAlive(enable !== false, initialDelay || 0);
508
+ return this;
509
+ }
510
+ ref() { return this; }
511
+ unref() { return this; }
512
+ /**
513
+ * Set the encoding for the socket as a Readable Stream.
514
+ * Use 'utf8', 'hex', etc.
515
+ */
516
+ setEncoding(encoding) {
517
+ super.setEncoding(encoding);
518
+ return this;
519
+ }
520
+ get timeout() {
521
+ return undefined; // Not tracked strictly as a property yet
522
+ }
523
+ get bufferSize() {
524
+ return 0; // Deprecated but often accessed
525
+ }
526
+ resetAndDestroy() {
527
+ if (this._driver) {
528
+ this._driver.resetAndDestroy();
529
+ this._driver = undefined;
530
+ }
531
+ this._connected = false;
532
+ this.connecting = false;
533
+ this.destroyed = true;
534
+ return this;
535
+ }
536
+ }
537
+ exports.Socket = Socket;
538
+ // -----------------------------------------------------------------------------
539
+ // Server
540
+ // -----------------------------------------------------------------------------
541
+ class Server extends eventemitter3_1.EventEmitter {
542
+ get maxConnections() {
543
+ return this._maxConnections;
544
+ }
545
+ set maxConnections(value) {
546
+ this._maxConnections = value;
547
+ // We handle maxConnections in JS to support 'drop' event.
548
+ // Disable native limit to ensure we receive the connection attempt.
549
+ this._driver.maxConnections = 0;
550
+ }
551
+ get dropMaxConnection() {
552
+ return this._dropMaxConnection;
553
+ }
554
+ set dropMaxConnection(value) {
555
+ this._dropMaxConnection = value;
556
+ }
557
+ get listening() {
558
+ // If we have a driver and we assume it's listening if it has been started?
559
+ // Actually, checking _driver state might be hard if not exposed.
560
+ // But typically 'listening' is true after 'listening' event.
561
+ // We can track it with a private flag or by checking address() which returns null if not listening.
562
+ return !!this.address();
563
+ }
564
+ constructor(options, connectionListener) {
565
+ super();
566
+ this._sockets = new Set();
567
+ this._connections = 0;
568
+ this._maxConnections = 0;
569
+ this._dropMaxConnection = false;
570
+ ensureInitialized();
571
+ this._driver = Driver_1.Driver.createServer();
572
+ if (typeof options === 'function') {
573
+ connectionListener = options;
574
+ options = {};
575
+ }
576
+ if (connectionListener) {
577
+ this.on('connection', connectionListener);
578
+ }
579
+ this._driver.onEvent = (eventType, data) => {
580
+ switch (eventType) {
581
+ case Net_nitro_1.NetServerEvent.CONNECTION: {
582
+ const payload = data ? react_native_nitro_buffer_1.Buffer.from(data).toString() : '';
583
+ if (payload === 'success') {
584
+ this.emit('listening');
585
+ }
586
+ else {
587
+ const clientId = payload;
588
+ debugLog(`Server connection clientId: '${clientId}', current connections: ${this._connections}, max: ${this._maxConnections}`);
589
+ if (clientId) {
590
+ // Check maxConnections
591
+ if (this._maxConnections > 0 && this._connections >= this._maxConnections) {
592
+ debugLog(`Server maxConnections reached (${this._connections} >= ${this._maxConnections}). Dropping connection. clientId: ${clientId}`);
593
+ const socketDriver = Driver_1.Driver.createSocket(clientId);
594
+ const socket = new Socket({
595
+ socketDriver: socketDriver,
596
+ readable: true,
597
+ writable: true
598
+ });
599
+ // @ts-ignore
600
+ socket._updateAddresses();
601
+ this.emit('drop', {
602
+ localAddress: socket.localAddress,
603
+ localPort: socket.localPort,
604
+ localFamily: socket.localFamily,
605
+ remoteAddress: socket.remoteAddress,
606
+ remotePort: socket.remotePort,
607
+ remoteFamily: socket.remoteFamily
608
+ });
609
+ socket.destroy();
610
+ return;
611
+ }
612
+ const socketDriver = Driver_1.Driver.createSocket(clientId);
613
+ const socket = new Socket({
614
+ socketDriver: socketDriver,
615
+ readable: true,
616
+ writable: true
617
+ });
618
+ // Initialize addresses immediately for server-side socket
619
+ // @ts-ignore
620
+ socket._updateAddresses();
621
+ debugLog(`Socket initialized addresses: local=${socket.localAddress}:${socket.localPort}, remote=${socket.remoteAddress}:${socket.remotePort}`);
622
+ // Keep reference to prevent GC
623
+ this._sockets.add(socket);
624
+ this._connections++;
625
+ socket.on('close', () => {
626
+ this._connections--;
627
+ this._sockets.delete(socket);
628
+ });
629
+ this.emit('connection', socket);
630
+ }
631
+ }
632
+ break;
633
+ }
634
+ case Net_nitro_1.NetServerEvent.ERROR:
635
+ this.emit('error', new Error(data ? react_native_nitro_buffer_1.Buffer.from(data).toString() : 'Unknown server error'));
636
+ break;
637
+ case Net_nitro_1.NetServerEvent.DEBUG: {
638
+ const msg = data ? react_native_nitro_buffer_1.Buffer.from(data).toString() : 'Unknown debug message';
639
+ debugLog(`Server NATIVE DEBUG: ${msg}`);
640
+ break;
641
+ }
642
+ case Net_nitro_1.NetServerEvent.CLOSE:
643
+ this.emit('close');
644
+ break;
645
+ }
646
+ };
647
+ }
648
+ ref() { return this; }
649
+ unref() { return this; }
650
+ // @ts-ignore
651
+ [Symbol.asyncDispose]() {
652
+ return new Promise((resolve) => {
653
+ this.close(() => resolve());
654
+ });
655
+ }
656
+ listen(port, host, backlog, callback) {
657
+ let _port = 0;
658
+ let _host;
659
+ let _backlog;
660
+ let _path;
661
+ let _callback;
662
+ let signal;
663
+ let ipv6Only = false;
664
+ let reusePort = false;
665
+ let handle;
666
+ if (typeof port === 'object' && port !== null) {
667
+ // Check if it's a handle object with fd property
668
+ if (typeof port.fd === 'number') {
669
+ handle = port;
670
+ _backlog = port.backlog;
671
+ _callback = host; // listen(handle, cb)
672
+ }
673
+ else {
674
+ _port = port.port;
675
+ _host = port.host;
676
+ _backlog = port.backlog;
677
+ _path = port.path;
678
+ signal = port.signal;
679
+ ipv6Only = port.ipv6Only === true;
680
+ reusePort = port.reusePort === true;
681
+ _callback = host; // listen(options, cb)
682
+ }
683
+ }
684
+ else {
685
+ _port = typeof port === 'number' ? port : (typeof port === 'string' && !isNaN(Number(port)) ? Number(port) : 0);
686
+ if (typeof port === 'string' && isNaN(Number(port)))
687
+ _path = port;
688
+ if (typeof host === 'string')
689
+ _host = host;
690
+ else if (typeof host === 'function')
691
+ _callback = host;
692
+ if (typeof backlog === 'number')
693
+ _backlog = backlog;
694
+ else if (typeof backlog === 'function')
695
+ _callback = backlog;
696
+ if (typeof callback === 'function')
697
+ _callback = callback;
698
+ }
699
+ if (_callback)
700
+ this.once('listening', _callback);
701
+ if (signal?.aborted) {
702
+ process.nextTick(() => this.emit('error', new Error('The operation was aborted')));
703
+ return this;
704
+ }
705
+ if (signal) {
706
+ const abortHandler = () => {
707
+ this.close();
708
+ this.emit('error', new Error('The operation was aborted'));
709
+ };
710
+ signal.addEventListener('abort', abortHandler, { once: true });
711
+ this.once('listening', () => signal.removeEventListener('abort', abortHandler));
712
+ this.once('close', () => signal.removeEventListener('abort', abortHandler));
713
+ }
714
+ if (handle && typeof handle.fd === 'number') {
715
+ // Listen on an existing file descriptor (handle)
716
+ this._driver.listenHandle(handle.fd, _backlog);
717
+ }
718
+ else if (_path) {
719
+ this._driver.listenUnix(_path, _backlog);
720
+ }
721
+ else {
722
+ this._driver.listen(_port || 0, _backlog, ipv6Only, reusePort);
723
+ }
724
+ return this;
725
+ }
726
+ close(callback) {
727
+ this._driver.close();
728
+ if (callback)
729
+ this.once('close', callback);
730
+ return this;
731
+ }
732
+ address() {
733
+ try {
734
+ const addr = this._driver.getLocalAddress();
735
+ if (addr) {
736
+ const parts = addr.split(':');
737
+ if (parts.length >= 2) {
738
+ const port = parseInt(parts[parts.length - 1], 10);
739
+ const address = parts.slice(0, parts.length - 1).join(':').replace(/[\[\]]/g, '');
740
+ const family = address.includes(':') ? 'IPv6' : 'IPv4';
741
+ return { port, family, address };
742
+ }
743
+ }
744
+ }
745
+ catch (e) {
746
+ // Ignore
747
+ }
748
+ return null;
749
+ }
750
+ getConnections(cb) {
751
+ cb(null, this._connections);
752
+ }
753
+ }
754
+ exports.Server = Server;
755
+ // -----------------------------------------------------------------------------
756
+ // Exports
757
+ // -----------------------------------------------------------------------------
758
+ function createConnection(options, connectionListener) {
759
+ const socket = new Socket(options);
760
+ return socket.connect(options, connectionListener);
761
+ }
762
+ exports.connect = createConnection;
763
+ function createServer(options, connectionListener) {
764
+ return new Server(options, connectionListener);
765
+ }
766
+ exports.default = {
767
+ Socket,
768
+ Server,
769
+ SocketAddress,
770
+ BlockList,
771
+ createConnection,
772
+ createServer,
773
+ connect: exports.connect,
774
+ isIP,
775
+ isIPv4,
776
+ isIPv6,
777
+ getDefaultAutoSelectFamily,
778
+ setDefaultAutoSelectFamily,
779
+ setVerbose,
780
+ initWithConfig,
781
+ };