@push.rocks/smartproxy 19.5.19 → 19.5.20

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 (101) 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 +0 -2
  28. package/dist_ts/core/utils/index.js +1 -3
  29. package/dist_ts/core/utils/route-manager.d.ts +0 -30
  30. package/dist_ts/core/utils/route-manager.js +6 -47
  31. package/dist_ts/core/utils/route-utils.d.ts +2 -68
  32. package/dist_ts/core/utils/route-utils.js +21 -218
  33. package/dist_ts/core/utils/security-utils.js +4 -4
  34. package/dist_ts/index.d.ts +2 -5
  35. package/dist_ts/index.js +5 -11
  36. package/dist_ts/proxies/http-proxy/http-proxy.d.ts +0 -1
  37. package/dist_ts/proxies/http-proxy/http-proxy.js +15 -60
  38. package/dist_ts/proxies/http-proxy/models/types.d.ts +0 -90
  39. package/dist_ts/proxies/http-proxy/models/types.js +1 -242
  40. package/dist_ts/proxies/http-proxy/request-handler.d.ts +3 -5
  41. package/dist_ts/proxies/http-proxy/request-handler.js +20 -171
  42. package/dist_ts/proxies/http-proxy/websocket-handler.d.ts +2 -5
  43. package/dist_ts/proxies/http-proxy/websocket-handler.js +15 -23
  44. package/dist_ts/proxies/index.d.ts +2 -2
  45. package/dist_ts/proxies/index.js +4 -3
  46. package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +3 -1
  47. package/dist_ts/proxies/smart-proxy/connection-manager.js +15 -7
  48. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +2 -1
  49. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +5 -2
  50. package/dist_ts/proxies/smart-proxy/index.d.ts +1 -1
  51. package/dist_ts/proxies/smart-proxy/index.js +2 -2
  52. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +6 -2
  53. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +1 -1
  54. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +48 -25
  55. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +1 -1
  56. package/dist_ts/proxies/smart-proxy/smart-proxy.js +15 -4
  57. package/dist_ts/proxies/smart-proxy/utils/route-utils.js +10 -43
  58. package/dist_ts/routing/router/http-router.d.ts +89 -0
  59. package/dist_ts/routing/router/http-router.js +205 -0
  60. package/dist_ts/routing/router/index.d.ts +2 -5
  61. package/dist_ts/routing/router/index.js +3 -4
  62. package/package.json +1 -1
  63. package/readme.delete.md +187 -0
  64. package/readme.hints.md +189 -1
  65. package/readme.plan.md +621 -0
  66. package/readme.routing.md +341 -0
  67. package/ts/core/models/index.ts +2 -0
  68. package/ts/core/models/socket-types.ts +21 -0
  69. package/ts/core/models/wrapped-socket.ts +99 -0
  70. package/ts/core/routing/index.ts +21 -0
  71. package/ts/core/routing/matchers/domain.ts +119 -0
  72. package/ts/core/routing/matchers/header.ts +120 -0
  73. package/ts/core/routing/matchers/index.ts +22 -0
  74. package/ts/core/routing/matchers/ip.ts +207 -0
  75. package/ts/core/routing/matchers/path.ts +184 -0
  76. package/ts/core/{utils → routing}/route-manager.ts +7 -57
  77. package/ts/core/routing/route-utils.ts +88 -0
  78. package/ts/core/routing/specificity.ts +141 -0
  79. package/ts/core/routing/types.ts +49 -0
  80. package/ts/core/utils/index.ts +0 -2
  81. package/ts/core/utils/security-utils.ts +3 -7
  82. package/ts/index.ts +4 -14
  83. package/ts/proxies/http-proxy/http-proxy.ts +13 -68
  84. package/ts/proxies/http-proxy/models/types.ts +0 -324
  85. package/ts/proxies/http-proxy/request-handler.ts +15 -186
  86. package/ts/proxies/http-proxy/websocket-handler.ts +15 -26
  87. package/ts/proxies/index.ts +3 -2
  88. package/ts/proxies/smart-proxy/connection-manager.ts +15 -7
  89. package/ts/proxies/smart-proxy/http-proxy-bridge.ts +6 -2
  90. package/ts/proxies/smart-proxy/index.ts +1 -1
  91. package/ts/proxies/smart-proxy/models/interfaces.ts +8 -2
  92. package/ts/proxies/smart-proxy/route-connection-handler.ts +58 -30
  93. package/ts/proxies/smart-proxy/smart-proxy.ts +15 -3
  94. package/ts/proxies/smart-proxy/utils/route-utils.ts +11 -49
  95. package/ts/routing/router/http-router.ts +266 -0
  96. package/ts/routing/router/index.ts +3 -8
  97. package/readme.problems.md +0 -170
  98. package/ts/core/utils/route-utils.ts +0 -312
  99. package/ts/proxies/smart-proxy/route-manager.ts +0 -554
  100. package/ts/routing/router/proxy-router.ts +0 -437
  101. package/ts/routing/router/route-router.ts +0 -482
