@push.rocks/smartproxy 19.5.19 → 19.5.21

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 (110) hide show
  1. package/dist_ts/core/models/index.d.ts +2 -0
  2. package/dist_ts/core/models/index.js +3 -1
  3. package/dist_ts/core/models/socket-types.d.ts +14 -0
  4. package/dist_ts/core/models/socket-types.js +15 -0
  5. package/dist_ts/core/models/wrapped-socket.d.ts +34 -0
  6. package/dist_ts/core/models/wrapped-socket.js +82 -0
  7. package/dist_ts/core/routing/index.d.ts +11 -0
  8. package/dist_ts/core/routing/index.js +17 -0
  9. package/dist_ts/core/routing/matchers/domain.d.ts +34 -0
  10. package/dist_ts/core/routing/matchers/domain.js +91 -0
  11. package/dist_ts/core/routing/matchers/header.d.ts +32 -0
  12. package/dist_ts/core/routing/matchers/header.js +94 -0
  13. package/dist_ts/core/routing/matchers/index.d.ts +18 -0
  14. package/dist_ts/core/routing/matchers/index.js +20 -0
  15. package/dist_ts/core/routing/matchers/ip.d.ts +53 -0
  16. package/dist_ts/core/routing/matchers/ip.js +169 -0
  17. package/dist_ts/core/routing/matchers/path.d.ts +44 -0
  18. package/dist_ts/core/routing/matchers/path.js +148 -0
  19. package/dist_ts/core/routing/route-manager.d.ts +88 -0
  20. package/dist_ts/core/routing/route-manager.js +342 -0
  21. package/dist_ts/core/routing/route-utils.d.ts +28 -0
  22. package/dist_ts/core/routing/route-utils.js +67 -0
  23. package/dist_ts/core/routing/specificity.d.ts +30 -0
  24. package/dist_ts/core/routing/specificity.js +115 -0
  25. package/dist_ts/core/routing/types.d.ts +41 -0
  26. package/dist_ts/core/routing/types.js +5 -0
  27. package/dist_ts/core/utils/index.d.ts +1 -2
  28. package/dist_ts/core/utils/index.js +2 -3
  29. package/dist_ts/core/utils/proxy-protocol.d.ts +45 -0
  30. package/dist_ts/core/utils/proxy-protocol.js +201 -0
  31. package/dist_ts/core/utils/route-manager.d.ts +0 -30
  32. package/dist_ts/core/utils/route-manager.js +6 -47
  33. package/dist_ts/core/utils/route-utils.d.ts +2 -68
  34. package/dist_ts/core/utils/route-utils.js +21 -218
  35. package/dist_ts/core/utils/security-utils.js +4 -4
  36. package/dist_ts/index.d.ts +2 -5
  37. package/dist_ts/index.js +5 -11
  38. package/dist_ts/proxies/http-proxy/http-proxy.d.ts +0 -1
  39. package/dist_ts/proxies/http-proxy/http-proxy.js +15 -60
  40. package/dist_ts/proxies/http-proxy/models/types.d.ts +0 -90
  41. package/dist_ts/proxies/http-proxy/models/types.js +1 -242
  42. package/dist_ts/proxies/http-proxy/request-handler.d.ts +3 -5
  43. package/dist_ts/proxies/http-proxy/request-handler.js +20 -171
  44. package/dist_ts/proxies/http-proxy/websocket-handler.d.ts +2 -5
  45. package/dist_ts/proxies/http-proxy/websocket-handler.js +15 -23
  46. package/dist_ts/proxies/index.d.ts +2 -2
  47. package/dist_ts/proxies/index.js +4 -3
  48. package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +3 -1
  49. package/dist_ts/proxies/smart-proxy/connection-manager.js +17 -7
  50. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +2 -1
  51. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +5 -2
  52. package/dist_ts/proxies/smart-proxy/index.d.ts +1 -1
  53. package/dist_ts/proxies/smart-proxy/index.js +2 -2
  54. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +7 -2
  55. package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +1 -0
  56. package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
  57. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +1 -1
  58. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +155 -35
  59. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +1 -1
  60. package/dist_ts/proxies/smart-proxy/smart-proxy.js +15 -4
  61. package/dist_ts/proxies/smart-proxy/utils/route-utils.js +10 -43
  62. package/dist_ts/routing/router/http-router.d.ts +89 -0
  63. package/dist_ts/routing/router/http-router.js +205 -0
  64. package/dist_ts/routing/router/index.d.ts +2 -5
  65. package/dist_ts/routing/router/index.js +3 -4
  66. package/package.json +1 -1
  67. package/readme.delete.md +187 -0
  68. package/readme.hints.md +196 -1
  69. package/readme.plan.md +625 -0
  70. package/readme.proxy-chain-summary.md +112 -0
  71. package/readme.proxy-protocol-example.md +462 -0
  72. package/readme.proxy-protocol.md +415 -0
  73. package/readme.routing.md +341 -0
  74. package/ts/core/models/index.ts +2 -0
  75. package/ts/core/models/socket-types.ts +21 -0
  76. package/ts/core/models/wrapped-socket.ts +99 -0
  77. package/ts/core/routing/index.ts +21 -0
  78. package/ts/core/routing/matchers/domain.ts +119 -0
  79. package/ts/core/routing/matchers/header.ts +120 -0
  80. package/ts/core/routing/matchers/index.ts +22 -0
  81. package/ts/core/routing/matchers/ip.ts +207 -0
  82. package/ts/core/routing/matchers/path.ts +184 -0
  83. package/ts/core/{utils → routing}/route-manager.ts +7 -57
  84. package/ts/core/routing/route-utils.ts +88 -0
  85. package/ts/core/routing/specificity.ts +141 -0
  86. package/ts/core/routing/types.ts +49 -0
  87. package/ts/core/utils/index.ts +1 -2
  88. package/ts/core/utils/proxy-protocol.ts +246 -0
  89. package/ts/core/utils/security-utils.ts +3 -7
  90. package/ts/index.ts +4 -14
  91. package/ts/proxies/http-proxy/http-proxy.ts +13 -68
  92. package/ts/proxies/http-proxy/models/types.ts +0 -324
  93. package/ts/proxies/http-proxy/request-handler.ts +15 -186
  94. package/ts/proxies/http-proxy/websocket-handler.ts +15 -26
  95. package/ts/proxies/index.ts +3 -2
  96. package/ts/proxies/smart-proxy/connection-manager.ts +17 -7
  97. package/ts/proxies/smart-proxy/http-proxy-bridge.ts +6 -2
  98. package/ts/proxies/smart-proxy/index.ts +1 -1
  99. package/ts/proxies/smart-proxy/models/interfaces.ts +9 -2
  100. package/ts/proxies/smart-proxy/models/route-types.ts +3 -0
  101. package/ts/proxies/smart-proxy/route-connection-handler.ts +173 -42
  102. package/ts/proxies/smart-proxy/smart-proxy.ts +15 -3
  103. package/ts/proxies/smart-proxy/utils/route-utils.ts +11 -49
  104. package/ts/routing/router/http-router.ts +266 -0
  105. package/ts/routing/router/index.ts +3 -8
  106. package/readme.problems.md +0 -170
  107. package/ts/core/utils/route-utils.ts +0 -312
  108. package/ts/proxies/smart-proxy/route-manager.ts +0 -554
  109. package/ts/routing/router/proxy-router.ts +0 -437
  110. package/ts/routing/router/route-router.ts +0 -482
