@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,341 @@
1
+ # SmartProxy Routing Architecture Unification Plan
2
+
3
+ ## Overview
4
+ This document analyzes the current state of routing in SmartProxy, identifies redundancies and inconsistencies, and proposes a unified architecture.
5
+
6
+ ## Current State Analysis
7
+
8
+ ### 1. Multiple Route Manager Implementations
9
+
10
+ #### 1.1 Core SharedRouteManager (`ts/core/utils/route-manager.ts`)
11
+ - **Purpose**: Designed as a shared component for SmartProxy and NetworkProxy
12
+ - **Features**:
13
+ - Port mapping and expansion (e.g., `[80, 443]` → individual routes)
14
+ - Comprehensive route matching (domain, path, IP, headers, TLS)
15
+ - Route validation and conflict detection
16
+ - Event emitter for route changes
17
+ - Detailed logging support
18
+ - **Status**: Well-designed but underutilized
19
+
20
+ #### 1.2 SmartProxy RouteManager (`ts/proxies/smart-proxy/route-manager.ts`)
21
+ - **Purpose**: SmartProxy-specific route management
22
+ - **Issues**:
23
+ - 95% duplicate code from SharedRouteManager
24
+ - Only difference is using `ISmartProxyOptions` instead of generic interface
25
+ - Contains deprecated security methods
26
+ - Unnecessary code duplication
27
+ - **Status**: Should be removed in favor of SharedRouteManager
28
+
29
+ #### 1.3 HttpProxy Route Management (`ts/proxies/http-proxy/`)
30
+ - **Purpose**: HTTP-specific routing
31
+ - **Implementation**: Minimal, inline route matching
32
+ - **Status**: Could benefit from SharedRouteManager
33
+
34
+ ### 2. Multiple Router Implementations
35
+
36
+ #### 2.1 ProxyRouter (`ts/routing/router/proxy-router.ts`)
37
+ - **Purpose**: Legacy compatibility with `IReverseProxyConfig`
38
+ - **Features**: Domain-based routing with path patterns
39
+ - **Used by**: HttpProxy for backward compatibility
40
+
41
+ #### 2.2 RouteRouter (`ts/routing/router/route-router.ts`)
42
+ - **Purpose**: Modern routing with `IRouteConfig`
43
+ - **Features**: Nearly identical to ProxyRouter
44
+ - **Issues**: Code duplication with ProxyRouter
45
+
46
+ ### 3. Scattered Route Utilities
47
+
48
+ #### 3.1 Core route-utils (`ts/core/utils/route-utils.ts`)
49
+ - **Purpose**: Shared matching functions
50
+ - **Features**: Domain, path, IP, CIDR matching
51
+ - **Status**: Well-implemented, should be the single source
52
+
53
+ #### 3.2 SmartProxy route-utils (`ts/proxies/smart-proxy/utils/route-utils.ts`)
54
+ - **Purpose**: Route configuration utilities
55
+ - **Features**: Different scope - config merging, not pattern matching
56
+ - **Status**: Keep separate as it serves different purpose
57
+
58
+ ### 4. Other Route-Related Files
59
+ - `route-patterns.ts`: Constants for route patterns
60
+ - `route-validators.ts`: Route configuration validation
61
+ - `route-helpers.ts`: Additional utilities
62
+ - `route-connection-handler.ts`: Connection routing logic
63
+
64
+ ## Problems Identified
65
+
66
+ ### 1. Code Duplication
67
+ - **SharedRouteManager vs SmartProxy RouteManager**: ~1000 lines of duplicate code
68
+ - **ProxyRouter vs RouteRouter**: ~500 lines of duplicate code
69
+ - **Matching logic**: Implemented in 4+ different places
70
+
71
+ ### 2. Inconsistent Implementations
72
+ ```typescript
73
+ // Example: Domain matching appears in multiple places
74
+ // 1. In route-utils.ts
75
+ export function matchDomain(pattern: string, hostname: string): boolean
76
+
77
+ // 2. In SmartProxy RouteManager
78
+ private matchDomain(domain: string, hostname: string): boolean
79
+
80
+ // 3. In ProxyRouter
81
+ private matchesHostname(configName: string, hostname: string): boolean
82
+
83
+ // 4. In RouteRouter
84
+ private matchDomain(pattern: string, hostname: string): boolean
85
+ ```
86
+
87
+ ### 3. Unclear Separation of Concerns
88
+ - Route Managers handle both storage AND matching
89
+ - Routers also handle storage AND matching
90
+ - No clear boundaries between layers
91
+
92
+ ### 4. Maintenance Burden
93
+ - Bug fixes need to be applied in multiple places
94
+ - New features must be implemented multiple times
95
+ - Testing effort multiplied
96
+
97
+ ## Proposed Unified Architecture
98
+
99
+ ### Layer 1: Core Routing Components
100
+ ```
101
+ ts/core/routing/
102
+ ├── types.ts # All route-related types
103
+ ├── utils.ts # All matching logic (consolidated)
104
+ ├── route-store.ts # Route storage and indexing
105
+ └── route-matcher.ts # Route matching engine
106
+ ```
107
+
108
+ ### Layer 2: Route Management
109
+ ```
110
+ ts/core/routing/
111
+ └── route-manager.ts # Single RouteManager for all proxies
112
+ - Uses RouteStore for storage
113
+ - Uses RouteMatcher for matching
114
+ - Provides high-level API
115
+ ```
116
+
117
+ ### Layer 3: HTTP Routing
118
+ ```
119
+ ts/routing/
120
+ └── http-router.ts # Single HTTP router implementation
121
+ - Uses RouteManager for route lookup
122
+ - Handles HTTP-specific concerns
123
+ - Legacy adapter built-in
124
+ ```
125
+
126
+ ### Layer 4: Proxy Integration
127
+ ```
128
+ ts/proxies/
129
+ ├── smart-proxy/
130
+ │ └── (uses core RouteManager directly)
131
+ ├── http-proxy/
132
+ │ └── (uses core RouteManager + HttpRouter)
133
+ └── network-proxy/
134
+ └── (uses core RouteManager directly)
135
+ ```
136
+
137
+ ## Implementation Plan
138
+
139
+ ### Phase 1: Consolidate Matching Logic (Week 1)
140
+ 1. **Audit all matching implementations**
141
+ - Document differences in behavior
142
+ - Identify the most comprehensive implementation
143
+ - Create test suite covering all edge cases
144
+
145
+ 2. **Create unified matching module**
146
+ ```typescript
147
+ // ts/core/routing/matchers.ts
148
+ export class DomainMatcher {
149
+ static match(pattern: string, hostname: string): boolean
150
+ }
151
+
152
+ export class PathMatcher {
153
+ static match(pattern: string, path: string): MatchResult
154
+ }
155
+
156
+ export class IpMatcher {
157
+ static match(pattern: string, ip: string): boolean
158
+ static matchCidr(cidr: string, ip: string): boolean
159
+ }
160
+ ```
161
+
162
+ 3. **Update all components to use unified matchers**
163
+ - Replace local implementations
164
+ - Ensure backward compatibility
165
+ - Run comprehensive tests
166
+
167
+ ### Phase 2: Unify Route Managers (Week 2)
168
+ 1. **Enhance SharedRouteManager**
169
+ - Add any missing features from SmartProxy RouteManager
170
+ - Make it truly generic (no proxy-specific dependencies)
171
+ - Add adapter pattern for different options types
172
+
173
+ 2. **Migrate SmartProxy to use SharedRouteManager**
174
+ ```typescript
175
+ // Before
176
+ this.routeManager = new RouteManager(this.settings);
177
+
178
+ // After
179
+ this.routeManager = new SharedRouteManager({
180
+ logger: this.settings.logger,
181
+ enableDetailedLogging: this.settings.enableDetailedLogging
182
+ });
183
+ ```
184
+
185
+ 3. **Remove duplicate RouteManager**
186
+ - Delete `ts/proxies/smart-proxy/route-manager.ts`
187
+ - Update all imports
188
+ - Verify all tests pass
189
+
190
+ ### Phase 3: Consolidate Routers (Week 3)
191
+ 1. **Create unified HttpRouter**
192
+ ```typescript
193
+ export class HttpRouter {
194
+ constructor(private routeManager: SharedRouteManager) {}
195
+
196
+ // Modern interface
197
+ route(req: IncomingMessage): RouteResult
198
+
199
+ // Legacy adapter
200
+ routeLegacy(config: IReverseProxyConfig): RouteResult
201
+ }
202
+ ```
203
+
204
+ 2. **Migrate HttpProxy**
205
+ - Replace both ProxyRouter and RouteRouter
206
+ - Use single HttpRouter with appropriate adapter
207
+ - Maintain backward compatibility
208
+
209
+ 3. **Clean up legacy code**
210
+ - Mark old interfaces as deprecated
211
+ - Add migration guides
212
+ - Plan removal in next major version
213
+
214
+ ### Phase 4: Architecture Cleanup (Week 4)
215
+ 1. **Reorganize file structure**
216
+ ```
217
+ ts/core/
218
+ ├── routing/
219
+ │ ├── index.ts
220
+ │ ├── types.ts
221
+ │ ├── matchers/
222
+ │ │ ├── domain.ts
223
+ │ │ ├── path.ts
224
+ │ │ ├── ip.ts
225
+ │ │ └── index.ts
226
+ │ ├── route-store.ts
227
+ │ ├── route-matcher.ts
228
+ │ └── route-manager.ts
229
+ └── utils/
230
+ └── (remove route-specific utils)
231
+ ```
232
+
233
+ 2. **Update documentation**
234
+ - Architecture diagrams
235
+ - Migration guides
236
+ - API documentation
237
+
238
+ 3. **Performance optimization**
239
+ - Add caching where beneficial
240
+ - Optimize hot paths
241
+ - Benchmark before/after
242
+
243
+ ## Migration Strategy
244
+
245
+ ### For SmartProxy RouteManager Users
246
+ ```typescript
247
+ // Old way
248
+ import { RouteManager } from './route-manager.js';
249
+ const manager = new RouteManager(options);
250
+
251
+ // New way
252
+ import { SharedRouteManager as RouteManager } from '../core/utils/route-manager.js';
253
+ const manager = new RouteManager({
254
+ logger: options.logger,
255
+ enableDetailedLogging: options.enableDetailedLogging
256
+ });
257
+ ```
258
+
259
+ ### For Router Users
260
+ ```typescript
261
+ // Old way
262
+ const proxyRouter = new ProxyRouter();
263
+ const routeRouter = new RouteRouter();
264
+
265
+ // New way
266
+ const router = new HttpRouter(routeManager);
267
+ // Automatically handles both modern and legacy configs
268
+ ```
269
+
270
+ ## Success Metrics
271
+
272
+ 1. **Code Reduction**
273
+ - Target: Remove ~1,500 lines of duplicate code
274
+ - Measure: Lines of code before/after
275
+
276
+ 2. **Performance**
277
+ - Target: No regression in routing performance
278
+ - Measure: Benchmark route matching operations
279
+
280
+ 3. **Maintainability**
281
+ - Target: Single implementation for each concept
282
+ - Measure: Time to implement new features
283
+
284
+ 4. **Test Coverage**
285
+ - Target: 100% coverage of routing logic
286
+ - Measure: Coverage reports
287
+
288
+ ## Risks and Mitigations
289
+
290
+ ### Risk 1: Breaking Changes
291
+ - **Mitigation**: Extensive adapter patterns and backward compatibility layers
292
+ - **Testing**: Run all existing tests plus new integration tests
293
+
294
+ ### Risk 2: Performance Regression
295
+ - **Mitigation**: Benchmark critical paths before changes
296
+ - **Testing**: Load testing with production-like scenarios
297
+
298
+ ### Risk 3: Hidden Dependencies
299
+ - **Mitigation**: Careful code analysis and dependency mapping
300
+ - **Testing**: Integration tests across all proxy types
301
+
302
+ ## Long-term Vision
303
+
304
+ ### Future Enhancements
305
+ 1. **Route Caching**: LRU cache for frequently accessed routes
306
+ 2. **Route Indexing**: Trie-based indexing for faster domain matching
307
+ 3. **Route Priorities**: Explicit priority system instead of specificity
308
+ 4. **Dynamic Routes**: Support for runtime route modifications
309
+ 5. **Route Templates**: Reusable route configurations
310
+
311
+ ### API Evolution
312
+ ```typescript
313
+ // Future unified routing API
314
+ const routingEngine = new RoutingEngine({
315
+ stores: [fileStore, dbStore, dynamicStore],
316
+ matchers: [domainMatcher, pathMatcher, customMatcher],
317
+ cache: new LRUCache({ max: 1000 }),
318
+ indexes: {
319
+ domain: new TrieIndex(),
320
+ path: new RadixTree()
321
+ }
322
+ });
323
+
324
+ // Simple, powerful API
325
+ const route = await routingEngine.findRoute({
326
+ domain: 'example.com',
327
+ path: '/api/v1/users',
328
+ ip: '192.168.1.1',
329
+ headers: { 'x-custom': 'value' }
330
+ });
331
+ ```
332
+
333
+ ## Conclusion
334
+
335
+ The current routing architecture has significant duplication and inconsistencies. By following this unification plan, we can:
336
+ 1. Reduce code by ~30%
337
+ 2. Improve maintainability
338
+ 3. Ensure consistent behavior
339
+ 4. Enable future enhancements
340
+
341
+ The phased approach minimizes risk while delivering incremental value. Each phase is independently valuable and can be deployed separately.
@@ -5,3 +5,5 @@
5
5
  export * from './common-types.js';