@@ -0,0 +1,342 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import { matchRouteDomain, calculateRouteSpecificity } from './route-utils.js';
3
+ import { DomainMatcher, PathMatcher, IpMatcher } from './matchers/index.js';
4
+ /**
5
+ * Shared RouteManager used by both SmartProxy and NetworkProxy
6
+ *
7
+ * This provides a unified implementation for route management,
8
+ * route matching, and port handling.
9
+ */
10
+ export class SharedRouteManager extends plugins.EventEmitter {
11
+ constructor(options) {
12
+ super();
13
+ this.routes = [];
14
+ this.portMap = new Map();
15
+ /**
16
+ * Memoization cache for expanded port ranges
17
+ */
18
+ this.portRangeCache = new Map();
19
+ // Set up logger (use console if not provided)
20
+ this.logger = options.logger || {
21
+ info: console.log,
22
+ warn: console.warn,
23
+ error: console.error,
24
+ debug: options.enableDetailedLogging ? console.log : undefined
25
+ };
26
+ this.enableDetailedLogging = options.enableDetailedLogging || false;
27
+ // Initialize routes if provided
28
+ if (options.routes) {
29
+ this.updateRoutes(options.routes);
30
+ }
31
+ }
32
+ /**
33
+ * Update routes with new configuration
34
+ */
35
+ updateRoutes(routes = []) {
36
+ // Sort routes by priority (higher first)
37
+ this.routes = [...(routes || [])].sort((a, b) => {
38
+ const priorityA = a.priority ?? 0;
39
+ const priorityB = b.priority ?? 0;
40
+ return priorityB - priorityA;
41
+ });
42
+ // Rebuild port mapping for fast lookups
43
+ this.rebuildPortMap();
44
+ this.logger.info(`Updated RouteManager with ${this.routes.length} routes`);
45
+ }
46
+ /**
47
+ * Get all routes
48
+ */
49
+ getRoutes() {
50
+ return [...this.routes];
51
+ }
52
+ /**
53
+ * Rebuild the port mapping for fast lookups
54
+ * Also logs information about the ports being listened on
55
+ */
56
+ rebuildPortMap() {
57
+ this.portMap.clear();
58
+ this.portRangeCache.clear(); // Clear cache when rebuilding
59
+ // Track ports for logging
60
+ const portToRoutesMap = new Map();
61
+ for (const route of this.routes) {
62
+ const ports = this.expandPortRange(route.match.ports);
63
+ // Skip if no ports were found
64
+ if (ports.length === 0) {
65
+ this.logger.warn(`Route ${route.name || 'unnamed'} has no valid ports to listen on`);
66
+ continue;
67
+ }
68
+ for (const port of ports) {
69
+ // Add to portMap for routing
70
+ if (!this.portMap.has(port)) {
71
+ this.portMap.set(port, []);
72
+ }
73
+ this.portMap.get(port).push(route);
74
+ // Add to tracking for logging
75
+ if (!portToRoutesMap.has(port)) {
76
+ portToRoutesMap.set(port, []);
77
+ }
78
+ portToRoutesMap.get(port).push(route.name || 'unnamed');
79
+ }
80
+ }
81
+ // Log summary of ports and routes
82
+ const totalPorts = this.portMap.size;
83
+ const totalRoutes = this.routes.length;
84
+ this.logger.info(`Route manager configured with ${totalRoutes} routes across ${totalPorts} ports`);
85
+ // Log port details if detailed logging is enabled
86
+ if (this.enableDetailedLogging) {
87
+ for (const [port, routes] of this.portMap.entries()) {
88
+ this.logger.info(`Port ${port}: ${routes.length} routes (${portToRoutesMap.get(port).join(', ')})`);
89
+ }
90
+ }
91
+ }
92
+ /**
93
+ * Expand a port range specification into an array of individual ports
94
+ * Uses caching to improve performance for frequently used port ranges
95
+ *
96
+ * @public - Made public to allow external code to interpret port ranges
97
+ */
98
+ expandPortRange(portRange) {
99
+ // For simple number, return immediately
100
+ if (typeof portRange === 'number') {
101
+ return [portRange];
102
+ }
103
+ // Create a cache key for this port range
104
+ const cacheKey = JSON.stringify(portRange);
105
+ // Check if we have a cached result
106
+ if (this.portRangeCache.has(cacheKey)) {
107
+ return this.portRangeCache.get(cacheKey);
108
+ }
109
+ // Process the port range
110
+ let result = [];
111
+ if (Array.isArray(portRange)) {
112
+ // Handle array of port objects or numbers
113
+ result = portRange.flatMap(item => {
114
+ if (typeof item === 'number') {
115
+ return [item];
116
+ }
117
+ else if (typeof item === 'object' && 'from' in item && 'to' in item) {
118
+ // Handle port range object - check valid range
119
+ if (item.from > item.to) {
120
+ this.logger.warn(`Invalid port range: from (${item.from}) > to (${item.to})`);
121
+ return [];
122
+ }
123
+ // Handle port range object
124
+ const ports = [];
125
+ for (let p = item.from; p <= item.to; p++) {
126
+ ports.push(p);
127
+ }
128
+ return ports;
129
+ }
130
+ return [];
131
+ });
132
+ }
133
+ // Cache the result
134
+ this.portRangeCache.set(cacheKey, result);
135
+ return result;
136
+ }
137
+ /**
138
+ * Get all ports that should be listened on
139
+ * This method automatically infers all required ports from route configurations
140
+ */
141
+ getListeningPorts() {
142
+ // Return the unique set of ports from all routes
143
+ return Array.from(this.portMap.keys());
144
+ }
145
+ /**
146
+ * Get all routes for a given port
147
+ */
148
+ getRoutesForPort(port) {
149
+ return this.portMap.get(port) || [];
150
+ }
151
+ /**
152
+ * Find the matching route for a connection
153
+ */
154
+ findMatchingRoute(context) {
155
+ // Get routes for this port if using port-based filtering
156
+ const routesToCheck = context.port
157
+ ? (this.portMap.get(context.port) || [])
158
+ : this.routes;
159
+ // Find the first matching route based on priority order
160
+ for (const route of routesToCheck) {
161
+ if (this.matchesRoute(route, context)) {
162
+ return { route };
163
+ }
164
+ }
165
+ return null;
166
+ }
167
+ /**
168
+ * Check if a route matches the given context
169
+ */
170
+ matchesRoute(route, context) {
171
+ // Skip disabled routes
172
+ if (route.enabled === false) {
173
+ return false;
174
+ }
175
+ // Check port match if provided in context
176
+ if (context.port !== undefined) {
177
+ const ports = this.expandPortRange(route.match.ports);
178
+ if (!ports.includes(context.port)) {
179
+ return false;
180
+ }
181
+ }
182
+ // Check domain match if specified
183
+ if (route.match.domains && context.domain) {
184
+ const domains = Array.isArray(route.match.domains)
185
+ ? route.match.domains
186
+ : [route.match.domains];
187
+ if (!domains.some(domainPattern => DomainMatcher.match(domainPattern, context.domain))) {
188
+ return false;
189
+ }
190
+ }
191
+ // Check path match if specified
192
+ if (route.match.path && context.path) {
193
+ if (!PathMatcher.match(route.match.path, context.path).matches) {
194
+ return false;
195
+ }
196
+ }
197
+ // Check client IP match if specified
198
+ if (route.match.clientIp && context.clientIp) {
199
+ if (!route.match.clientIp.some(ip => IpMatcher.match(ip, context.clientIp))) {
200
+ return false;
201
+ }
202
+ }
203
+ // Check TLS version match if specified
204
+ if (route.match.tlsVersion && context.tlsVersion) {
205
+ if (!route.match.tlsVersion.includes(context.tlsVersion)) {
206
+ return false;
207
+ }
208
+ }
209
+ // Check header match if specified
210
+ if (route.match.headers && context.headers) {
211
+ for (const [headerName, expectedValue] of Object.entries(route.match.headers)) {
212
+ const actualValue = context.headers[headerName.toLowerCase()];
213
+ // If header doesn't exist, no match
214
+ if (actualValue === undefined) {
215
+ return false;
216
+ }
217
+ // Match against string or regex
218
+ if (typeof expectedValue === 'string') {
219
+ if (actualValue !== expectedValue) {
220
+ return false;
221
+ }
222
+ }
223
+ else if (expectedValue instanceof RegExp) {
224
+ if (!expectedValue.test(actualValue)) {
225
+ return false;
226
+ }
227
+ }
228
+ }
229
+ }
230
+ // All criteria matched
231
+ return true;
232
+ }
233
+ /**
234
+ * Validate the route configuration and return any warnings
235
+ */
236
+ validateConfiguration() {
237
+ const warnings = [];
238
+ const duplicatePorts = new Map();
239
+ // Check for routes with the same exact match criteria
240
+ for (let i = 0; i < this.routes.length; i++) {
241
+ for (let j = i + 1; j < this.routes.length; j++) {
242
+ const route1 = this.routes[i];
243
+ const route2 = this.routes[j];
244
+ // Check if route match criteria are the same
245
+ if (this.areMatchesSimilar(route1.match, route2.match)) {
246
+ warnings.push(`Routes "${route1.name || i}" and "${route2.name || j}" have similar match criteria. ` +
247
+ `The route with higher priority (${Math.max(route1.priority || 0, route2.priority || 0)}) will be used.`);
248
+ }
249
+ }
250
+ }
251
+ // Check for routes that may never be matched due to priority
252
+ for (let i = 0; i < this.routes.length; i++) {
253
+ const route = this.routes[i];
254
+ const higherPriorityRoutes = this.routes.filter(r => (r.priority || 0) > (route.priority || 0));
255
+ for (const higherRoute of higherPriorityRoutes) {
256
+ if (this.isRouteShadowed(route, higherRoute)) {
257
+ warnings.push(`Route "${route.name || i}" may never be matched because it is shadowed by ` +
258
+ `higher priority route "${higherRoute.name || 'unnamed'}"`);
259
+ break;
260
+ }
261
+ }
262
+ }
263
+ return warnings;
264
+ }
265
+ /**
266
+ * Check if two route matches are similar (potential conflict)
267
+ */
268
+ areMatchesSimilar(match1, match2) {
269
+ // Check port overlap
270
+ const ports1 = new Set(this.expandPortRange(match1.ports));
271
+ const ports2 = new Set(this.expandPortRange(match2.ports));
272
+ let havePortOverlap = false;
273
+ for (const port of ports1) {
274
+ if (ports2.has(port)) {
275
+ havePortOverlap = true;
276
+ break;
277
+ }
278
+ }
279
+ if (!havePortOverlap) {
280
+ return false;
281
+ }
282
+ // Check domain overlap
283
+ if (match1.domains && match2.domains) {
284
+ const domains1 = Array.isArray(match1.domains) ? match1.domains : [match1.domains];
285
+ const domains2 = Array.isArray(match2.domains) ? match2.domains : [match2.domains];
286
+ // Check if any domain pattern from match1 could match any from match2
287
+ let haveDomainOverlap = false;
288
+ for (const domain1 of domains1) {
289
+ for (const domain2 of domains2) {
290
+ if (domain1 === domain2 ||
291
+ (domain1.includes('*') || domain2.includes('*'))) {
292
+ haveDomainOverlap = true;
293
+ break;
294
+ }
295
+ }
296
+ if (haveDomainOverlap)
297
+ break;
298
+ }
299
+ if (!haveDomainOverlap) {
300
+ return false;
301
+ }
302
+ }
303
+ else if (match1.domains || match2.domains) {
304
+ // One has domains, the other doesn't - they could overlap
305
+ // The one with domains is more specific, so it's not exactly a conflict
306
+ return false;
307
+ }
308
+ // Check path overlap
309
+ if (match1.path && match2.path) {
310
+ // This is a simplified check - in a real implementation,
311
+ // you'd need to check if the path patterns could match the same paths
312
+ return match1.path === match2.path ||
313
+ match1.path.includes('*') ||
314
+ match2.path.includes('*');
315
+ }
316
+ else if (match1.path || match2.path) {
317
+ // One has a path, the other doesn't
318
+ return false;
319
+ }
320
+ // If we get here, the matches have significant overlap
321
+ return true;
322
+ }
323
+ /**
324
+ * Check if a route is completely shadowed by a higher priority route
325
+ */
326
+ isRouteShadowed(route, higherPriorityRoute) {
327
+ // If they don't have similar match criteria, no shadowing occurs
328
+ if (!this.areMatchesSimilar(route.match, higherPriorityRoute.match)) {
329
+ return false;
330
+ }
331
+ // If higher priority route has more specific criteria, no shadowing
332
+ const routeSpecificity = calculateRouteSpecificity(route.match);
333
+ const higherRouteSpecificity = calculateRouteSpecificity(higherPriorityRoute.match);
334
+ if (higherRouteSpecificity > routeSpecificity) {
335
+ return false;
336
+ }
337
+ // If higher priority route is equally or less specific but has higher priority,
338
+ // it shadows the lower priority route
339
+ return true;
340
+ }
341
+ }
342
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2NvcmUvcm91dGluZy9yb3V0ZS1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFRNUMsT0FBTyxFQUNMLGdCQUFnQixFQUNoQix5QkFBeUIsRUFDMUIsTUFBTSxrQkFBa0IsQ0FBQztBQUMxQixPQUFPLEVBQUUsYUFBYSxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQXFCNUU7Ozs7O0dBS0c7QUFDSCxNQUFNLE9BQU8sa0JBQW1CLFNBQVEsT0FBTyxDQUFDLFlBQVk7SUFXMUQsWUFBWSxPQUlYO1FBQ0MsS0FBSyxFQUFFLENBQUM7UUFmRixXQUFNLEdBQW1CLEVBQUUsQ0FBQztRQUM1QixZQUFPLEdBQWdDLElBQUksR0FBRyxFQUFFLENBQUM7UUFJekQ7O1dBRUc7UUFDSyxtQkFBYyxHQUEwQixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBU3hELDhDQUE4QztRQUM5QyxJQUFJLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLElBQUk7WUFDOUIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxHQUFHO1lBQ2pCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtZQUNsQixLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUs7WUFDcEIsS0FBSyxFQUFFLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsU0FBUztTQUMvRCxDQUFDO1FBRUYsSUFBSSxDQUFDLHFCQUFxQixHQUFHLE9BQU8sQ0FBQyxxQkFBcUIsSUFBSSxLQUFLLENBQUM7UUFFcEUsZ0NBQWdDO1FBQ2hDLElBQUksT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ25CLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxD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
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Route matching utilities for SmartProxy components
3
+ *
4
+ * This file provides utility functions that use the unified matchers
5
+ * and additional route-specific utilities.
6
+ */
7
+ /**
8
+ * Match domains from a route against a given domain
9
+ *
10
+ * @param domains Array or single domain pattern to match against
11
+ * @param domain Domain to match
12
+ * @returns Whether the domain matches any of the patterns
13
+ */
14
+ export declare function matchRouteDomain(domains: string | string[] | undefined, domain: string | undefined): boolean;
15
+ /**
16
+ * Calculate route specificity score
17
+ * Higher score means more specific matching criteria
18
+ *
19
+ * @param match Match criteria to evaluate
20
+ * @returns Numeric specificity score
21
+ */
22
+ export declare function calculateRouteSpecificity(match: {
23
+ domains?: string | string[];
24
+ path?: string;
25
+ clientIp?: string[];
26
+ tlsVersion?: string[];
27
+ headers?: Record<string, string | RegExp>;
28
+ }): number;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Route matching utilities for SmartProxy components
3
+ *
4
+ * This file provides utility functions that use the unified matchers
5
+ * and additional route-specific utilities.
6
+ */
7
+ import { DomainMatcher, PathMatcher, IpMatcher, HeaderMatcher } from './matchers/index.js';
8
+ import { RouteSpecificity } from './specificity.js';
9
+ /**
10
+ * Match domains from a route against a given domain
11
+ *
12
+ * @param domains Array or single domain pattern to match against
13
+ * @param domain Domain to match
14
+ * @returns Whether the domain matches any of the patterns
15
+ */
16
+ export function matchRouteDomain(domains, domain) {
17
+ // If no domains specified in the route, match all domains
18
+ if (!domains) {
19
+ return true;
20
+ }
21
+ // If no domain in the request, can't match domain-specific routes
22
+ if (!domain) {
23
+ return false;
24
+ }
25
+ const patterns = Array.isArray(domains) ? domains : [domains];
26
+ return patterns.some(pattern => DomainMatcher.match(pattern, domain));
27
+ }
28
+ /**
29
+ * Calculate route specificity score
30
+ * Higher score means more specific matching criteria
31
+ *
32
+ * @param match Match criteria to evaluate
33
+ * @returns Numeric specificity score
34
+ */
35
+ export function calculateRouteSpecificity(match) {
36
+ let score = 0;
37
+ // Path specificity using PathMatcher
38
+ if (match.path) {
39
+ score += PathMatcher.calculateSpecificity(match.path);
40
+ }
41
+ // Domain specificity using DomainMatcher
42
+ if (match.domains) {
43
+ const domains = Array.isArray(match.domains) ? match.domains : [match.domains];
44
+ // Use the highest specificity among all domains
45
+ const domainScore = Math.max(...domains.map(d => DomainMatcher.calculateSpecificity(d)));
46
+ score += domainScore;
47
+ }
48
+ // Headers specificity using HeaderMatcher
49
+ if (match.headers) {
50
+ const stringHeaders = {};
51
+ for (const [key, value] of Object.entries(match.headers)) {
52
+ stringHeaders[key] = value instanceof RegExp ? value.source : value;
53
+ }
54
+ score += HeaderMatcher.calculateSpecificity(stringHeaders);
55
+ }
56
+ // Client IP adds some specificity
57
+ if (match.clientIp && match.clientIp.length > 0) {
58
+ // Use the first IP pattern for specificity
59
+ score += IpMatcher.calculateSpecificity(match.clientIp[0]);
60
+ }
61
+ // TLS version adds minimal specificity
62
+ if (match.tlsVersion && match.tlsVersion.length > 0) {
63
+ score += match.tlsVersion.length * 10;
64
+ }
65
+ return score;
66
+ }
67
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUtdXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9jb3JlL3JvdXRpbmcvcm91dGUtdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0dBS0c7QUFFSCxPQUFPLEVBQUUsYUFBYSxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDM0YsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFLcEQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLGdCQUFnQixDQUFDLE9BQXNDLEVBQUUsTUFBMEI7SUFDakcsMERBQTBEO0lBQzFELElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNiLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELGtFQUFrRTtJQUNsRSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDWixPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDOUQsT0FBTyxRQUFRLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztBQUN4RSxDQUFDO0FBSUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLHlCQUF5QixDQUFDLEtBTXpDO0lBQ0MsSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFDO0lBRWQscUNBQXFDO0lBQ3JDLElBQUksS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2YsS0FBSyxJQUFJLFdBQVcsQ0FBQyxvQkFBb0IsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUVELHlDQUF5QztJQUN6QyxJQUFJLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNsQixNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDL0UsZ0RBQWdEO1FBQ2hELE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLG9CQUFvQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN6RixLQUFLLElBQUksV0FBVyxDQUFDO0lBQ3ZCLENBQUM7SUFFRCwwQ0FBMEM7SUFDMUMsSUFBSSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDbEIsTUFBTSxhQUFhLEdBQTJCLEVBQUUsQ0FBQztRQUNqRCxLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUN6RCxhQUFhLENBQUMsR0FBRyxDQUFDLEdBQUcsS0FBSyxZQUFZLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO1FBQ3RFLENBQUM7UUFDRCxLQUFLLElBQUksYUFBYSxDQUFDLG9CQUFvQixDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFRCxrQ0FBa0M7SUFDbEMsSUFBSSxLQUFLLENBQUMsUUFBUSxJQUFJLEtBQUssQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ2hELDJDQUEyQztRQUMzQyxLQUFLLElBQUksU0FBUyxDQUFDLG9CQUFvQixDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBRUQsdUNBQXVDO0lBQ3ZDLElBQUksS0FBSyxDQUFDLFVBQVUsSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUNwRCxLQUFLLElBQUksS0FBSyxDQUFDLFVBQVUsQ0FBQyxNQUFNLEdBQUcsRUFBRSxDQUFDO0lBQ3hDLENBQUM7SUFFRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMifQ==
@@ -0,0 +1,30 @@
1
+ import type { IRouteConfig } from '../../proxies/smart-proxy/models/route-types.js';
2
+ import type { IRouteSpecificity } from './types.js';
3
+ /**
4
+ * Unified route specificity calculator
5
+ * Provides consistent specificity scoring across all routing components
6
+ */
7
+ export declare class RouteSpecificity {
8
+ /**
9
+ * Calculate the total specificity score for a route
10
+ * Higher scores indicate more specific routes that should match first
11
+ */
12
+ static calculate(route: IRouteConfig): IRouteSpecificity;
13
+ /**
14
+ * Compare two routes and determine which is more specific
15
+ * @returns positive if route1 is more specific, negative if route2 is more specific, 0 if equal
16
+ */
17
+ static compare(route1: IRouteConfig, route2: IRouteConfig): number;
18
+ /**
19
+ * Sort routes by specificity (most specific first)
20
+ */
21
+ static sort(routes: IRouteConfig[]): IRouteConfig[];
22
+ /**
23
+ * Find the most specific route from a list
24
+ */
25
+ static findMostSpecific(routes: IRouteConfig[]): IRouteConfig | null;
26
+ /**
27
+ * Check if a route has any matching criteria
28
+ */
29
+ static hasMatchCriteria(route: IRouteConfig): boolean;
30
+ }
@@ -0,0 +1,115 @@
1
+ import { DomainMatcher, PathMatcher, IpMatcher, HeaderMatcher } from './matchers/index.js';
2
+ /**
3
+ * Unified route specificity calculator
4
+ * Provides consistent specificity scoring across all routing components
5
+ */
6
+ export class RouteSpecificity {
7
+ /**
8
+ * Calculate the total specificity score for a route
9
+ * Higher scores indicate more specific routes that should match first
10
+ */
11
+ static calculate(route) {
12
+ const specificity = {
13
+ pathSpecificity: 0,
14
+ domainSpecificity: 0,
15
+ ipSpecificity: 0,
16
+ headerSpecificity: 0,
17
+ tlsSpecificity: 0,
18
+ totalScore: 0
19
+ };
20
+ // Path specificity
21
+ if (route.match.path) {
22
+ specificity.pathSpecificity = PathMatcher.calculateSpecificity(route.match.path);
23
+ }
24
+ // Domain specificity
25
+ if (route.match.domains) {
26
+ const domains = Array.isArray(route.match.domains)
27
+ ? route.match.domains
28
+ : [route.match.domains];
29
+ // Use the highest specificity among all domains
30
+ specificity.domainSpecificity = Math.max(...domains.map(d => DomainMatcher.calculateSpecificity(d)));
31
+ }
32
+ // IP specificity (clientIp is an array of IPs)
33
+ if (route.match.clientIp && route.match.clientIp.length > 0) {
34
+ // Use the first IP pattern for specificity calculation
35
+ specificity.ipSpecificity = IpMatcher.calculateSpecificity(route.match.clientIp[0]);
36
+ }
37
+ // Header specificity (convert RegExp values to strings)
38
+ if (route.match.headers) {
39
+ const stringHeaders = {};
40
+ for (const [key, value] of Object.entries(route.match.headers)) {
41
+ stringHeaders[key] = value instanceof RegExp ? value.source : value;
42
+ }
43
+ specificity.headerSpecificity = HeaderMatcher.calculateSpecificity(stringHeaders);
44
+ }
45
+ // TLS version specificity
46
+ if (route.match.tlsVersion && route.match.tlsVersion.length > 0) {
47
+ specificity.tlsSpecificity = route.match.tlsVersion.length * 10;
48
+ }
49
+ // Calculate total score with weights
50
+ specificity.totalScore =
51
+ specificity.pathSpecificity * 3 + // Path is most important
52
+ specificity.domainSpecificity * 2 + // Domain is second
53
+ specificity.ipSpecificity * 1.5 + // IP is moderately important
54
+ specificity.headerSpecificity * 1 + // Headers are less important
55
+ specificity.tlsSpecificity * 0.5; // TLS is least important
56
+ return specificity;
57
+ }
58
+ /**
59
+ * Compare two routes and determine which is more specific
60
+ * @returns positive if route1 is more specific, negative if route2 is more specific, 0 if equal
61
+ */
62
+ static compare(route1, route2) {
63
+ const spec1 = this.calculate(route1);
64
+ const spec2 = this.calculate(route2);
65
+ // First compare by total score
66
+ if (spec1.totalScore !== spec2.totalScore) {
67
+ return spec1.totalScore - spec2.totalScore;
68
+ }
69
+ // If total scores are equal, compare by individual components
70
+ // Path is most important tiebreaker
71
+ if (spec1.pathSpecificity !== spec2.pathSpecificity) {
72
+ return spec1.pathSpecificity - spec2.pathSpecificity;
73
+ }
74
+ // Then domain
75
+ if (spec1.domainSpecificity !== spec2.domainSpecificity) {
76
+ return spec1.domainSpecificity - spec2.domainSpecificity;
77
+ }
78
+ // Then IP
79
+ if (spec1.ipSpecificity !== spec2.ipSpecificity) {
80
+ return spec1.ipSpecificity - spec2.ipSpecificity;
81
+ }
82
+ // Then headers
83
+ if (spec1.headerSpecificity !== spec2.headerSpecificity) {
84
+ return spec1.headerSpecificity - spec2.headerSpecificity;
85
+ }
86
+ // Finally TLS
87
+ return spec1.tlsSpecificity - spec2.tlsSpecificity;
88
+ }
89
+ /**
90
+ * Sort routes by specificity (most specific first)
91
+ */
92
+ static sort(routes) {
93
+ return [...routes].sort((a, b) => this.compare(b, a));
94
+ }
95
+ /**
96
+ * Find the most specific route from a list
97
+ */
98
+ static findMostSpecific(routes) {
99
+ if (routes.length === 0)
100
+ return null;
101
+ return routes.reduce((most, current) => this.compare(current, most) > 0 ? current : most);
102
+ }
103
+ /**
104
+ * Check if a route has any matching criteria
105
+ */
106
+ static hasMatchCriteria(route) {
107
+ const match = route.match;
108
+ return !!(match.domains ||
109
+ match.path ||
110
+ match.clientIp?.length ||
111
+ match.headers ||
112
+ match.tlsVersion?.length);
113
+ }
114
+ }
115
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BlY2lmaWNpdHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9jb3JlL3JvdXRpbmcvc3BlY2lmaWNpdHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLGFBQWEsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRTNGOzs7R0FHRztBQUNILE1BQU0sT0FBTyxnQkFBZ0I7SUFDM0I7OztPQUdHO0lBQ0gsTUFBTSxDQUFDLFNBQVMsQ0FBQyxLQUFtQjtRQUNsQyxNQUFNLFdBQVcsR0FBc0I7WUFDckMsZUFBZSxFQUFFLENBQUM7WUFDbEIsaUJBQWlCLEVBQUUsQ0FBQztZQUNwQixhQUFhLEVBQUUsQ0FBQztZQUNoQixpQkFBaUIsRUFBRSxDQUFDO1lBQ3BCLGNBQWMsRUFBRSxDQUFDO1lBQ2pCLFVBQVUsRUFBRSxDQUFDO1NBQ2QsQ0FBQztRQUVGLG1CQUFtQjtRQUNuQixJQUFJLEtBQUssQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDckIsV0FBVyxDQUFDLGVBQWUsR0FBRyxXQUFXLENBQUMsb0JBQW9CLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNuRixDQUFDO1FBRUQscUJBQXFCO1FBQ3JCLElBQUksS0FBSyxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUN4QixNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDO2dCQUNoRCxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxPQUFPO2dCQUNyQixDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBRTFCLGdEQUFnRDtZQUNoRCxXQUFXLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FDdEMsR0FBRyxPQUFPLENBQUMs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
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Core routing types used throughout the routing system
3
+ */
4
+ export interface IPathMatchResult {
5
+ matches: boolean;
6
+ params?: Record<string, string>;
7
+ pathMatch?: string;
8
+ pathRemainder?: string;
9
+ }
10
+ export interface IRouteMatchResult {
11
+ matches: boolean;
12
+ score: number;
13
+ specificity: number;
14
+ matchedCriteria: string[];
15
+ }
16
+ export interface IDomainMatchOptions {
17
+ allowWildcards?: boolean;
18
+ caseInsensitive?: boolean;
19
+ }
20
+ export interface IIpMatchOptions {
21
+ allowCidr?: boolean;
22
+ allowRanges?: boolean;
23
+ }
24
+ export interface IHeaderMatchOptions {
25
+ caseInsensitive?: boolean;
26
+ exactMatch?: boolean;
27
+ }
28
+ export interface IRouteSpecificity {
29
+ pathSpecificity: number;
30
+ domainSpecificity: number;
31
+ ipSpecificity: number;
32
+ headerSpecificity: number;
33
+ tlsSpecificity: number;
34
+ totalScore: number;
35
+ }
36
+ export interface IMatcher<T = any, O = any> {
37
+ match(pattern: string, value: string, options?: O): T | boolean;
38
+ }
39
+ export interface IAsyncMatcher<T = any, O = any> {
40
+ match(pattern: string, value: string, options?: O): Promise<T | boolean>;
41
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Core routing types used throughout the routing system
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9jb3JlL3JvdXRpbmcvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUcifQ==