@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,169 @@
1
+ /**
2
+ * IpMatcher provides comprehensive IP address matching functionality
3
+ * Supporting exact matches, CIDR notation, ranges, and wildcards
4
+ */
5
+ export class IpMatcher {
6
+ /**
7
+ * Check if a value is a valid IPv4 address
8
+ */
9
+ static isValidIpv4(ip) {
10
+ const parts = ip.split('.');
11
+ if (parts.length !== 4)
12
+ return false;
13
+ return parts.every(part => {
14
+ const num = parseInt(part, 10);
15
+ return !isNaN(num) && num >= 0 && num <= 255 && part === num.toString();
16
+ });
17
+ }
18
+ /**
19
+ * Check if a value is a valid IPv6 address (simplified check)
20
+ */
21
+ static isValidIpv6(ip) {
22
+ // Basic IPv6 validation - can be enhanced
23
+ const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|(([0-9a-fA-F]{1,4}:){1,7}|:):|(([0-9a-fA-F]{1,4}:){1,6}|::):[0-9a-fA-F]{1,4})$/;
24
+ return ipv6Regex.test(ip);
25
+ }
26
+ /**
27
+ * Convert IP address to numeric value for comparison
28
+ */
29
+ static ipToNumber(ip) {
30
+ const parts = ip.split('.');
31
+ return parts.reduce((acc, part, index) => {
32
+ return acc + (parseInt(part, 10) << (8 * (3 - index)));
33
+ }, 0);
34
+ }
35
+ /**
36
+ * Match an IP against a CIDR notation pattern
37
+ */
38
+ static matchCidr(cidr, ip) {
39
+ const [range, bits] = cidr.split('/');
40
+ if (!bits || !this.isValidIpv4(range) || !this.isValidIpv4(ip)) {
41
+ return false;
42
+ }
43
+ const rangeMask = parseInt(bits, 10);
44
+ if (isNaN(rangeMask) || rangeMask < 0 || rangeMask > 32) {
45
+ return false;
46
+ }
47
+ const rangeNum = this.ipToNumber(range);
48
+ const ipNum = this.ipToNumber(ip);
49
+ const mask = (-1 << (32 - rangeMask)) >>> 0;
50
+ return (rangeNum & mask) === (ipNum & mask);
51
+ }
52
+ /**
53
+ * Match an IP against a wildcard pattern
54
+ */
55
+ static matchWildcard(pattern, ip) {
56
+ if (!this.isValidIpv4(ip))
57
+ return false;
58
+ const patternParts = pattern.split('.');
59
+ const ipParts = ip.split('.');
60
+ if (patternParts.length !== 4)
61
+ return false;
62
+ return patternParts.every((part, index) => {
63
+ if (part === '*')
64
+ return true;
65
+ return part === ipParts[index];
66
+ });
67
+ }
68
+ /**
69
+ * Match an IP against a range (e.g., "192.168.1.1-192.168.1.100")
70
+ */
71
+ static matchRange(range, ip) {
72
+ const [start, end] = range.split('-').map(s => s.trim());
73
+ if (!start || !end || !this.isValidIpv4(start) || !this.isValidIpv4(end) || !this.isValidIpv4(ip)) {
74
+ return false;
75
+ }
76
+ const startNum = this.ipToNumber(start);
77
+ const endNum = this.ipToNumber(end);
78
+ const ipNum = this.ipToNumber(ip);
79
+ return ipNum >= startNum && ipNum <= endNum;
80
+ }
81
+ /**
82
+ * Match an IP pattern against an IP address
83
+ * Supports multiple formats:
84
+ * - Exact match: "192.168.1.1"
85
+ * - CIDR: "192.168.1.0/24"
86
+ * - Wildcard: "192.168.1.*"
87
+ * - Range: "192.168.1.1-192.168.1.100"
88
+ */
89
+ static match(pattern, ip, options = {}) {
90
+ // Handle null/undefined cases
91
+ if (!pattern || !ip) {
92
+ return false;
93
+ }
94
+ // Normalize inputs
95
+ const normalizedPattern = pattern.trim();
96
+ const normalizedIp = ip.trim();
97
+ // Extract IPv4 from IPv6-mapped addresses (::ffff:192.168.1.1)
98
+ const ipv4Match = normalizedIp.match(/::ffff:(\d+\.\d+\.\d+\.\d+)/i);
99
+ const testIp = ipv4Match ? ipv4Match[1] : normalizedIp;
100
+ // Exact match
101
+ if (normalizedPattern === testIp) {
102
+ return true;
103
+ }
104
+ // CIDR notation
105
+ if (options.allowCidr !== false && normalizedPattern.includes('/')) {
106
+ return this.matchCidr(normalizedPattern, testIp);
107
+ }
108
+ // Wildcard matching
109
+ if (normalizedPattern.includes('*')) {
110
+ return this.matchWildcard(normalizedPattern, testIp);
111
+ }
112
+ // Range matching
113
+ if (options.allowRanges !== false && normalizedPattern.includes('-')) {
114
+ return this.matchRange(normalizedPattern, testIp);
115
+ }
116
+ return false;
117
+ }
118
+ /**
119
+ * Check if an IP is authorized based on allow and block lists
120
+ */
121
+ static isAuthorized(ip, allowList = [], blockList = []) {
122
+ // If IP is in block list, deny
123
+ if (blockList.some(pattern => this.match(pattern, ip))) {
124
+ return false;
125
+ }
126
+ // If allow list is empty, allow all (except blocked)
127
+ if (allowList.length === 0) {
128
+ return true;
129
+ }
130
+ // If allow list exists, IP must match
131
+ return allowList.some(pattern => this.match(pattern, ip));
132
+ }
133
+ /**
134
+ * Calculate the specificity of an IP pattern
135
+ * Higher values mean more specific patterns
136
+ */
137
+ static calculateSpecificity(pattern) {
138
+ if (!pattern)
139
+ return 0;
140
+ let score = 0;
141
+ // Exact IPs are most specific
142
+ if (this.isValidIpv4(pattern) || this.isValidIpv6(pattern)) {
143
+ score += 100;
144
+ }
145
+ // CIDR notation
146
+ if (pattern.includes('/')) {
147
+ const [, bits] = pattern.split('/');
148
+ const maskBits = parseInt(bits, 10);
149
+ if (!isNaN(maskBits)) {
150
+ score += maskBits; // Higher mask = more specific
151
+ }
152
+ }
153
+ // Wildcard patterns
154
+ const wildcards = (pattern.match(/\*/g) || []).length;
155
+ score -= wildcards * 20; // More wildcards = less specific
156
+ // Range patterns are somewhat specific
157
+ if (pattern.includes('-')) {
158
+ score += 30;
159
+ }
160
+ return score;
161
+ }
162
+ /**
163
+ * Instance method for interface compliance
164
+ */
165
+ match(pattern, ip, options) {
166
+ return IpMatcher.match(pattern, ip, options);
167
+ }
168
+ }
169
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9jb3JlL3JvdXRpbmcvbWF0Y2hlcnMvaXAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUE7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLFNBQVM7SUFDcEI7O09BRUc7SUFDSCxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQVU7UUFDM0IsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM1QixJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE9BQU8sS0FBSyxDQUFDO1FBRXJDLE9BQU8sS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUN4QixNQUFNLEdBQUcsR0FBRyxRQUFRLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQy9CLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksR0FBRyxJQUFJLElBQUksS0FBSyxHQUFHLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDMUUsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQVU7UUFDM0IsMENBQTBDO1FBQzFDLE1BQU0sU0FBUyxHQUFHLDRIQUE0SCxDQUFDO1FBQy9JLE9BQU8sU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUM1QixDQUFDO0lBRUQ7O09BRUc7SUFDSyxNQUFNLENBQUMsVUFBVSxDQUFDLEVBQVU7UUFDbEMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM1QixPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ3ZDLE9BQU8sR0FBRyxHQUFHLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDekQsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ1IsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLFNBQVMsQ0FBQyxJQUFZLEVBQUUsRUFBVTtRQUN2QyxNQUFNLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDdEMsSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7WUFDL0QsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO1FBRUQsTUFBTSxTQUFTLEdBQUcsUUFBUSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNyQyxJQUFJLEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBSSxTQUFTLEdBQUcsQ0FBQyxJQUFJLFNBQVMsR0FBRyxFQUFFLEVBQUUsQ0FBQztZQUN4RCxPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFFRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3hDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDbEMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUU1QyxPQUFPLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQzlDLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxhQUFhLENBQUMsT0FBZSxFQUFFLEVBQVU7UUFDOUMsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFFeEMsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN4QyxNQUFNLE9BQU8sR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBRTlCLElBQUksWUFBWSxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFFNUMsT0FBTyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ3hDLElBQUksSUFBSSxLQUFLLEdBQUc7Z0JBQUUsT0FBTyxJQUFJLENBQUM7WUFDOUIsT0FBTyxJQUFJLEtBQUssT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2pDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLFVBQVUsQ0FBQyxLQUFhLEVBQUUsRUFBVTtRQUN6QyxNQUFNLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFFekQsSUFBSSxDQUFDLEtBQUssSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO1lBQ2xHLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztRQUVELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDeEMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNwQyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRWxDLE9BQU8sS0FBSyxJQUFJLFFBQVEsSUFBSSxLQUFLLElBQUksTUFBTSxDQUFDO0lBQzlDLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FDVixPQUFlLEVBQ2YsRUFBVSxFQUNWLFVBQTJCLEVBQUU7UUFFN0IsOEJBQThCO1FBQzlCLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNwQixPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFFRCxtQkFBbUI7UUFDbkIsTUFBTSxpQkFBaUIsR0FBRyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDekMsTUFBTSxZQUFZLEdBQUcsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDO1FBRS9CLCtEQUErRDtRQUMvRCxNQUFNLFNBQVMsR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDLDhCQUE4QixDQUFDLENBQUM7UUFDckUsTUFBTSxNQUFNLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQztRQUV2RCxjQUFjO1FBQ2QsSUFBSSxpQkFBaUIsS0FBSyxNQUFNLEVBQUUsQ0FBQztZQUNqQyxPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFFRCxnQkFBZ0I7UUFDaEIsSUFBSSxPQUFPLENBQUMsU0FBUyxLQUFLLEtBQUssSUFBSSxpQkFBaUIsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNuRSxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsaUJBQWlCLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDbkQsQ0FBQztRQUVELG9CQUFvQjtRQUNwQixJQUFJLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3BDLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQyxpQkFBaUIsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUN2RCxDQUFDO1FBRUQsaUJBQWlCO1FBQ2pCLElBQUksT0FBTyxDQUFDLFdBQVcsS0FBSyxLQUFLLElBQUksaUJBQWlCLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDckUsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFFRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxZQUFZLENBQ2pCLEVBQVUsRUFDVixZQUFzQixFQUFFLEVBQ3hCLFlBQXNCLEVBQUU7UUFFeEIsK0JBQStCO1FBQy9CLElBQUksU0FBUyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUN2RCxPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFFRCxxREFBcUQ7UUFDckQsSUFBSSxTQUFTLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzNCLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELHNDQUFzQztRQUN0QyxPQUFPLFNBQVMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzVELENBQUM7SUFFRDs7O09BR0c7SUFDSCxNQUFNLENBQUMsb0JBQW9CLENBQUMsT0FBZTtRQUN6QyxJQUFJLENBQUMsT0FBTztZQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRXZCLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztRQUVkLDhCQUE4QjtRQUM5QixJQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLElBQUksSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQzNELEtBQUssSUFBSSxHQUFHLENBQUM7UUFDZixDQUFDO1FBRUQsZ0JBQWdCO1FBQ2hCLElBQUksT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzFCLE1BQU0sQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDcEMsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztZQUNwQyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7Z0JBQ3JCLEtBQUssSUFBSSxRQUFRLENBQUMsQ0FBQyw4QkFBOEI7WUFDbkQsQ0FBQztRQUNILENBQUM7UUFFRCxvQkFBb0I7UUFDcEIsTUFBTSxTQUFTLEdBQUcsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQztRQUN0RCxLQUFLLElBQUksU0FBUyxHQUFHLEVBQUUsQ0FBQyxDQUFDLGlDQUFpQztRQUUxRCx1Q0FBdUM7UUFDdkMsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDMUIsS0FBSyxJQUFJLEVBQUUsQ0FBQztRQUNkLENBQUM7UUFFRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxPQUFlLEVBQUUsRUFBVSxFQUFFLE9BQXlCO1FBQzFELE9BQU8sU0FBUyxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsRUFBRSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQy9DLENBQUM7Q0FDRiJ9
@@ -0,0 +1,44 @@
1
+ import type { IMatcher, IPathMatchResult } from '../types.js';
2
+ /**
3
+ * PathMatcher provides comprehensive path matching functionality
4
+ * Supporting exact matches, wildcards, and parameter extraction
5
+ */
6
+ export declare class PathMatcher implements IMatcher<IPathMatchResult> {
7
+ /**
8
+ * Convert a path pattern to a regex and extract parameter names
9
+ * Supports:
10
+ * - Exact paths: /api/users
11
+ * - Wildcards: /api/*
12
+ * - Parameters: /api/users/:id
13
+ * - Mixed: /api/users/:id/*
14
+ */
15
+ private static patternToRegex;
16
+ /**
17
+ * Match a path pattern against a request path
18
+ * @param pattern The pattern to match
19
+ * @param path The request path to test
20
+ * @returns Match result with params and remainder
21
+ */
22
+ static match(pattern: string, path: string): IPathMatchResult;
23
+ /**
24
+ * Check if a pattern contains parameters or wildcards
25
+ */
26
+ static isDynamicPattern(pattern: string): boolean;
27
+ /**
28
+ * Calculate the specificity of a path pattern
29
+ * Higher values mean more specific patterns
30
+ */
31
+ static calculateSpecificity(pattern: string): number;
32
+ /**
33
+ * Find all matching patterns from a list
34
+ * Returns patterns sorted by specificity (most specific first)
35
+ */
36
+ static findAllMatches(patterns: string[], path: string): Array<{
37
+ pattern: string;
38
+ result: IPathMatchResult;
39
+ }>;
40
+ /**
41
+ * Instance method for interface compliance
42
+ */
43
+ match(pattern: string, path: string): IPathMatchResult;
44
+ }
@@ -0,0 +1,148 @@
1
+ /**
2
+ * PathMatcher provides comprehensive path matching functionality
3
+ * Supporting exact matches, wildcards, and parameter extraction
4
+ */
5
+ export class PathMatcher {
6
+ /**
7
+ * Convert a path pattern to a regex and extract parameter names
8
+ * Supports:
9
+ * - Exact paths: /api/users
10
+ * - Wildcards: /api/*
11
+ * - Parameters: /api/users/:id
12
+ * - Mixed: /api/users/:id/*
13
+ */
14
+ static patternToRegex(pattern) {
15
+ const paramNames = [];
16
+ let regexPattern = pattern;
17
+ // Escape special regex characters except : and *
18
+ regexPattern = regexPattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
19
+ // Handle path parameters (:param)
20
+ regexPattern = regexPattern.replace(/:(\w+)/g, (match, paramName) => {
21
+ paramNames.push(paramName);
22
+ return '([^/]+)'; // Match any non-slash characters
23
+ });
24
+ // Handle wildcards
25
+ regexPattern = regexPattern.replace(/\*/g, '(.*)');
26
+ // Ensure the pattern matches from start
27
+ regexPattern = `^${regexPattern}`;
28
+ // If pattern doesn't end with wildcard, ensure it matches to end
29
+ // But only for patterns that don't have parameters or wildcards
30
+ if (!pattern.includes('*') && !pattern.includes(':') && !pattern.endsWith('/')) {
31
+ regexPattern = `${regexPattern}$`;
32
+ }
33
+ return {
34
+ regex: new RegExp(regexPattern),
35
+ paramNames
36
+ };
37
+ }
38
+ /**
39
+ * Match a path pattern against a request path
40
+ * @param pattern The pattern to match
41
+ * @param path The request path to test
42
+ * @returns Match result with params and remainder
43
+ */
44
+ static match(pattern, path) {
45
+ // Handle null/undefined cases
46
+ if (!pattern || !path) {
47
+ return { matches: false };
48
+ }
49
+ // Normalize paths (remove trailing slashes unless it's just "/")
50
+ const normalizedPattern = pattern === '/' ? '/' : pattern.replace(/\/$/, '');
51
+ const normalizedPath = path === '/' ? '/' : path.replace(/\/$/, '');
52
+ // Exact match (most common case)
53
+ if (normalizedPattern === normalizedPath) {
54
+ return {
55
+ matches: true,
56
+ pathMatch: normalizedPath,
57
+ pathRemainder: '',
58
+ params: {}
59
+ };
60
+ }
61
+ // Pattern matching (wildcards and parameters)
62
+ const { regex, paramNames } = this.patternToRegex(normalizedPattern);
63
+ const match = normalizedPath.match(regex);
64
+ if (!match) {
65
+ return { matches: false };
66
+ }
67
+ // Extract parameters
68
+ const params = {};
69
+ paramNames.forEach((name, index) => {
70
+ params[name] = match[index + 1];
71
+ });
72
+ // Calculate path match and remainder
73
+ let pathMatch = match[0];
74
+ let pathRemainder = normalizedPath.substring(pathMatch.length);
75
+ // Handle wildcard captures
76
+ if (normalizedPattern.includes('*') && match.length > paramNames.length + 1) {
77
+ const wildcardCapture = match[match.length - 1];
78
+ if (wildcardCapture) {
79
+ pathRemainder = wildcardCapture;
80
+ pathMatch = normalizedPath.substring(0, normalizedPath.length - wildcardCapture.length);
81
+ }
82
+ }
83
+ // Clean up path match (remove trailing slash if present)
84
+ if (pathMatch !== '/' && pathMatch.endsWith('/')) {
85
+ pathMatch = pathMatch.slice(0, -1);
86
+ }
87
+ return {
88
+ matches: true,
89
+ pathMatch,
90
+ pathRemainder,
91
+ params
92
+ };
93
+ }
94
+ /**
95
+ * Check if a pattern contains parameters or wildcards
96
+ */
97
+ static isDynamicPattern(pattern) {
98
+ return pattern.includes(':') || pattern.includes('*');
99
+ }
100
+ /**
101
+ * Calculate the specificity of a path pattern
102
+ * Higher values mean more specific patterns
103
+ */
104
+ static calculateSpecificity(pattern) {
105
+ if (!pattern)
106
+ return 0;
107
+ let score = 0;
108
+ // Exact paths are most specific
109
+ if (!this.isDynamicPattern(pattern)) {
110
+ score += 100;
111
+ }
112
+ // Count path segments
113
+ const segments = pattern.split('/').filter(s => s.length > 0);
114
+ score += segments.length * 10;
115
+ // Count static segments (more static = more specific)
116
+ const staticSegments = segments.filter(s => !s.startsWith(':') && s !== '*');
117
+ score += staticSegments.length * 20;
118
+ // Penalize wildcards and parameters
119
+ const wildcards = (pattern.match(/\*/g) || []).length;
120
+ const params = (pattern.match(/:/g) || []).length;
121
+ score -= wildcards * 30; // Wildcards are very generic
122
+ score -= params * 10; // Parameters are somewhat generic
123
+ // Bonus for longer patterns
124
+ score += pattern.length;
125
+ return score;
126
+ }
127
+ /**
128
+ * Find all matching patterns from a list
129
+ * Returns patterns sorted by specificity (most specific first)
130
+ */
131
+ static findAllMatches(patterns, path) {
132
+ const matches = patterns
133
+ .map(pattern => ({
134
+ pattern,
135
+ result: this.match(pattern, path)
136
+ }))
137
+ .filter(({ result }) => result.matches);
138
+ // Sort by specificity (highest first)
139
+ return matches.sort((a, b) => this.calculateSpecificity(b.pattern) - this.calculateSpecificity(a.pattern));
140
+ }
141
+ /**
142
+ * Instance method for interface compliance
143
+ */
144
+ match(pattern, path) {
145
+ return PathMatcher.match(pattern, path);
146
+ }
147
+ }
148
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL2NvcmUvcm91dGluZy9tYXRjaGVycy9wYXRoLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBOzs7R0FHRztBQUNILE1BQU0sT0FBTyxXQUFXO0lBQ3RCOzs7Ozs7O09BT0c7SUFDSyxNQUFNLENBQUMsY0FBYyxDQUFDLE9BQWU7UUFJM0MsTUFBTSxVQUFVLEdBQWEsRUFBRSxDQUFDO1FBQ2hDLElBQUksWUFBWSxHQUFHLE9BQU8sQ0FBQztRQUUzQixpREFBaUQ7UUFDakQsWUFBWSxHQUFHLFlBQVksQ0FBQyxPQUFPLENBQUMsb0JBQW9CLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFbEUsa0NBQWtDO1FBQ2xDLFlBQVksR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxDQUFDLEtBQUssRUFBRSxTQUFTLEVBQUUsRUFBRTtZQUNsRSxVQUFVLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQzNCLE9BQU8sU0FBUyxDQUFDLENBQUMsaUNBQWlDO1FBQ3JELENBQUMsQ0FBQyxDQUFDO1FBRUgsbUJBQW1CO1FBQ25CLFlBQVksR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztRQUVuRCx3Q0FBd0M7UUFDeEMsWUFBWSxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFFbEMsaUVBQWlFO1FBQ2pFLGdFQUFnRTtRQUNoRSxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDL0UsWUFBWSxHQUFHLEdBQUcsWUFBWSxHQUFHLENBQUM7UUFDcEMsQ0FBQztRQUVELE9BQU87WUFDTCxLQUFLLEVBQUUsSUFBSSxNQUFNLENBQUMs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
@@ -0,0 +1,88 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { IRouteConfig, TPortRange, IRouteContext } from '../../proxies/smart-proxy/models/route-types.js';
3
+ /**
4
+ * Result of route lookup
5
+ */
6
+ export interface IRouteLookupResult {
7
+ route: IRouteConfig;
8
+ params?: Record<string, string>;
9
+ }
10
+ /**
11
+ * Logger interface for RouteManager
12
+ */
13
+ export interface ILogger {
14
+ info: (message: string, ...args: any[]) => void;
15
+ warn: (message: string, ...args: any[]) => void;
16
+ error: (message: string, ...args: any[]) => void;
17
+ debug?: (message: string, ...args: any[]) => void;
18
+ }
19
+ /**
20
+ * Shared RouteManager used by both SmartProxy and NetworkProxy
21
+ *
22
+ * This provides a unified implementation for route management,
23
+ * route matching, and port handling.
24
+ */
25
+ export declare class SharedRouteManager extends plugins.EventEmitter {
26
+ private routes;
27
+ private portMap;
28
+ private logger;
29
+ private enableDetailedLogging;
30
+ /**
31
+ * Memoization cache for expanded port ranges
32
+ */
33
+ private portRangeCache;
34
+ constructor(options: {
35
+ logger?: ILogger;
36
+ enableDetailedLogging?: boolean;
37
+ routes?: IRouteConfig[];
38
+ });
39
+ /**
40
+ * Update routes with new configuration
41
+ */
42
+ updateRoutes(routes?: IRouteConfig[]): void;
43
+ /**
44
+ * Get all routes
45
+ */
46
+ getRoutes(): IRouteConfig[];
47
+ /**
48
+ * Rebuild the port mapping for fast lookups
49
+ * Also logs information about the ports being listened on
50
+ */
51
+ private rebuildPortMap;
52
+ /**
53
+ * Expand a port range specification into an array of individual ports
54
+ * Uses caching to improve performance for frequently used port ranges
55
+ *
56
+ * @public - Made public to allow external code to interpret port ranges
57
+ */
58
+ expandPortRange(portRange: TPortRange): number[];
59
+ /**
60
+ * Get all ports that should be listened on
61
+ * This method automatically infers all required ports from route configurations
62
+ */
63
+ getListeningPorts(): number[];
64
+ /**
65
+ * Get all routes for a given port
66
+ */
67
+ getRoutesForPort(port: number): IRouteConfig[];
68
+ /**
69
+ * Find the matching route for a connection
70
+ */
71
+ findMatchingRoute(context: IRouteContext): IRouteLookupResult | null;
72
+ /**
73
+ * Check if a route matches the given context
74
+ */
75
+ private matchesRoute;
76
+ /**
77
+ * Validate the route configuration and return any warnings
78
+ */
79
+ validateConfiguration(): string[];
80
+ /**
81
+ * Check if two route matches are similar (potential conflict)
82
+ */
83
+ private areMatchesSimilar;
84
+ /**
85
+ * Check if a route is completely shadowed by a higher priority route
86
+ */
87
+ private isRouteShadowed;
88
+ }