@push.rocks/smartproxy 16.0.2 → 16.0.4
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.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/core/models/index.d.ts +2 -0
- package/dist_ts/core/models/index.js +3 -1
- package/dist_ts/core/models/route-context.d.ts +62 -0
- package/dist_ts/core/models/route-context.js +43 -0
- package/dist_ts/core/models/socket-augmentation.d.ts +12 -0
- package/dist_ts/core/models/socket-augmentation.js +18 -0
- package/dist_ts/core/utils/event-system.d.ts +200 -0
- package/dist_ts/core/utils/event-system.js +224 -0
- package/dist_ts/core/utils/index.d.ts +7 -0
- package/dist_ts/core/utils/index.js +8 -1
- package/dist_ts/core/utils/route-manager.d.ts +118 -0
- package/dist_ts/core/utils/route-manager.js +383 -0
- package/dist_ts/core/utils/route-utils.d.ts +94 -0
- package/dist_ts/core/utils/route-utils.js +264 -0
- package/dist_ts/core/utils/security-utils.d.ts +111 -0
- package/dist_ts/core/utils/security-utils.js +212 -0
- package/dist_ts/core/utils/shared-security-manager.d.ts +110 -0
- package/dist_ts/core/utils/shared-security-manager.js +252 -0
- package/dist_ts/core/utils/template-utils.d.ts +37 -0
- package/dist_ts/core/utils/template-utils.js +104 -0
- package/dist_ts/core/utils/websocket-utils.d.ts +23 -0
- package/dist_ts/core/utils/websocket-utils.js +86 -0
- package/dist_ts/http/router/index.d.ts +5 -1
- package/dist_ts/http/router/index.js +4 -2
- package/dist_ts/http/router/route-router.d.ts +108 -0
- package/dist_ts/http/router/route-router.js +393 -0
- package/dist_ts/index.d.ts +8 -2
- package/dist_ts/index.js +10 -3
- package/dist_ts/proxies/index.d.ts +7 -2
- package/dist_ts/proxies/index.js +10 -4
- package/dist_ts/proxies/network-proxy/certificate-manager.d.ts +21 -0
- package/dist_ts/proxies/network-proxy/certificate-manager.js +92 -1
- package/dist_ts/proxies/network-proxy/context-creator.d.ts +34 -0
- package/dist_ts/proxies/network-proxy/context-creator.js +108 -0
- package/dist_ts/proxies/network-proxy/function-cache.d.ts +90 -0
- package/dist_ts/proxies/network-proxy/function-cache.js +198 -0
- package/dist_ts/proxies/network-proxy/http-request-handler.d.ts +40 -0
- package/dist_ts/proxies/network-proxy/http-request-handler.js +256 -0
- package/dist_ts/proxies/network-proxy/http2-request-handler.d.ts +24 -0
- package/dist_ts/proxies/network-proxy/http2-request-handler.js +201 -0
- package/dist_ts/proxies/network-proxy/models/types.d.ts +73 -1
- package/dist_ts/proxies/network-proxy/models/types.js +242 -1
- package/dist_ts/proxies/network-proxy/network-proxy.d.ts +23 -20
- package/dist_ts/proxies/network-proxy/network-proxy.js +149 -60
- package/dist_ts/proxies/network-proxy/request-handler.d.ts +38 -5
- package/dist_ts/proxies/network-proxy/request-handler.js +584 -198
- package/dist_ts/proxies/network-proxy/security-manager.d.ts +65 -0
- package/dist_ts/proxies/network-proxy/security-manager.js +255 -0
- package/dist_ts/proxies/network-proxy/websocket-handler.d.ts +13 -2
- package/dist_ts/proxies/network-proxy/websocket-handler.js +238 -20
- package/dist_ts/proxies/smart-proxy/index.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/index.js +3 -3
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +3 -5
- package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +56 -4
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +4 -57
- package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +19 -228
- package/dist_ts/proxies/smart-proxy/port-manager.d.ts +81 -0
- package/dist_ts/proxies/smart-proxy/port-manager.js +166 -0
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +5 -0
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +131 -15
- package/dist_ts/proxies/smart-proxy/route-helpers/index.d.ts +3 -1
- package/dist_ts/proxies/smart-proxy/route-helpers/index.js +5 -3
- package/dist_ts/proxies/smart-proxy/route-helpers.d.ts +5 -178
- package/dist_ts/proxies/smart-proxy/route-helpers.js +8 -296
- package/dist_ts/proxies/smart-proxy/route-manager.d.ts +11 -2
- package/dist_ts/proxies/smart-proxy/route-manager.js +79 -10
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +29 -2
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +48 -43
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +67 -1
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +120 -1
- package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +3 -3
- package/dist_ts/proxies/smart-proxy/utils/route-validators.js +27 -5
- package/package.json +1 -1
- package/readme.md +102 -14
- package/readme.plan.md +103 -168
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/core/models/index.ts +2 -0
- package/ts/core/models/route-context.ts +113 -0
- package/ts/core/models/socket-augmentation.ts +33 -0
- package/ts/core/utils/event-system.ts +376 -0
- package/ts/core/utils/index.ts +7 -0
- package/ts/core/utils/route-manager.ts +489 -0
- package/ts/core/utils/route-utils.ts +312 -0
- package/ts/core/utils/security-utils.ts +309 -0
- package/ts/core/utils/shared-security-manager.ts +333 -0
- package/ts/core/utils/template-utils.ts +124 -0
- package/ts/core/utils/websocket-utils.ts +81 -0
- package/ts/http/router/index.ts +8 -1
- package/ts/http/router/route-router.ts +482 -0
- package/ts/index.ts +14 -2
- package/ts/proxies/index.ts +12 -3
- package/ts/proxies/network-proxy/certificate-manager.ts +114 -10
- package/ts/proxies/network-proxy/context-creator.ts +145 -0
- package/ts/proxies/network-proxy/function-cache.ts +259 -0
- package/ts/proxies/network-proxy/http-request-handler.ts +330 -0
- package/ts/proxies/network-proxy/http2-request-handler.ts +255 -0
- package/ts/proxies/network-proxy/models/types.ts +312 -1
- package/ts/proxies/network-proxy/network-proxy.ts +197 -85
- package/ts/proxies/network-proxy/request-handler.ts +698 -246
- package/ts/proxies/network-proxy/security-manager.ts +298 -0
- package/ts/proxies/network-proxy/websocket-handler.ts +276 -33
- package/ts/proxies/smart-proxy/index.ts +2 -12
- package/ts/proxies/smart-proxy/models/interfaces.ts +7 -4
- package/ts/proxies/smart-proxy/models/route-types.ts +77 -10
- package/ts/proxies/smart-proxy/network-proxy-bridge.ts +20 -257
- package/ts/proxies/smart-proxy/port-manager.ts +195 -0
- package/ts/proxies/smart-proxy/route-connection-handler.ts +156 -21
- package/ts/proxies/smart-proxy/route-manager.ts +98 -14
- package/ts/proxies/smart-proxy/smart-proxy.ts +56 -55
- package/ts/proxies/smart-proxy/utils/route-helpers.ts +167 -1
- package/ts/proxies/smart-proxy/utils/route-validators.ts +24 -5
- package/ts/proxies/smart-proxy/domain-config-manager.ts.bak +0 -441
- package/ts/proxies/smart-proxy/route-helpers/index.ts +0 -9
- 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhcmVkLXNlY3VyaXR5LW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9jb3JlL3V0aWxzL3NoYXJlZC1zZWN1cml0eS1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFRNUMsT0FBTyxFQUNMLGNBQWMsRUFDZCxtQkFBbUIsRUFDbkIsbUJBQW1CLEVBQ25CLGVBQWUsRUFDZixnQkFBZ0IsRUFDaEIsd0JBQXdCLEVBQ3hCLG9CQUFvQixFQUNyQixNQUFNLHFCQUFxQixDQUFDO0FBRTdCOzs7R0FHRztBQUNILE1BQU0sT0FBTyxxQkFBcUI7SUFpQmhDOzs7OztPQUtHO0lBQ0gsWUFBWSxPQUtYLEVBQVUsTUFBd0I7UUFBeEIsV0FBTSxHQUFOLE1BQU0sQ0FBa0I7UUEzQm5DLHlCQUF5QjtRQUNqQixvQkFBZSxHQUFtQyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBRXBFLCtCQUErQjtRQUN2QixlQUFVLEdBQTZDLElBQUksR0FBRyxFQUFFLENBQUM7UUFFekUsOERBQThEO1FBQ3RELGtCQUFhLEdBQXNDLElBQUksR0FBRyxFQUFFLENBQUM7UUFNckUseUJBQXlCO1FBQ2pCLG9CQUFlLEdBQTBCLElBQUksQ0FBQztRQWNwRCxJQUFJLENBQUMsbUJBQW1CLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixJQUFJLEdBQUcsQ0FBQztRQUM5RCxJQUFJLENBQUMsNEJBQTRCLEdBQUcsT0FBTyxDQUFDLDRCQUE0QixJQUFJLEdBQUcsQ0FBQztRQUVoRiw4Q0FBOEM7UUFDOUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLElBQUk7WUFDdEIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxHQUFHO1lBQ2pCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtZQUNsQixLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUs7U0FDckIsQ0FBQztRQUVGLGdDQUFnQztRQUNoQyxNQUFN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
|
|
@@ -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
|
|
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
|
-
|
|
5
|
-
|
|
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=
|