6
6
  export * from './socket-augmentation.js';
7
7
  export * from './route-context.js';
8
+ export * from './wrapped-socket.js';
9
+ export * from './socket-types.js';
@@ -0,0 +1,21 @@
1
+ import * as net from 'net';
2
+ import { WrappedSocket } from './wrapped-socket.js';
3
+
4
+ /**
5
+ * Type guard to check if a socket is a WrappedSocket
6
+ */
7
+ export function isWrappedSocket(socket: net.Socket | WrappedSocket): socket is WrappedSocket {
8
+ return socket instanceof WrappedSocket || 'socket' in socket;
9
+ }
10
+
11
+ /**
12
+ * Helper to get the underlying socket from either a Socket or WrappedSocket
13
+ */
14
+ export function getUnderlyingSocket(socket: net.Socket | WrappedSocket): net.Socket {
15
+ return isWrappedSocket(socket) ? socket.socket : socket;
16
+ }
17
+
18
+ /**
19
+ * Type that represents either a regular socket or a wrapped socket
20
+ */
21
+ export type AnySocket = net.Socket | WrappedSocket;
@@ -0,0 +1,99 @@
1
+ import * as plugins from '../../plugins.js';
2
+
3
+ /**
4
+ * WrappedSocket wraps a regular net.Socket to provide transparent access
5
+ * to the real client IP and port when behind a proxy using PROXY protocol.
6
+ *
7
+ * This is the FOUNDATION for all PROXY protocol support and must be implemented
8
+ * before any protocol parsing can occur.
9
+ *
10
+ * This implementation uses a Proxy to delegate all properties and methods
11
+ * to the underlying socket while allowing override of specific properties.
12
+ */
13
+ export class WrappedSocket {
14
+ public readonly socket: plugins.net.Socket;
15
+ private realClientIP?: string;
16
+ private realClientPort?: number;
17
+
18
+ // Make TypeScript happy by declaring the Socket methods that will be proxied
19
+ [key: string]: any;
20
+
21
+ constructor(
22
+ socket: plugins.net.Socket,
23
+ realClientIP?: string,
24
+ realClientPort?: number
25
+ ) {
26
+ this.socket = socket;
27
+ this.realClientIP = realClientIP;
28
+ this.realClientPort = realClientPort;
29
+
30
+ // Create a proxy that delegates everything to the underlying socket
31
+ return new Proxy(this, {
32
+ get(target, prop, receiver) {
33
+ // Override specific properties
34
+ if (prop === 'remoteAddress') {
35
+ return target.remoteAddress;
36
+ }
37
+ if (prop === 'remotePort') {
38
+ return target.remotePort;
39
+ }
40
+ if (prop === 'socket') {
41
+ return target.socket;
42
+ }
43
+ if (prop === 'realClientIP') {
44
+ return target.realClientIP;
45
+ }
46
+ if (prop === 'realClientPort') {
47
+ return target.realClientPort;
48
+ }
49
+ if (prop === 'isFromTrustedProxy') {
50
+ return target.isFromTrustedProxy;
51
+ }
52
+ if (prop === 'setProxyInfo') {
53
+ return target.setProxyInfo.bind(target);
54
+ }
55
+
56
+ // For all other properties/methods, delegate to the underlying socket
57
+ const value = target.socket[prop as keyof plugins.net.Socket];
58
+ if (typeof value === 'function') {
59
+ return value.bind(target.socket);
60
+ }
61
+ return value;
62
+ },
63
+ set(target, prop, value) {
64
+ // Set on the underlying socket
65
+ (target.socket as any)[prop] = value;
66
+ return true;
67
+ }
68
+ }) as any;
69
+ }
70
+
71
+ /**
72
+ * Returns the real client IP if available, otherwise the socket's remote address
73
+ */
74
+ get remoteAddress(): string | undefined {
75
+ return this.realClientIP || this.socket.remoteAddress;
76
+ }
77
+
78
+ /**
79
+ * Returns the real client port if available, otherwise the socket's remote port
80
+ */
81
+ get remotePort(): number | undefined {
82
+ return this.realClientPort || this.socket.remotePort;
83
+ }
84
+
85
+ /**
86
+ * Indicates if this connection came through a trusted proxy
87
+ */
88
+ get isFromTrustedProxy(): boolean {
89
+ return !!this.realClientIP;
90
+ }
91
+
92
+ /**
93
+ * Updates the real client information (called after parsing PROXY protocol)
94
+ */
95
+ setProxyInfo(ip: string, port: number): void {
96
+ this.realClientIP = ip;
97
+ this.realClientPort = port;
98
+ }
99
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Unified routing module
3
+ * Provides all routing functionality in a centralized location
4
+ */
5
+
6
+ // Export all types
7
+ export * from './types.js';
8
+
9
+ // Export all matchers
10
+ export * from './matchers/index.js';
11
+
12
+ // Export specificity calculator
13
+ export * from './specificity.js';
14
+
15
+ // Export route management
16
+ export * from './route-manager.js';
17
+ export * from './route-utils.js';
18
+
19
+ // Convenience re-exports
20
+ export { matchers } from './matchers/index.js';
21
+ export { RouteSpecificity } from './specificity.js';
@@ -0,0 +1,119 @@
1
+ import type { IMatcher, IDomainMatchOptions } from '../types.js';
2
+
3
+ /**
4
+ * DomainMatcher provides comprehensive domain matching functionality
5
+ * Supporting exact matches, wildcards, and case-insensitive matching
6
+ */
7
+ export class DomainMatcher implements IMatcher<boolean, IDomainMatchOptions> {
8
+ private static wildcardToRegex(pattern: string): RegExp {
9
+ // Escape special regex characters except *
10
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
11
+ // Replace * with regex equivalent
12
+ const regexPattern = escaped.replace(/\*/g, '.*');
13
+ return new RegExp(`^${regexPattern}$`, 'i');
14
+ }
15
+
16
+ /**
17
+ * Match a domain pattern against a hostname
18
+ * @param pattern The pattern to match (supports wildcards like *.example.com)
19
+ * @param hostname The hostname to test
20
+ * @param options Matching options
21
+ * @returns true if the hostname matches the pattern
22
+ */
23
+ static match(
24
+ pattern: string,
25
+ hostname: string,
26
+ options: IDomainMatchOptions = {}
27
+ ): boolean {
28
+ // Handle null/undefined cases
29
+ if (!pattern || !hostname) {
30
+ return false;
31
+ }
32
+
33
+ // Normalize inputs
34
+ const normalizedPattern = pattern.toLowerCase().trim();
35
+ const normalizedHostname = hostname.toLowerCase().trim();
36
+
37
+ // Remove trailing dots (FQDN normalization)
38
+ const cleanPattern = normalizedPattern.replace(/\.$/, '');
39
+ const cleanHostname = normalizedHostname.replace(/\.$/, '');
40
+
41
+ // Exact match (most common case)
42
+ if (cleanPattern === cleanHostname) {
43
+ return true;
44
+ }
45
+
46
+ // Wildcard matching
47
+ if (options.allowWildcards !== false && cleanPattern.includes('*')) {
48
+ const regex = this.wildcardToRegex(cleanPattern);
49
+ return regex.test(cleanHostname);
50
+ }
51
+
52
+ // No match
53
+ return false;
54
+ }
55
+
56
+ /**
57
+ * Check if a pattern contains wildcards
58
+ */
59
+ static isWildcardPattern(pattern: string): boolean {
60
+ return pattern.includes('*');
61
+ }
62
+
63
+ /**
64
+ * Calculate the specificity of a domain pattern
65
+ * Higher values mean more specific patterns
66
+ */
67
+ static calculateSpecificity(pattern: string): number {
68
+ if (!pattern) return 0;
69
+
70
+ let score = 0;
71
+
72
+ // Exact domains are most specific
73
+ if (!pattern.includes('*')) {
74
+ score += 100;
75
+ }
76
+
77
+ // Count domain segments
78
+ const segments = pattern.split('.');
79
+ score += segments.length * 10;
80
+
81
+ // Penalize wildcards based on position
82
+ if (pattern.startsWith('*')) {
83
+ score -= 50; // Leading wildcard is very generic
84
+ } else if (pattern.includes('*')) {
85
+ score -= 20; // Wildcard elsewhere is less generic
86
+ }
87
+
88
+ // Bonus for longer patterns
89
+ score += pattern.length;
90
+
91
+ return score;
92
+ }
93
+
94
+ /**
95
+ * Find all matching patterns from a list
96
+ * Returns patterns sorted by specificity (most specific first)
97
+ */
98
+ static findAllMatches(
99
+ patterns: string[],
100
+ hostname: string,
101
+ options: IDomainMatchOptions = {}
102
+ ): string[] {
103
+ const matches = patterns.filter(pattern =>
104
+ this.match(pattern, hostname, options)
105
+ );
106
+
107
+ // Sort by specificity (highest first)
108
+ return matches.sort((a, b) =>
109
+ this.calculateSpecificity(b) - this.calculateSpecificity(a)
110
+ );
111
+ }
112
+
113
+ /**
114
+ * Instance method for interface compliance
115
+ */
116
+ match(pattern: string, hostname: string, options?: IDomainMatchOptions): boolean {
117
+ return DomainMatcher.match(pattern, hostname, options);
118
+ }
119
+ }