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