@@ -1,13 +1,11 @@
1
1
  import * as plugins from '../../plugins.js';
2
2
  import {
3
3
  createLogger,
4
- RouteManager,
5
- convertLegacyConfigToRouteConfig
6
4
  } from './models/types.js';
5
+ import { SharedRouteManager as RouteManager } from '../../core/routing/route-manager.js';
7
6
  import type {
8
7
  IHttpProxyOptions,
9
- ILogger,
10
- IReverseProxyConfig
8
+ ILogger
11
9
  } from './models/types.js';
12
10
  import type { IRouteConfig } from '../smart-proxy/models/route-types.js';
13
11
  import type { IRouteContext, IHttpRouteContext } from '../../core/models/route-context.js';
@@ -16,8 +14,7 @@ import { CertificateManager } from './certificate-manager.js';
16
14
  import { ConnectionPool } from './connection-pool.js';
17
15
  import { RequestHandler, type IMetricsTracker } from './request-handler.js';
18
16
  import { WebSocketHandler } from './websocket-handler.js';
19
- import { ProxyRouter } from '../../routing/router/index.js';
20
- import { RouteRouter } from '../../routing/router/route-router.js';
17
+ import { HttpRouter } from '../../routing/router/index.js';
21
18
  import { cleanupSocket } from '../../core/utils/socket-utils.js';
