@push.rocks/smartproxy 16.0.2 → 16.0.3

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 (115) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/core/models/index.d.ts +2 -0
  3. package/dist_ts/core/models/index.js +3 -1
  4. package/dist_ts/core/models/route-context.d.ts +62 -0
  5. package/dist_ts/core/models/route-context.js +43 -0
  6. package/dist_ts/core/models/socket-augmentation.d.ts +12 -0
  7. package/dist_ts/core/models/socket-augmentation.js +18 -0
  8. package/dist_ts/core/utils/event-system.d.ts +200 -0
  9. package/dist_ts/core/utils/event-system.js +224 -0
  10. package/dist_ts/core/utils/index.d.ts +7 -0
  11. package/dist_ts/core/utils/index.js +8 -1
  12. package/dist_ts/core/utils/route-manager.d.ts +118 -0
  13. package/dist_ts/core/utils/route-manager.js +383 -0
  14. package/dist_ts/core/utils/route-utils.d.ts +94 -0
  15. package/dist_ts/core/utils/route-utils.js +264 -0
  16. package/dist_ts/core/utils/security-utils.d.ts +111 -0
  17. package/dist_ts/core/utils/security-utils.js +212 -0
  18. package/dist_ts/core/utils/shared-security-manager.d.ts +110 -0
  19. package/dist_ts/core/utils/shared-security-manager.js +252 -0
  20. package/dist_ts/core/utils/template-utils.d.ts +37 -0
  21. package/dist_ts/core/utils/template-utils.js +104 -0
  22. package/dist_ts/core/utils/websocket-utils.d.ts +23 -0
  23. package/dist_ts/core/utils/websocket-utils.js +86 -0
  24. package/dist_ts/http/router/index.d.ts +5 -1
  25. package/dist_ts/http/router/index.js +4 -2
  26. package/dist_ts/http/router/route-router.d.ts +108 -0
  27. package/dist_ts/http/router/route-router.js +393 -0
  28. package/dist_ts/index.d.ts +8 -2
  29. package/dist_ts/index.js +10 -3
  30. package/dist_ts/proxies/index.d.ts +7 -2
  31. package/dist_ts/proxies/index.js +10 -4
  32. package/dist_ts/proxies/network-proxy/certificate-manager.d.ts +21 -0
  33. package/dist_ts/proxies/network-proxy/certificate-manager.js +92 -1
  34. package/dist_ts/proxies/network-proxy/context-creator.d.ts +34 -0
  35. package/dist_ts/proxies/network-proxy/context-creator.js +108 -0
  36. package/dist_ts/proxies/network-proxy/function-cache.d.ts +90 -0
  37. package/dist_ts/proxies/network-proxy/function-cache.js +198 -0
  38. package/dist_ts/proxies/network-proxy/http-request-handler.d.ts +40 -0
  39. package/dist_ts/proxies/network-proxy/http-request-handler.js +256 -0
  40. package/dist_ts/proxies/network-proxy/http2-request-handler.d.ts +24 -0
  41. package/dist_ts/proxies/network-proxy/http2-request-handler.js +201 -0
  42. package/dist_ts/proxies/network-proxy/models/types.d.ts +73 -1
  43. package/dist_ts/proxies/network-proxy/models/types.js +242 -1
  44. package/dist_ts/proxies/network-proxy/network-proxy.d.ts +23 -20
  45. package/dist_ts/proxies/network-proxy/network-proxy.js +147 -60
  46. package/dist_ts/proxies/network-proxy/request-handler.d.ts +38 -5
  47. package/dist_ts/proxies/network-proxy/request-handler.js +584 -198
  48. package/dist_ts/proxies/network-proxy/security-manager.d.ts +65 -0
  49. package/dist_ts/proxies/network-proxy/security-manager.js +255 -0
  50. package/dist_ts/proxies/network-proxy/websocket-handler.d.ts +13 -2
  51. package/dist_ts/proxies/network-proxy/websocket-handler.js +238 -20
  52. package/dist_ts/proxies/smart-proxy/index.d.ts +1 -1
  53. package/dist_ts/proxies/smart-proxy/index.js +3 -3
  54. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +3 -5
  55. package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +56 -3
  56. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +4 -57
  57. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +19 -228
  58. package/dist_ts/proxies/smart-proxy/port-manager.d.ts +81 -0
  59. package/dist_ts/proxies/smart-proxy/port-manager.js +166 -0
  60. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +5 -0
  61. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +131 -15
  62. package/dist_ts/proxies/smart-proxy/route-helpers/index.d.ts +3 -1
  63. package/dist_ts/proxies/smart-proxy/route-helpers/index.js +5 -3
  64. package/dist_ts/proxies/smart-proxy/route-helpers.d.ts +5 -178
  65. package/dist_ts/proxies/smart-proxy/route-helpers.js +8 -296
  66. package/dist_ts/proxies/smart-proxy/route-manager.d.ts +11 -2
  67. package/dist_ts/proxies/smart-proxy/route-manager.js +79 -10
  68. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +29 -2
  69. package/dist_ts/proxies/smart-proxy/smart-proxy.js +48 -43
  70. package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +67 -1
  71. package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +120 -1
  72. package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +3 -3
  73. package/dist_ts/proxies/smart-proxy/utils/route-validators.js +27 -5
  74. package/package.json +1 -1
  75. package/readme.md +102 -14
  76. package/readme.plan.md +103 -168
  77. package/ts/00_commitinfo_data.ts +1 -1
  78. package/ts/core/models/index.ts +2 -0
  79. package/ts/core/models/route-context.ts +113 -0
  80. package/ts/core/models/socket-augmentation.ts +33 -0
  81. package/ts/core/utils/event-system.ts +376 -0
  82. package/ts/core/utils/index.ts +7 -0
  83. package/ts/core/utils/route-manager.ts +489 -0
  84. package/ts/core/utils/route-utils.ts +312 -0
  85. package/ts/core/utils/security-utils.ts +309 -0
  86. package/ts/core/utils/shared-security-manager.ts +333 -0
  87. package/ts/core/utils/template-utils.ts +124 -0
  88. package/ts/core/utils/websocket-utils.ts +81 -0
  89. package/ts/http/router/index.ts +8 -1
  90. package/ts/http/router/route-router.ts +482 -0
  91. package/ts/index.ts +14 -2
  92. package/ts/proxies/index.ts +12 -3
  93. package/ts/proxies/network-proxy/certificate-manager.ts +114 -10
  94. package/ts/proxies/network-proxy/context-creator.ts +145 -0
  95. package/ts/proxies/network-proxy/function-cache.ts +259 -0
  96. package/ts/proxies/network-proxy/http-request-handler.ts +330 -0
  97. package/ts/proxies/network-proxy/http2-request-handler.ts +255 -0
  98. package/ts/proxies/network-proxy/models/types.ts +312 -1
  99. package/ts/proxies/network-proxy/network-proxy.ts +195 -86
  100. package/ts/proxies/network-proxy/request-handler.ts +698 -246
  101. package/ts/proxies/network-proxy/security-manager.ts +298 -0
  102. package/ts/proxies/network-proxy/websocket-handler.ts +276 -33
  103. package/ts/proxies/smart-proxy/index.ts +2 -12
  104. package/ts/proxies/smart-proxy/models/interfaces.ts +7 -4
  105. package/ts/proxies/smart-proxy/models/route-types.ts +78 -10
  106. package/ts/proxies/smart-proxy/network-proxy-bridge.ts +20 -257
  107. package/ts/proxies/smart-proxy/port-manager.ts +195 -0
  108. package/ts/proxies/smart-proxy/route-connection-handler.ts +156 -21
  109. package/ts/proxies/smart-proxy/route-manager.ts +98 -14
  110. package/ts/proxies/smart-proxy/smart-proxy.ts +56 -55
  111. package/ts/proxies/smart-proxy/utils/route-helpers.ts +167 -1
  112. package/ts/proxies/smart-proxy/utils/route-validators.ts +24 -5
  113. package/ts/proxies/smart-proxy/domain-config-manager.ts.bak +0 -441
  114. package/ts/proxies/smart-proxy/route-helpers/index.ts +0 -9
  115. package/ts/proxies/smart-proxy/route-helpers.ts +0 -498