22
19
  import { FunctionCache } from './function-cache.js';
23
20
 
@@ -43,8 +40,7 @@ export class HttpProxy implements IMetricsTracker {
43
40
  private connectionPool: ConnectionPool;
44
41
  private requestHandler: RequestHandler;
45
42
  private webSocketHandler: WebSocketHandler;
46
- private legacyRouter = new ProxyRouter(); // Legacy router for backward compatibility
47
- private router = new RouteRouter(); // New modern router
43
+ private router = new HttpRouter(); // Unified HTTP router
48
44
  private routeManager: RouteManager;
49
45
  private functionCache: FunctionCache;
50
46
 
@@ -87,7 +83,6 @@ export class HttpProxy implements IMetricsTracker {
87
83
  // Defaults for SmartProxy integration
88
84
  connectionPoolSize: optionsArg.connectionPoolSize || 50,
89
85
  portProxyIntegration: optionsArg.portProxyIntegration || false,
90
- useExternalPort80Handler: optionsArg.useExternalPort80Handler || false,
91
86
  // Backend protocol (http1 or http2)
92
87
  backendProtocol: optionsArg.backendProtocol || 'http1',
93
88
  // Default ACME options
@@ -107,7 +102,11 @@ export class HttpProxy implements IMetricsTracker {
107
102
  this.logger = createLogger(this.options.logLevel);
108
103
 
109
104
  // Initialize route manager
110
- this.routeManager = new RouteManager(this.logger);
105
+ this.routeManager = new RouteManager({
106
+ logger: this.logger,
107
+ enableDetailedLogging: this.options.logLevel === 'debug',
108
+ routes: []
109
+ });
111
110
 
112
111
  // Initialize function cache
113
112
  this.functionCache = new FunctionCache(this.logger, {
@@ -121,15 +120,13 @@ export class HttpProxy implements IMetricsTracker {
121
120
  this.requestHandler = new RequestHandler(
122
121
  this.options,
123
122
  this.connectionPool,
124
- this.legacyRouter, // Still use legacy router for backward compatibility
125
123
  this.routeManager,
126
124
  this.functionCache,
127
- this.router // Pass the new modern router as well
125
+ this.router
128
126
  );
129
127
  this.webSocketHandler = new WebSocketHandler(
130
128
  this.options,
131
129
  this.connectionPool,
132
- this.legacyRouter,
133
130
  this.routes // Pass current routes to WebSocketHandler
134
131
  );
135
132
 
@@ -429,65 +426,13 @@ export class HttpProxy implements IMetricsTracker {
429
426
  }
430
427
  }
431
428
 
432
- // Create legacy proxy configs for the router
433
- // This is only needed for backward compatibility with ProxyRouter
434
-
435
- const defaultPort = 443; // Default port for HTTPS when using 'preserve'
436
- // and will be removed in the future
437
- const legacyConfigs: IReverseProxyConfig[] = [];
438
-
439
- for (const domain of currentHostnames) {
440
- // Find route for this domain
441
- const route = routes.find(r => {
442
- const domains = Array.isArray(r.match.domains) ? r.match.domains : [r.match.domains];
443
- return domains.includes(domain);
444
- });
445
-
446
- if (!route || route.action.type !== 'forward' || !route.action.target) {
447
- continue;
448
- }
449
-
450
- // Skip routes with function-based targets - we'll handle them during request processing
451
- if (typeof route.action.target.host === 'function' || typeof route.action.target.port === 'function') {
452
- this.logger.info(`Domain ${domain} uses function-based targets - will be handled at request time`);
453
- continue;
454
- }
455
-
456
- // Extract static target information
457
- const targetHosts = Array.isArray(route.action.target.host)
458
- ? route.action.target.host
459
- : [route.action.target.host];
460
-
461
- // Handle 'preserve' port value
462
- const targetPort = route.action.target.port === 'preserve' ? defaultPort : route.action.target.port;
463
-
464
- // Get certificate information
465
- const certData = certificateUpdates.get(domain);
466
- const defaultCerts = this.certificateManager.getDefaultCertificates();
467
-
468
- legacyConfigs.push({
469
- hostName: domain,
470
- destinationIps: targetHosts,
471
- destinationPorts: [targetPort],
472
- privateKey: certData?.key || defaultCerts.key,
473
- publicKey: certData?.cert || defaultCerts.cert
474
- });
475
- }
476
-
477
- // Update the router with legacy configs
478
- // Handle both old and new router interfaces
479
- if (typeof this.router.setRoutes === 'function') {
480
- this.router.setRoutes(routes);
481
- } else if (typeof this.router.setNewProxyConfigs === 'function') {
482
- this.router.setNewProxyConfigs(legacyConfigs);
483
- } else {
484
- this.logger.warn('Router has no recognized configuration method');
485
- }
429
+ // Update the router with new routes
430
+ this.router.setRoutes(routes);
486
431
 
487
432
  // Update WebSocket handler with new routes
488
433
  this.webSocketHandler.setRoutes(routes);
489
434
 
490
- this.logger.info(`Route configuration updated with ${routes.length} routes and ${legacyConfigs.length} proxy configs`);
435
+ this.logger.info(`Route configuration updated with ${routes.length} routes`);
491
436
  }
492
437
 
493
438
  // Legacy methods have been removed.
@@ -13,7 +13,6 @@ export interface IAcmeOptions {
13
13
  skipConfiguredCerts?: boolean;
14
14
  }
15
15
  import type { IRouteConfig } from '../../smart-proxy/models/route-types.js';
16
- import type { IRouteContext } from '../../../core/models/route-context.js';
17
16
 
18
17
  /**
19
18
  * Configuration options for HttpProxy
@@ -34,7 +33,6 @@ export interface IHttpProxyOptions {
34
33
  // Settings for SmartProxy integration
35
34
  connectionPoolSize?: number; // Maximum connections to maintain in the pool to each backend
36
35
  portProxyIntegration?: boolean; // Flag to indicate this proxy is used by SmartProxy
37
- useExternalPort80Handler?: boolean; // @deprecated - use SmartCertManager instead
38
36
  // Protocol to use when proxying to backends: HTTP/1.x or HTTP/2
39
37
  backendProtocol?: 'http1' | 'http2';
40
38
 
@@ -58,329 +56,7 @@ export interface ICertificateEntry {
58
56
  expires?: Date;
59
57
  }
60
58
 
61
- /**
62
- * @deprecated Use IRouteConfig instead. This interface will be removed in a future release.
63
- *
64
- * IMPORTANT: This is a legacy interface maintained only for backward compatibility.
65
- * New code should use IRouteConfig for all configuration purposes.
66
- *
67
- * @see IRouteConfig for the modern, recommended configuration format
68
- */
69
- export interface IReverseProxyConfig {
70
- /** Target hostnames/IPs to proxy requests to */
71
- destinationIps: string[];
72
-
73
- /** Target ports to proxy requests to */
74
- destinationPorts: number[];
75
-
76
- /** Hostname to match for routing */
77
- hostName: string;
78
-
79
- /** SSL private key for this host (PEM format) */
80
- privateKey: string;
81
-
82
- /** SSL public key/certificate for this host (PEM format) */
83
- publicKey: string;
84
-
85
- /** Basic authentication configuration */
86
- authentication?: {
87
- type: 'Basic';
88
- user: string;
89
- pass: string;
90
- };
91
-
92
- /** Whether to rewrite the Host header to match the target */
93
- rewriteHostHeader?: boolean;
94
-
95
- /**
96
- * Protocol to use when proxying to this backend: 'http1' or 'http2'.
97
- * Overrides the global backendProtocol option if set.
98
- */
99
- backendProtocol?: 'http1' | 'http2';
100
- }
101
-
102
- /**
103
- * Convert a legacy IReverseProxyConfig to the modern IRouteConfig format
104
- *
105
- * @deprecated This function is maintained for backward compatibility.
106
- * New code should create IRouteConfig objects directly.
107
- *
108
- * @param legacyConfig The legacy configuration to convert
109
- * @param proxyPort The port the proxy listens on
110
- * @returns A modern route configuration equivalent to the legacy config
111
- */
112
- export function convertLegacyConfigToRouteConfig(
113
- legacyConfig: IReverseProxyConfig,
114
- proxyPort: number
115
- ): IRouteConfig {
116
- // Create basic route configuration
117
- const routeConfig: IRouteConfig = {
118
- // Match properties
119
- match: {
120
- ports: proxyPort,
121
- domains: legacyConfig.hostName
122
- },
123
-
124
- // Action properties
125
- action: {
126
- type: 'forward',
127
- target: {
128
- host: legacyConfig.destinationIps,
129
- port: legacyConfig.destinationPorts[0]
130
- },
131
-
132
- // TLS mode is always 'terminate' for legacy configs
133
- tls: {
134
- mode: 'terminate',
135
- certificate: {
136
- key: legacyConfig.privateKey,
137
- cert: legacyConfig.publicKey
138
- }
139
- },
140
-
141
- // Advanced options
142
- advanced: {
143
- // Rewrite host header if specified
144
- headers: legacyConfig.rewriteHostHeader ? { 'host': '{domain}' } : {}
145
- }
146
- },
147
-
148
- // Metadata
149
- name: `Legacy Config - ${legacyConfig.hostName}`,
150
- priority: 0, // Default priority
151
- enabled: true
152
- };
153
-
154
- // Add authentication if present
155
- if (legacyConfig.authentication) {
156
- routeConfig.security = {
157
- authentication: {
158
- type: 'basic',
159
- credentials: [{
160
- username: legacyConfig.authentication.user,
161
- password: legacyConfig.authentication.pass
162
- }]
163
- }
164
- };
165
- }
166
-
167
- // Add backend protocol if specified
168
- if (legacyConfig.backendProtocol) {
169
- if (!routeConfig.action.options) {
170
- routeConfig.action.options = {};
171
- }
172
- routeConfig.action.options.backendProtocol = legacyConfig.backendProtocol;
173
- }
174
-
175
- return routeConfig;
176
- }
177
-
178
- /**
179
- * Route manager for NetworkProxy
180
- * Handles route matching and configuration
181
- */
182
- export class RouteManager {
183
- private routes: IRouteConfig[] = [];
184
- private logger: ILogger;
185
-
186
- constructor(logger: ILogger) {
187
- this.logger = logger;
188
- }
189
-
190
- /**
191
- * Update the routes configuration
192
- */
193
- public updateRoutes(routes: IRouteConfig[]): void {
194
- // Sort routes by priority (higher first)
195
- this.routes = [...routes].sort((a, b) => {
196
- const priorityA = a.priority ?? 0;
197
- const priorityB = b.priority ?? 0;
198
- return priorityB - priorityA;
199
- });
200
-
201
- this.logger.info(`Updated RouteManager with ${this.routes.length} routes`);
202
- }
203
-
204
- /**
205
- * Get all routes
206
- */
207
- public getRoutes(): IRouteConfig[] {
208
- return [...this.routes];
209
- }
210
-
211
- /**
212
- * Find the first matching route for a context
213
- */
214
- public findMatchingRoute(context: IRouteContext): IRouteConfig | null {
215
- for (const route of this.routes) {
216
- if (this.matchesRoute(route, context)) {
217
- return route;
218
- }
219
- }
220
- return null;
221
- }
222
59
 
223
- /**
224
- * Check if a route matches the given context
225
- */
226
- private matchesRoute(route: IRouteConfig, context: IRouteContext): boolean {
227
- // Skip disabled routes
228
- if (route.enabled === false) {
229
- return false;
230
- }
231
-
232
- // Check domain match if specified
233
- if (route.match.domains && context.domain) {
234
- const domains = Array.isArray(route.match.domains)
235
- ? route.match.domains
236
- : [route.match.domains];
237
-
238
- if (!domains.some(domainPattern => this.matchDomain(domainPattern, context.domain!))) {
239
- return false;
240
- }
241
- }
242
-
243
- // Check path match if specified
244
- if (route.match.path && context.path) {
245
- if (!this.matchPath(route.match.path, context.path)) {
246
- return false;
247
- }
248
- }
249
-
250
- // Check client IP match if specified
251
- if (route.match.clientIp && context.clientIp) {
252
- if (!route.match.clientIp.some(ip => this.matchIp(ip, context.clientIp))) {
253
- return false;
254
- }
255
- }
256
-
257
- // Check TLS version match if specified
258
- if (route.match.tlsVersion && context.tlsVersion) {
259
- if (!route.match.tlsVersion.includes(context.tlsVersion)) {
260
- return false;
261
- }
262
- }
263
-
264
- // All criteria matched
265
- return true;
266
- }
267
-
268
- /**
269
- * Match a domain pattern against a domain
270
- */
271
- private matchDomain(pattern: string, domain: string): boolean {
272
- if (pattern === domain) {
273
- return true;
274
- }
275
-
276
- if (pattern.includes('*')) {
277
- const regexPattern = pattern
278
- .replace(/\./g, '\\.')
279
- .replace(/\*/g, '.*');
280
-
281
- const regex = new RegExp(`^${regexPattern}$`, 'i');
282
- return regex.test(domain);
283
- }
284
-
285
- return false;
286
- }
287
-
288
- /**
289
- * Match a path pattern against a path
290
- */
291
- private matchPath(pattern: string, path: string): boolean {
292
- if (pattern === path) {
293
- return true;
294
- }
295
-
296
- if (pattern.endsWith('*')) {
297
- const prefix = pattern.slice(0, -1);
298
- return path.startsWith(prefix);
299
- }
300
-
301
- return false;
302
- }
303
-
304
- /**
305
- * Match an IP pattern against an IP
306
- * Supports exact matches, wildcard patterns, and CIDR notation
307
- */
308
- private matchIp(pattern: string, ip: string): boolean {
309
- // Exact match
310
- if (pattern === ip) {
311
- return true;
312
- }
313
-
314
- // Wildcard matching (e.g., 192.168.0.*)
315
- if (pattern.includes('*')) {
316
- const regexPattern = pattern
317
- .replace(/\./g, '\\.')
318
- .replace(/\*/g, '.*');
319
-
320
- const regex = new RegExp(`^${regexPattern}$`);
321
- return regex.test(ip);
322
- }
323
-
324
- // CIDR matching (e.g., 192.168.0.0/24)
325
- if (pattern.includes('/')) {
326
- try {
327
- const [subnet, bits] = pattern.split('/');
328
-
329
- // Convert IP addresses to numeric format for comparison
330
- const ipBinary = this.ipToBinary(ip);
331
- const subnetBinary = this.ipToBinary(subnet);
332
-
333
- if (!ipBinary || !subnetBinary) {
334
- return false;
335
- }
336
-
337
- // Get the subnet mask from CIDR notation
338
- const mask = parseInt(bits, 10);
339
- if (isNaN(mask) || mask < 0 || mask > 32) {
340
- return false;
341
- }
342
-
343
- // Check if the first 'mask' bits match between IP and subnet
344
- return ipBinary.slice(0, mask) === subnetBinary.slice(0, mask);
345
- } catch (error) {
346
- // If we encounter any error during CIDR matching, return false
347
- return false;
348
- }
349
- }
350
-
351
- return false;
352
- }
353
-
354
- /**
355
- * Convert an IP address to its binary representation
356
- * @param ip The IP address to convert
357
- * @returns Binary string representation or null if invalid
358
- */
359
- private ipToBinary(ip: string): string | null {
360
- // Handle IPv4 addresses only for now
361
- const parts = ip.split('.');
362
-
363
- // Validate IP format
364
- if (parts.length !== 4) {
365
- return null;
366
- }
367
-
368
- // Convert each octet to 8-bit binary and concatenate
369
- try {
370
- return parts
371
- .map(part => {
372
- const num = parseInt(part, 10);
373
- if (isNaN(num) || num < 0 || num > 255) {
374
- throw new Error('Invalid IP octet');
375
- }
376
- return num.toString(2).padStart(8, '0');
377
- })
378
- .join('');
379
- } catch (error) {
380
- return null;
381
- }
382
- }
383
- }
384
60
 
385
61
  /**
386
62
  * Interface for connection tracking in the pool