@@ -0,0 +1,333 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { IRouteConfig, IRouteContext } from '../../proxies/smart-proxy/models/route-types.js';
3
+ import type {
4
+ IIpValidationResult,
5
+ IIpConnectionInfo,
6
+ ISecurityLogger,
7
+ IRateLimitInfo
8
+ } from './security-utils.js';
9
+ import {
10
+ isIPAuthorized,
11
+ checkMaxConnections,
12
+ checkConnectionRate,
13
+ trackConnection,
14
+ removeConnection,
15
+ cleanupExpiredRateLimits,
16
+ parseBasicAuthHeader
17
+ } from './security-utils.js';
18
+
19
+ /**
20
+ * Shared SecurityManager for use across proxy components
21
+ * Handles IP tracking, rate limiting, and authentication
22
+ */
23
+ export class SharedSecurityManager {
24
+ // IP connection tracking
25
+ private connectionsByIP: Map<string, IIpConnectionInfo> = new Map();
26
+
27
+ // Route-specific rate limiting
28
+ private rateLimits: Map<string, Map<string, IRateLimitInfo>> = new Map();
29
+
30
+ // Cache IP filtering results to avoid constant regex matching
31
+ private ipFilterCache: Map<string, Map<string, boolean>> = new Map();
32
+
33
+ // Default limits
34
+ private maxConnectionsPerIP: number;
35
+ private connectionRateLimitPerMinute: number;
36
+
37
+ // Cache cleanup interval
38
+ private cleanupInterval: NodeJS.Timeout | null = null;
39
+
40
+ /**
41
+ * Create a new SharedSecurityManager
42
+ *
43
+ * @param options - Configuration options
44
+ * @param logger - Logger instance
45
+ */
46
+ constructor(options: {
47
+ maxConnectionsPerIP?: number;
48
+ connectionRateLimitPerMinute?: number;
49
+ cleanupIntervalMs?: number;
50
+ routes?: IRouteConfig[];
51
+ }, private logger?: ISecurityLogger) {
52
+ this.maxConnectionsPerIP = options.maxConnectionsPerIP || 100;
53
+ this.connectionRateLimitPerMinute = options.connectionRateLimitPerMinute || 300;
54
+
55
+ // Set up logger with defaults if not provided
56
+ this.logger = logger || {
57
+ info: console.log,
58
+ warn: console.warn,
59
+ error: console.error
60
+ };
61
+
62
+ // Set up cache cleanup interval
63
+ const cleanupInterval = options.cleanupIntervalMs || 60000; // Default: 1 minute
64
+ this.cleanupInterval = setInterval(() => {
65
+ this.cleanupCaches();
66
+ }, cleanupInterval);
67
+
68
+ // Don't keep the process alive just for cleanup
69
+ if (this.cleanupInterval.unref) {
70
+ this.cleanupInterval.unref();
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Get connections count by IP
76
+ *
77
+ * @param ip - The IP address to check
78
+ * @returns Number of connections from this IP
79
+ */
80
+ public getConnectionCountByIP(ip: string): number {
81
+ return this.connectionsByIP.get(ip)?.connections.size || 0;
82
+ }
83
+
84
+ /**
85
+ * Track connection by IP
86
+ *
87
+ * @param ip - The IP address to track
88
+ * @param connectionId - The connection ID to associate
89
+ */
90
+ public trackConnectionByIP(ip: string, connectionId: string): void {
91
+ trackConnection(ip, connectionId, this.connectionsByIP);
92
+ }
93
+
94
+ /**
95
+ * Remove connection tracking for an IP
96
+ *
97
+ * @param ip - The IP address to update
98
+ * @param connectionId - The connection ID to remove
99
+ */
100
+ public removeConnectionByIP(ip: string, connectionId: string): void {
101
+ removeConnection(ip, connectionId, this.connectionsByIP);
102
+ }
103
+
104
+ /**
105
+ * Check if IP is authorized based on route security settings
106
+ *
107
+ * @param ip - The IP address to check
108
+ * @param allowedIPs - List of allowed IP patterns
109
+ * @param blockedIPs - List of blocked IP patterns
110
+ * @returns Whether the IP is authorized
111
+ */
112
+ public isIPAuthorized(
113
+ ip: string,
114
+ allowedIPs: string[] = ['*'],
115
+ blockedIPs: string[] = []
116
+ ): boolean {
117
+ return isIPAuthorized(ip, allowedIPs, blockedIPs);
118
+ }
119
+
120
+ /**
121
+ * Validate IP against rate limits and connection limits
122
+ *
123
+ * @param ip - The IP address to validate
124
+ * @returns Result with allowed status and reason if blocked
125
+ */
126
+ public validateIP(ip: string): IIpValidationResult {
127
+ // Check connection count limit
128
+ const connectionResult = checkMaxConnections(
129
+ ip,
130
+ this.connectionsByIP,
131
+ this.maxConnectionsPerIP
132
+ );
133
+ if (!connectionResult.allowed) {
134
+ return connectionResult;
135
+ }
136
+
137
+ // Check connection rate limit
138
+ const rateResult = checkConnectionRate(
139
+ ip,
140
+ this.connectionsByIP,
141
+ this.connectionRateLimitPerMinute
142
+ );
143
+ if (!rateResult.allowed) {
144
+ return rateResult;
145
+ }
146
+
147
+ return { allowed: true };
148
+ }
149
+
150
+ /**
151
+ * Check if a client is allowed to access a specific route
152
+ *
153
+ * @param route - The route to check
154
+ * @param context - The request context
155
+ * @returns Whether access is allowed
156
+ */
157
+ public isAllowed(route: IRouteConfig, context: IRouteContext): boolean {
158
+ if (!route.security) {
159
+ return true; // No security restrictions
160
+ }
161
+
162
+ // --- IP filtering ---
163
+ if (!this.isClientIpAllowed(route, context.clientIp)) {
164
+ this.logger?.debug?.(`IP ${context.clientIp} is blocked for route ${route.name || 'unnamed'}`);
165
+ return false;
166
+ }
167
+
168
+ // --- Rate limiting ---
169
+ if (route.security.rateLimit?.enabled && !this.isWithinRateLimit(route, context)) {
170
+ this.logger?.debug?.(`Rate limit exceeded for route ${route.name || 'unnamed'}`);
171
+ return false;
172
+ }
173
+
174
+ return true;
175
+ }
176
+
177
+ /**
178
+ * Check if a client IP is allowed for a route
179
+ *
180
+ * @param route - The route to check
181
+ * @param clientIp - The client IP
182
+ * @returns Whether the IP is allowed
183
+ */
184
+ private isClientIpAllowed(route: IRouteConfig, clientIp: string): boolean {
185
+ if (!route.security) {
186
+ return true; // No security restrictions
187
+ }
188
+
189
+ const routeId = route.id || route.name || 'unnamed';
190
+
191
+ // Check cache first
192
+ if (!this.ipFilterCache.has(routeId)) {
193
+ this.ipFilterCache.set(routeId, new Map());
194
+ }
195
+
196
+ const routeCache = this.ipFilterCache.get(routeId)!;
197
+ if (routeCache.has(clientIp)) {
198
+ return routeCache.get(clientIp)!;
199
+ }
200
+
201
+ // Check IP against route security settings
202
+ const ipAllowList = route.security.ipAllowList || route.security.allowedIps;
203
+ const ipBlockList = route.security.ipBlockList || route.security.blockedIps;
204
+
205
+ const allowed = this.isIPAuthorized(clientIp, ipAllowList, ipBlockList);
206
+
207
+ // Cache the result
208
+ routeCache.set(clientIp, allowed);
209
+
210
+ return allowed;
211
+ }
212
+
213
+ /**
214
+ * Check if request is within rate limit
215
+ *
216
+ * @param route - The route to check
217
+ * @param context - The request context
218
+ * @returns Whether the request is within rate limit
219
+ */
220
+ private isWithinRateLimit(route: IRouteConfig, context: IRouteContext): boolean {
221
+ if (!route.security?.rateLimit?.enabled) {
222
+ return true;
223
+ }
224
+
225
+ const rateLimit = route.security.rateLimit;
226
+ const routeId = route.id || route.name || 'unnamed';
227
+
228
+ // Determine rate limit key (by IP, path, or header)
229
+ let key = context.clientIp; // Default to IP
230
+
231
+ if (rateLimit.keyBy === 'path' && context.path) {
232
+ key = `${context.clientIp}:${context.path}`;
233
+ } else if (rateLimit.keyBy === 'header' && rateLimit.headerName && context.headers) {
234
+ const headerValue = context.headers[rateLimit.headerName.toLowerCase()];
235
+ if (headerValue) {
236
+ key = `${context.clientIp}:${headerValue}`;
237
+ }
238
+ }
239
+
240
+ // Get or create rate limit tracking for this route
241
+ if (!this.rateLimits.has(routeId)) {
242
+ this.rateLimits.set(routeId, new Map());
243
+ }
244
+
245
+ const routeLimits = this.rateLimits.get(routeId)!;
246
+ const now = Date.now();
247
+
248
+ // Get or create rate limit tracking for this key
249
+ let limit = routeLimits.get(key);
250
+ if (!limit || limit.expiry < now) {
251
+ // Create new rate limit or reset expired one
252
+ limit = {
253
+ count: 1,
254
+ expiry: now + (rateLimit.window * 1000)
255
+ };
256
+ routeLimits.set(key, limit);
257
+ return true;
258
+ }
259
+
260
+ // Increment the counter
261
+ limit.count++;
262
+
263
+ // Check if rate limit is exceeded
264
+ return limit.count <= rateLimit.maxRequests;
265
+ }
266
+
267
+ /**
268
+ * Validate HTTP Basic Authentication
269
+ *
270
+ * @param route - The route to check
271
+ * @param authHeader - The Authorization header
272
+ * @returns Whether authentication is valid
273
+ */
274
+ public validateBasicAuth(route: IRouteConfig, authHeader?: string): boolean {
275
+ // Skip if basic auth not enabled for route
276
+ if (!route.security?.basicAuth?.enabled) {
277
+ return true;
278
+ }
279
+
280
+ // No auth header means auth failed
281
+ if (!authHeader) {
282
+ return false;
283
+ }
284
+
285
+ // Parse auth header
286
+ const credentials = parseBasicAuthHeader(authHeader);
287
+ if (!credentials) {
288
+ return false;
289
+ }
290
+
291
+ // Check credentials against configured users
292
+ const { username, password } = credentials;
293
+ const users = route.security.basicAuth.users;
294
+
295
+ return users.some(user =>
296
+ user.username === username && user.password === password
297
+ );
298
+ }
299
+
300
+ /**
301
+ * Clean up caches to prevent memory leaks
302
+ */
303
+ private cleanupCaches(): void {
304
+ // Clean up rate limits
305
+ cleanupExpiredRateLimits(this.rateLimits, this.logger);
306
+
307
+ // IP filter cache doesn't need cleanup (tied to routes)
308
+ }
309
+
310
+ /**
311
+ * Clear all IP tracking data (for shutdown)
312
+ */
313
+ public clearIPTracking(): void {
314
+ this.connectionsByIP.clear();
315
+ this.rateLimits.clear();
316
+ this.ipFilterCache.clear();
317
+
318
+ if (this.cleanupInterval) {
319
+ clearInterval(this.cleanupInterval);
320
+ this.cleanupInterval = null;
321
+ }
322
+ }
323
+
324
+ /**
325
+ * Update routes for security checking
326
+ *
327
+ * @param routes - New routes to use
328
+ */
329
+ public setRoutes(routes: IRouteConfig[]): void {
330
+ // Only clear the IP filter cache - route-specific
331
+ this.ipFilterCache.clear();
332
+ }
333
+ }
@@ -0,0 +1,124 @@
1
+ import type { IRouteContext } from '../models/route-context.js';
2
+
3
+ /**
4
+ * Utility class for resolving template variables in strings
5
+ */
6
+ export class TemplateUtils {
7
+ /**
8
+ * Resolve template variables in a string using the route context
9
+ * Supports variables like {domain}, {path}, {clientIp}, etc.
10
+ *
11
+ * @param template The template string with {variables}
12
+ * @param context The route context with values
13
+ * @returns The resolved string
14
+ */
15
+ public static resolveTemplateVariables(template: string, context: IRouteContext): string {
16
+ if (!template) {
17
+ return template;
18
+ }
19
+
20
+ // Replace variables with values from context
21
+ return template.replace(/\{([a-zA-Z0-9_\.]+)\}/g, (match, varName) => {
22
+ // Handle nested properties with dot notation (e.g., {headers.host})
23
+ if (varName.includes('.')) {
24
+ const parts = varName.split('.');
25
+ let current: any = context;
26
+
27
+ // Traverse nested object structure
28
+ for (const part of parts) {
29
+ if (current === undefined || current === null) {
30
+ return match; // Return original if path doesn't exist
31
+ }
32
+ current = current[part];
33
+ }
34
+
35
+ // Return the resolved value if it exists
36
+ if (current !== undefined && current !== null) {
37
+ return TemplateUtils.convertToString(current);
38
+ }
39
+
40
+ return match;
41
+ }
42
+
43
+ // Direct property access
44
+ const value = context[varName as keyof IRouteContext];
45
+ if (value === undefined) {
46
+ return match; // Keep the original {variable} if not found
47
+ }
48
+
49
+ // Convert value to string
50
+ return TemplateUtils.convertToString(value);
51
+ });
52
+ }
53
+
54
+ /**
55
+ * Safely convert a value to a string
56
+ *
57
+ * @param value Any value to convert to string
58
+ * @returns String representation or original match for complex objects
59
+ */
60
+ private static convertToString(value: any): string {
61
+ if (value === null || value === undefined) {
62
+ return '';
63
+ }
64
+
65
+ if (typeof value === 'string') {
66
+ return value;
67
+ }
68
+
69
+ if (typeof value === 'number' || typeof value === 'boolean') {
70
+ return value.toString();
71
+ }
72
+
73
+ if (Array.isArray(value)) {
74
+ return value.join(',');
75
+ }
76
+
77
+ if (typeof value === 'object') {
78
+ try {
79
+ return JSON.stringify(value);
80
+ } catch (e) {
81
+ return '[Object]';
82
+ }
83
+ }
84
+
85
+ return String(value);
86
+ }
87
+
88
+ /**
89
+ * Resolve template variables in header values
90
+ *
91
+ * @param headers Header object with potential template variables
92
+ * @param context Route context for variable resolution
93
+ * @returns New header object with resolved values
94
+ */
95
+ public static resolveHeaderTemplates(
96
+ headers: Record<string, string>,
97
+ context: IRouteContext
98
+ ): Record<string, string> {
99
+ const result: Record<string, string> = {};
100
+
101
+ for (const [key, value] of Object.entries(headers)) {
102
+ // Skip special directive headers (starting with !)
103
+ if (value.startsWith('!')) {
104
+ result[key] = value;
105
+ continue;
106
+ }
107
+
108
+ // Resolve template variables in the header value
109
+ result[key] = TemplateUtils.resolveTemplateVariables(value, context);
110
+ }
111
+
112
+ return result;
113
+ }
114
+
115
+ /**
116
+ * Check if a string contains template variables
117
+ *
118
+ * @param str String to check for template variables
119
+ * @returns True if string contains template variables
120
+ */
121
+ public static containsTemplateVariables(str: string): boolean {
122
+ return !!str && /\{([a-zA-Z0-9_\.]+)\}/g.test(str);
123
+ }
124
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * WebSocket utility functions
3
+ */
4
+
5
+ /**
6
+ * Type for WebSocket RawData that can be different types in different environments
7
+ * This matches the ws library's type definition
8
+ */
9
+ export type RawData = Buffer | ArrayBuffer | Buffer[] | any;
10
+
11
+ /**
12
+ * Get the length of a WebSocket message regardless of its type
13
+ * (handles all possible WebSocket message data types)
14
+ *
15
+ * @param data - The data message from WebSocket (could be any RawData type)
16
+ * @returns The length of the data in bytes
17
+ */
18
+ export function getMessageSize(data: RawData): number {
19
+ if (typeof data === 'string') {
20
+ // For string data, get the byte length
21
+ return Buffer.from(data, 'utf8').length;
22
+ } else if (data instanceof Buffer) {
23
+ // For Node.js Buffer
24
+ return data.length;
25
+ } else if (data instanceof ArrayBuffer) {
26
+ // For ArrayBuffer
27
+ return data.byteLength;
28
+ } else if (Array.isArray(data)) {
29
+ // For array of buffers, sum their lengths
30
+ return data.reduce((sum, chunk) => {
31
+ if (chunk instanceof Buffer) {
32
+ return sum + chunk.length;
33
+ } else if (chunk instanceof ArrayBuffer) {
34
+ return sum + chunk.byteLength;
35
+ }
36
+ return sum;
37
+ }, 0);
38
+ } else {
39
+ // For other types, try to determine the size or return 0
40
+ try {
41
+ return Buffer.from(data).length;
42
+ } catch (e) {
43
+ console.warn('Could not determine message size', e);
44
+ return 0;
45
+ }
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Convert any raw WebSocket data to Buffer for consistent handling
51
+ *
52
+ * @param data - The data message from WebSocket (could be any RawData type)
53
+ * @returns A Buffer containing the data
54
+ */
55
+ export function toBuffer(data: RawData): Buffer {
56
+ if (typeof data === 'string') {
57
+ return Buffer.from(data, 'utf8');
58
+ } else if (data instanceof Buffer) {
59
+ return data;
60
+ } else if (data instanceof ArrayBuffer) {
61
+ return Buffer.from(data);
62
+ } else if (Array.isArray(data)) {
63
+ // For array of buffers, concatenate them
64
+ return Buffer.concat(data.map(chunk => {
65
+ if (chunk instanceof Buffer) {
66
+ return chunk;
67
+ } else if (chunk instanceof ArrayBuffer) {
68
+ return Buffer.from(chunk);
69
+ }
70
+ return Buffer.from(chunk);
71
+ }));
72
+ } else {
73
+ // For other types, try to convert to Buffer or return empty Buffer
74
+ try {
75
+ return Buffer.from(data);
76
+ } catch (e) {
77
+ console.warn('Could not convert message to Buffer', e);
78
+ return Buffer.alloc(0);
79
+ }
80
+ }
81
+ }
@@ -2,4 +2,11 @@
2
2
  * HTTP routing
3
3
  */
4
4
 
5
- export * from './proxy-router.js';
5
+ // Export selectively to avoid ambiguity between duplicate type names
6
+ export { ProxyRouter } from './proxy-router.js';
7
+ export type { IPathPatternConfig } from './proxy-router.js';
8
+ // Re-export the RouterResult and PathPatternConfig from proxy-router.js (legacy names maintained for compatibility)
9
+ export type { PathPatternConfig as ProxyPathPatternConfig, RouterResult as ProxyRouterResult } from './proxy-router.js';
10
+
11
+ export { RouteRouter } from './route-router.js';
12
+ export type { PathPatternConfig as RoutePathPatternConfig, RouterResult as RouteRouterResult } from './route-router.js';