@push.rocks/smartproxy 21.1.7 → 22.4.2
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/changelog.md +81 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/core/utils/shared-security-manager.d.ts +17 -0
- package/dist_ts/core/utils/shared-security-manager.js +66 -1
- package/dist_ts/proxies/http-proxy/default-certificates.d.ts +54 -0
- package/dist_ts/proxies/http-proxy/default-certificates.js +127 -0
- package/dist_ts/proxies/http-proxy/http-proxy.d.ts +1 -1
- package/dist_ts/proxies/http-proxy/http-proxy.js +9 -14
- package/dist_ts/proxies/http-proxy/index.d.ts +5 -1
- package/dist_ts/proxies/http-proxy/index.js +6 -2
- package/dist_ts/proxies/http-proxy/security-manager.d.ts +4 -12
- package/dist_ts/proxies/http-proxy/security-manager.js +66 -99
- package/dist_ts/proxies/nftables-proxy/index.d.ts +1 -0
- package/dist_ts/proxies/nftables-proxy/index.js +2 -1
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.d.ts +4 -26
- package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +84 -236
- package/dist_ts/proxies/nftables-proxy/utils/index.d.ts +9 -0
- package/dist_ts/proxies/nftables-proxy/utils/index.js +12 -0
- package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.d.ts +66 -0
- package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.js +131 -0
- package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.d.ts +39 -0
- package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.js +112 -0
- package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.d.ts +59 -0
- package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.js +130 -0
- package/dist_ts/proxies/smart-proxy/certificate-manager.js +4 -3
- package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +13 -2
- package/dist_ts/proxies/smart-proxy/connection-manager.js +16 -6
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +35 -10
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +0 -1
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +17 -0
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +72 -9
- package/dist_ts/proxies/smart-proxy/security-manager.d.ts +14 -12
- package/dist_ts/proxies/smart-proxy/security-manager.js +80 -74
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +1 -2
- package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +2 -9
- package/dist_ts/proxies/smart-proxy/tls-manager.js +3 -26
- package/dist_ts/proxies/smart-proxy/utils/index.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/utils/index.js +3 -4
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/api-helpers.d.ts +49 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/api-helpers.js +108 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.d.ts +57 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.js +89 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/http-helpers.d.ts +17 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/http-helpers.js +32 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/https-helpers.d.ts +68 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/https-helpers.js +117 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/index.d.ts +17 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/index.js +27 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.d.ts +63 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.js +105 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.d.ts +83 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.js +126 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/security-helpers.d.ts +47 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/security-helpers.js +66 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.d.ts +70 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.js +287 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.d.ts +46 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.js +67 -0
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +4 -457
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +6 -950
- package/dist_ts/proxies/smart-proxy/utils/route-utils.js +2 -2
- package/dist_ts/proxies/smart-proxy/utils/route-validator.d.ts +67 -1
- package/dist_ts/proxies/smart-proxy/utils/route-validator.js +251 -3
- package/npmextra.json +12 -6
- package/package.json +34 -24
- package/readme.hints.md +184 -1
- package/readme.md +235 -172
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/core/utils/shared-security-manager.ts +98 -13
- package/ts/proxies/http-proxy/default-certificates.ts +150 -0
- package/ts/proxies/http-proxy/http-proxy.ts +9 -15
- package/ts/proxies/http-proxy/index.ts +6 -1
- package/ts/proxies/http-proxy/security-manager.ts +141 -161
- package/ts/proxies/nftables-proxy/index.ts +1 -0
- package/ts/proxies/nftables-proxy/nftables-proxy.ts +116 -290
- package/ts/proxies/nftables-proxy/utils/index.ts +38 -0
- package/ts/proxies/nftables-proxy/utils/nft-command-executor.ts +162 -0
- package/ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.ts +125 -0
- package/ts/proxies/nftables-proxy/utils/nft-rule-validator.ts +156 -0
- package/ts/proxies/smart-proxy/certificate-manager.ts +3 -2
- package/ts/proxies/smart-proxy/connection-manager.ts +21 -8
- package/ts/proxies/smart-proxy/http-proxy-bridge.ts +39 -13
- package/ts/proxies/smart-proxy/models/interfaces.ts +0 -1
- package/ts/proxies/smart-proxy/route-connection-handler.ts +88 -16
- package/ts/proxies/smart-proxy/security-manager.ts +98 -86
- package/ts/proxies/smart-proxy/smart-proxy.ts +0 -2
- package/ts/proxies/smart-proxy/tls-manager.ts +1 -37
- package/ts/proxies/smart-proxy/utils/index.ts +3 -5
- package/ts/proxies/smart-proxy/utils/route-helpers/api-helpers.ts +144 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.ts +124 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/http-helpers.ts +40 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/https-helpers.ts +163 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/index.ts +62 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.ts +154 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.ts +202 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/security-helpers.ts +96 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.ts +337 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.ts +98 -0
- package/ts/proxies/smart-proxy/utils/route-helpers.ts +5 -1302
- package/ts/proxies/smart-proxy/utils/route-utils.ts +1 -1
- package/ts/proxies/smart-proxy/utils/route-validator.ts +274 -4
- package/ts/proxies/http-proxy/certificate-manager.ts +0 -244
- package/ts/proxies/smart-proxy/utils/route-validators.ts +0 -283
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Socket Handler Functions
|
|
3
|
+
*
|
|
4
|
+
* This module provides pre-built socket handlers for common use cases
|
|
5
|
+
* like echoing, proxying, HTTP responses, and redirects.
|
|
6
|
+
*/
|
|
7
|
+
import * as plugins from '../../../../plugins.js';
|
|
8
|
+
import { ProtocolDetector } from '../../../../detection/index.js';
|
|
9
|
+
import { createSocketTracker } from '../../../../core/utils/socket-tracker.js';
|
|
10
|
+
/**
|
|
11
|
+
* Pre-built socket handlers for common use cases
|
|
12
|
+
*/
|
|
13
|
+
export const SocketHandlers = {
|
|
14
|
+
/**
|
|
15
|
+
* Simple echo server handler
|
|
16
|
+
*/
|
|
17
|
+
echo: (socket, context) => {
|
|
18
|
+
socket.write('ECHO SERVER READY\n');
|
|
19
|
+
socket.on('data', data => socket.write(data));
|
|
20
|
+
},
|
|
21
|
+
/**
|
|
22
|
+
* TCP proxy handler
|
|
23
|
+
*/
|
|
24
|
+
proxy: (targetHost, targetPort) => (socket, context) => {
|
|
25
|
+
const target = plugins.net.connect(targetPort, targetHost);
|
|
26
|
+
socket.pipe(target);
|
|
27
|
+
target.pipe(socket);
|
|
28
|
+
socket.on('close', () => target.destroy());
|
|
29
|
+
target.on('close', () => socket.destroy());
|
|
30
|
+
target.on('error', (err) => {
|
|
31
|
+
console.error('Proxy target error:', err);
|
|
32
|
+
socket.destroy();
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
/**
|
|
36
|
+
* Line-based protocol handler
|
|
37
|
+
*/
|
|
38
|
+
lineProtocol: (handler) => (socket, context) => {
|
|
39
|
+
let buffer = '';
|
|
40
|
+
socket.on('data', (data) => {
|
|
41
|
+
buffer += data.toString();
|
|
42
|
+
const lines = buffer.split('\n');
|
|
43
|
+
buffer = lines.pop() || '';
|
|
44
|
+
lines.forEach(line => {
|
|
45
|
+
if (line.trim()) {
|
|
46
|
+
handler(line.trim(), socket);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
/**
|
|
52
|
+
* Simple HTTP response handler (for testing)
|
|
53
|
+
*/
|
|
54
|
+
httpResponse: (statusCode, body) => (socket, context) => {
|
|
55
|
+
const response = [
|
|
56
|
+
`HTTP/1.1 ${statusCode} ${statusCode === 200 ? 'OK' : 'Error'}`,
|
|
57
|
+
'Content-Type: text/plain',
|
|
58
|
+
`Content-Length: ${body.length}`,
|
|
59
|
+
'Connection: close',
|
|
60
|
+
'',
|
|
61
|
+
body
|
|
62
|
+
].join('\r\n');
|
|
63
|
+
socket.write(response);
|
|
64
|
+
socket.end();
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* Block connection immediately
|
|
68
|
+
*/
|
|
69
|
+
block: (message) => (socket, context) => {
|
|
70
|
+
const finalMessage = message || `Connection blocked from ${context.clientIp}`;
|
|
71
|
+
if (finalMessage) {
|
|
72
|
+
socket.write(finalMessage);
|
|
73
|
+
}
|
|
74
|
+
socket.end();
|
|
75
|
+
},
|
|
76
|
+
/**
|
|
77
|
+
* HTTP block response
|
|
78
|
+
*/
|
|
79
|
+
httpBlock: (statusCode = 403, message) => (socket, context) => {
|
|
80
|
+
const defaultMessage = `Access forbidden for ${context.domain || context.clientIp}`;
|
|
81
|
+
const finalMessage = message || defaultMessage;
|
|
82
|
+
const response = [
|
|
83
|
+
`HTTP/1.1 ${statusCode} ${finalMessage}`,
|
|
84
|
+
'Content-Type: text/plain',
|
|
85
|
+
`Content-Length: ${finalMessage.length}`,
|
|
86
|
+
'Connection: close',
|
|
87
|
+
'',
|
|
88
|
+
finalMessage
|
|
89
|
+
].join('\r\n');
|
|
90
|
+
socket.write(response);
|
|
91
|
+
socket.end();
|
|
92
|
+
},
|
|
93
|
+
/**
|
|
94
|
+
* HTTP redirect handler
|
|
95
|
+
* Uses the centralized detection module for HTTP parsing
|
|
96
|
+
*/
|
|
97
|
+
httpRedirect: (locationTemplate, statusCode = 301) => (socket, context) => {
|
|
98
|
+
const tracker = createSocketTracker(socket);
|
|
99
|
+
const connectionId = ProtocolDetector.createConnectionId({
|
|
100
|
+
socketId: context.connectionId || `${Date.now()}-${Math.random()}`
|
|
101
|
+
});
|
|
102
|
+
const handleData = async (data) => {
|
|
103
|
+
// Use detection module for parsing
|
|
104
|
+
const detectionResult = await ProtocolDetector.detectWithConnectionTracking(data, connectionId, { extractFullHeaders: false } // We only need method and path
|
|
105
|
+
);
|
|
106
|
+
if (detectionResult.protocol === 'http' && detectionResult.connectionInfo.path) {
|
|
107
|
+
const method = detectionResult.connectionInfo.method || 'GET';
|
|
108
|
+
const path = detectionResult.connectionInfo.path || '/';
|
|
109
|
+
const domain = context.domain || 'localhost';
|
|
110
|
+
const port = context.port;
|
|
111
|
+
let finalLocation = locationTemplate
|
|
112
|
+
.replace('{domain}', domain)
|
|
113
|
+
.replace('{port}', String(port))
|
|
114
|
+
.replace('{path}', path)
|
|
115
|
+
.replace('{clientIp}', context.clientIp);
|
|
116
|
+
const message = `Redirecting to ${finalLocation}`;
|
|
117
|
+
const response = [
|
|
118
|
+
`HTTP/1.1 ${statusCode} ${statusCode === 301 ? 'Moved Permanently' : 'Found'}`,
|
|
119
|
+
`Location: ${finalLocation}`,
|
|
120
|
+
'Content-Type: text/plain',
|
|
121
|
+
`Content-Length: ${message.length}`,
|
|
122
|
+
'Connection: close',
|
|
123
|
+
'',
|
|
124
|
+
message
|
|
125
|
+
].join('\r\n');
|
|
126
|
+
socket.write(response);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// Not a valid HTTP request, close connection
|
|
130
|
+
socket.write('HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n');
|
|
131
|
+
}
|
|
132
|
+
socket.end();
|
|
133
|
+
// Clean up detection state
|
|
134
|
+
ProtocolDetector.cleanupConnections();
|
|
135
|
+
// Clean up all tracked resources
|
|
136
|
+
tracker.cleanup();
|
|
137
|
+
};
|
|
138
|
+
// Use tracker to manage the listener
|
|
139
|
+
socket.once('data', handleData);
|
|
140
|
+
tracker.addListener('error', (err) => {
|
|
141
|
+
tracker.safeDestroy(err);
|
|
142
|
+
});
|
|
143
|
+
tracker.addListener('close', () => {
|
|
144
|
+
tracker.cleanup();
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
/**
|
|
148
|
+
* HTTP server handler for ACME challenges and other HTTP needs
|
|
149
|
+
* Uses the centralized detection module for HTTP parsing
|
|
150
|
+
*/
|
|
151
|
+
httpServer: (handler) => (socket, context) => {
|
|
152
|
+
const tracker = createSocketTracker(socket);
|
|
153
|
+
let requestParsed = false;
|
|
154
|
+
let responseTimer = null;
|
|
155
|
+
const connectionId = ProtocolDetector.createConnectionId({
|
|
156
|
+
socketId: context.connectionId || `${Date.now()}-${Math.random()}`
|
|
157
|
+
});
|
|
158
|
+
const processData = async (data) => {
|
|
159
|
+
if (requestParsed)
|
|
160
|
+
return; // Only handle the first request
|
|
161
|
+
// Use HttpDetector for parsing
|
|
162
|
+
const detectionResult = await ProtocolDetector.detectWithConnectionTracking(data, connectionId, { extractFullHeaders: true });
|
|
163
|
+
if (detectionResult.protocol !== 'http' || !detectionResult.isComplete) {
|
|
164
|
+
// Not a complete HTTP request yet
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
requestParsed = true;
|
|
168
|
+
// Remove data listener after parsing request
|
|
169
|
+
socket.removeListener('data', processData);
|
|
170
|
+
const connInfo = detectionResult.connectionInfo;
|
|
171
|
+
// Create request object from detection result
|
|
172
|
+
const req = {
|
|
173
|
+
method: connInfo.method || 'GET',
|
|
174
|
+
url: connInfo.path || '/',
|
|
175
|
+
headers: connInfo.headers || {},
|
|
176
|
+
body: detectionResult.remainingBuffer?.toString() || ''
|
|
177
|
+
};
|
|
178
|
+
// Create response object
|
|
179
|
+
let statusCode = 200;
|
|
180
|
+
const responseHeaders = {};
|
|
181
|
+
let ended = false;
|
|
182
|
+
const res = {
|
|
183
|
+
status: (code) => {
|
|
184
|
+
statusCode = code;
|
|
185
|
+
},
|
|
186
|
+
header: (name, value) => {
|
|
187
|
+
responseHeaders[name] = value;
|
|
188
|
+
},
|
|
189
|
+
send: (data) => {
|
|
190
|
+
if (ended)
|
|
191
|
+
return;
|
|
192
|
+
ended = true;
|
|
193
|
+
// Clear response timer since we're sending now
|
|
194
|
+
if (responseTimer) {
|
|
195
|
+
clearTimeout(responseTimer);
|
|
196
|
+
responseTimer = null;
|
|
197
|
+
}
|
|
198
|
+
if (!responseHeaders['content-type']) {
|
|
199
|
+
responseHeaders['content-type'] = 'text/plain';
|
|
200
|
+
}
|
|
201
|
+
responseHeaders['content-length'] = String(data.length);
|
|
202
|
+
responseHeaders['connection'] = 'close';
|
|
203
|
+
const statusText = statusCode === 200 ? 'OK' :
|
|
204
|
+
statusCode === 404 ? 'Not Found' :
|
|
205
|
+
statusCode === 500 ? 'Internal Server Error' : 'Response';
|
|
206
|
+
let response = `HTTP/1.1 ${statusCode} ${statusText}\r\n`;
|
|
207
|
+
for (const [name, value] of Object.entries(responseHeaders)) {
|
|
208
|
+
response += `${name}: ${value}\r\n`;
|
|
209
|
+
}
|
|
210
|
+
response += '\r\n';
|
|
211
|
+
response += data;
|
|
212
|
+
socket.write(response);
|
|
213
|
+
socket.end();
|
|
214
|
+
},
|
|
215
|
+
end: () => {
|
|
216
|
+
if (ended)
|
|
217
|
+
return;
|
|
218
|
+
ended = true;
|
|
219
|
+
socket.write('HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: close\r\n\r\n');
|
|
220
|
+
socket.end();
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
try {
|
|
224
|
+
handler(req, res);
|
|
225
|
+
// Ensure response is sent even if handler doesn't call send()
|
|
226
|
+
responseTimer = setTimeout(() => {
|
|
227
|
+
if (!ended) {
|
|
228
|
+
res.send('');
|
|
229
|
+
}
|
|
230
|
+
responseTimer = null;
|
|
231
|
+
}, 1000);
|
|
232
|
+
// Track and unref the timer
|
|
233
|
+
tracker.addTimer(responseTimer);
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
if (!ended) {
|
|
237
|
+
res.status(500);
|
|
238
|
+
res.send('Internal Server Error');
|
|
239
|
+
}
|
|
240
|
+
// Use safeDestroy for error cases
|
|
241
|
+
tracker.safeDestroy(error instanceof Error ? error : new Error('Handler error'));
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
// Use tracker to manage listeners
|
|
245
|
+
tracker.addListener('data', processData);
|
|
246
|
+
tracker.addListener('error', (err) => {
|
|
247
|
+
if (!requestParsed) {
|
|
248
|
+
tracker.safeDestroy(err);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
tracker.addListener('close', () => {
|
|
252
|
+
// Clear any pending response timer
|
|
253
|
+
if (responseTimer) {
|
|
254
|
+
clearTimeout(responseTimer);
|
|
255
|
+
responseTimer = null;
|
|
256
|
+
}
|
|
257
|
+
// Clean up detection state
|
|
258
|
+
ProtocolDetector.cleanupConnections();
|
|
259
|
+
// Clean up all tracked resources
|
|
260
|
+
tracker.cleanup();
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
/**
|
|
265
|
+
* Create a socket handler route configuration
|
|
266
|
+
* @param domains Domain(s) to match
|
|
267
|
+
* @param ports Port(s) to listen on
|
|
268
|
+
* @param handler Socket handler function
|
|
269
|
+
* @param options Additional route options
|
|
270
|
+
* @returns Route configuration object
|
|
271
|
+
*/
|
|
272
|
+
export function createSocketHandlerRoute(domains, ports, handler, options = {}) {
|
|
273
|
+
return {
|
|
274
|
+
name: options.name || 'socket-handler-route',
|
|
275
|
+
priority: options.priority !== undefined ? options.priority : 50,
|
|
276
|
+
match: {
|
|
277
|
+
domains,
|
|
278
|
+
ports,
|
|
279
|
+
...(options.path && { path: options.path })
|
|
280
|
+
},
|
|
281
|
+
action: {
|
|
282
|
+
type: 'socket-handler',
|
|
283
|
+
socketHandler: handler
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic29ja2V0LWhhbmRsZXJzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vdHMvcHJveGllcy9zbWFydC1wcm94eS91dGlscy9yb3V0ZS1oZWxwZXJzL3NvY2tldC1oYW5kbGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7R0FLRztBQUVILE9BQU8sS0FBSyxPQUFPLE1BQU0sd0JBQXdCLENBQUM7QUFFbEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDbEUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMENBQTBDLENBQUM7QUFFL0U7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUc7SUFDNUI7O09BRUc7SUFDSCxJQUFJLEVBQUUsQ0FBQyxNQUEwQixFQUFFLE9BQXNCLEVBQUUsRUFBRTtRQUMzRCxNQUFNLENBQUMsS0FBSyxDQUFDLHFCQUFxQixDQUFDLENBQUM7UUFDcEMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxFQUFFLENBQUMsVUFBa0IsRUFBRSxVQUFrQixFQUFFLEVBQUUsQ0FBQyxDQUFDLE1BQTBCLEVBQUUsT0FBc0IsRUFBRSxFQUFFO1FBQ3hHLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxVQUFVLENBQUMsQ0FBQztRQUMzRCxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3BCLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDcEIsTUFBTSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFD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
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Route Helper Functions
|
|
3
|
+
*
|
|
4
|
+
* This module provides utility functions for creating WebSocket route configurations.
|
|
5
|
+
*/
|
|
6
|
+
import type { IRouteConfig } from '../../models/route-types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Create a WebSocket route configuration
|
|
9
|
+
* @param domains Domain(s) to match
|
|
10
|
+
* @param targetOrPath Target server OR WebSocket path (legacy)
|
|
11
|
+
* @param targetOrOptions Target server (legacy) OR options
|
|
12
|
+
* @param options Additional route options (legacy)
|
|
13
|
+
* @returns Route configuration object
|
|
14
|
+
*/
|
|
15
|
+
export declare function createWebSocketRoute(domains: string | string[], targetOrPath: {
|
|
16
|
+
host: string | string[];
|
|
17
|
+
port: number;
|
|
18
|
+
} | string, targetOrOptions?: {
|
|
19
|
+
host: string | string[];
|
|
20
|
+
port: number;
|
|
21
|
+
} | {
|
|
22
|
+
useTls?: boolean;
|
|
23
|
+
certificate?: 'auto' | {
|
|
24
|
+
key: string;
|
|
25
|
+
cert: string;
|
|
26
|
+
};
|
|
27
|
+
path?: string;
|
|
28
|
+
httpPort?: number | number[];
|
|
29
|
+
httpsPort?: number | number[];
|
|
30
|
+
pingInterval?: number;
|
|
31
|
+
pingTimeout?: number;
|
|
32
|
+
name?: string;
|
|
33
|
+
[key: string]: any;
|
|
34
|
+
}, options?: {
|
|
35
|
+
useTls?: boolean;
|
|
36
|
+
certificate?: 'auto' | {
|
|
37
|
+
key: string;
|
|
38
|
+
cert: string;
|
|
39
|
+
};
|
|
40
|
+
httpPort?: number | number[];
|
|
41
|
+
httpsPort?: number | number[];
|
|
42
|
+
pingInterval?: number;
|
|
43
|
+
pingTimeout?: number;
|
|
44
|
+
name?: string;
|
|
45
|
+
[key: string]: any;
|
|
46
|
+
}): IRouteConfig;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Route Helper Functions
|
|
3
|
+
*
|
|
4
|
+
* This module provides utility functions for creating WebSocket route configurations.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Create a WebSocket route configuration
|
|
8
|
+
* @param domains Domain(s) to match
|
|
9
|
+
* @param targetOrPath Target server OR WebSocket path (legacy)
|
|
10
|
+
* @param targetOrOptions Target server (legacy) OR options
|
|
11
|
+
* @param options Additional route options (legacy)
|
|
12
|
+
* @returns Route configuration object
|
|
13
|
+
*/
|
|
14
|
+
export function createWebSocketRoute(domains, targetOrPath, targetOrOptions, options) {
|
|
15
|
+
// Handle different signatures
|
|
16
|
+
let target;
|
|
17
|
+
let wsPath;
|
|
18
|
+
let finalOptions;
|
|
19
|
+
if (typeof targetOrPath === 'string') {
|
|
20
|
+
// Legacy signature: (domains, path, target, options)
|
|
21
|
+
wsPath = targetOrPath;
|
|
22
|
+
target = targetOrOptions;
|
|
23
|
+
finalOptions = options || {};
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
// New signature: (domains, target, options)
|
|
27
|
+
target = targetOrPath;
|
|
28
|
+
finalOptions = targetOrOptions || {};
|
|
29
|
+
wsPath = finalOptions.path || '/ws';
|
|
30
|
+
}
|
|
31
|
+
// Normalize WebSocket path
|
|
32
|
+
const normalizedPath = wsPath.startsWith('/') ? wsPath : `/${wsPath}`;
|
|
33
|
+
// Create route match
|
|
34
|
+
const match = {
|
|
35
|
+
ports: finalOptions.useTls
|
|
36
|
+
? (finalOptions.httpsPort || 443)
|
|
37
|
+
: (finalOptions.httpPort || 80),
|
|
38
|
+
domains,
|
|
39
|
+
path: normalizedPath
|
|
40
|
+
};
|
|
41
|
+
// Create route action
|
|
42
|
+
const action = {
|
|
43
|
+
type: 'forward',
|
|
44
|
+
targets: [target],
|
|
45
|
+
websocket: {
|
|
46
|
+
enabled: true,
|
|
47
|
+
pingInterval: finalOptions.pingInterval || 30000, // 30 seconds
|
|
48
|
+
pingTimeout: finalOptions.pingTimeout || 5000 // 5 seconds
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
// Add TLS configuration if using HTTPS
|
|
52
|
+
if (finalOptions.useTls) {
|
|
53
|
+
action.tls = {
|
|
54
|
+
mode: 'terminate',
|
|
55
|
+
certificate: finalOptions.certificate || 'auto'
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
// Create the route config
|
|
59
|
+
return {
|
|
60
|
+
match,
|
|
61
|
+
action,
|
|
62
|
+
name: finalOptions.name || `WebSocket Route ${normalizedPath} for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
|
|
63
|
+
priority: finalOptions.priority || 100, // Higher priority for WebSocket routes
|
|
64
|
+
...finalOptions
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2Vic29ja2V0LWhlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L3V0aWxzL3JvdXRlLWhlbHBlcnMvd2Vic29ja2V0LWhlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUlIOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLFVBQVUsb0JBQW9CLENBQ2xDLE9BQTBCLEVBQzFCLFlBQWdFLEVBQ2hFLGVBVUMsRUFDRCxPQVNDO0lBRUQsOEJBQThCO0lBQzlCLElBQUksTUFBaUQsQ0FBQztJQUN0RCxJQUFJLE1BQWMsQ0FBQztJQUNuQixJQUFJLFlBQWlCLENBQUM7SUFFdEIsSUFBSSxPQUFPLFlBQVksS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUNyQyxxREFBcUQ7UUFDckQsTUFBTSxHQUFHLFlBQVksQ0FBQztRQUN0QixNQUFNLEdBQUcsZUFBNEQsQ0FBQztRQUN0RSxZQUFZLEdBQUcsT0FBTyxJQUFJLEVBQUUsQ0FBQztJQUMvQixDQUFDO1NBQU0sQ0FBQztRQUNOLDRDQUE0QztRQUM1QyxNQUFNLEdBQUcsWUFBWSxDQUFDO1FBQ3RCLFlBQVksR0FBSSxlQUF1QixJQUFJLEVBQUUsQ0FBQztRQUM5QyxNQUFNLEdBQUcsWUFBWSxDQUFDLElBQUksSUFBSSxLQUFLLENBQUM7SUFDdEMsQ0FBQztJQUVELDJCQUEyQjtJQUMzQixNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksTUFBTSxFQUFFLENBQUM7SUFFdEUscUJBQXFCO0lBQ3JCLE1BQU0sS0FBSyxHQUFnQjtRQUN6QixLQUFLLEVBQUUsWUFBWSxDQUFDLE1BQU07WUFDeEIsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLFNBQVMsSUFBSSxHQUFHLENBQUM7WUFDakMsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUM7UUFDakMsT0FBTztRQUNQLElBQUksRUFBRSxjQUFjO0tBQ3JCLENBQUM7SUFFRixzQkFBc0I7SUFDdEIsTUFBTSxNQUFNLEdBQWlCO1FBQzNCLElBQUksRUFBRSxTQUFTO1FBQ2YsT0FBTyxFQUFFLENBQUMsTUFBTSxDQUFDO1FBQ2pCLFNBQVMsRUFBRTtZQUNULE9BQU8sRUFBRSxJQUFJO1lBQ2IsWUFBWSxFQUFFLFlBQVksQ0FBQyxZQUFZLElBQUksS0FBSyxFQUFFLGFBQWE7WUFDL0QsV0FBVyxFQUFFLFlBQVksQ0FBQyxXQUFXLElBQUksSUFBSSxDQUFJLFlBQVk7U0FDOUQ7S0FDRixDQUFDO0lBRUYsdUNBQXVDO0lBQ3ZDLElBQUksWUFBWSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ3hCLE1BQU0sQ0FBQyxHQUFHLEdBQUc7WUFDWCxJQUFJLEVBQUUsV0FBVztZQUNqQixXQUFXLEVBQUUsWUFBWSxDQUFDLFdBQVcsSUFBSSxNQUFNO1NBQ2hELENBQUM7SUFDSixDQUFDO0lBRUQsMEJBQTBCO0lBQzFCLE9BQU87UUFDTCxLQUFLO1FBQ0wsTUFBTTtRQUNOLElBQUksRUFBRSxZQUFZLENBQUMsSUFBSSxJQUFJLG1CQUFtQixjQUFjLFFBQVEsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxFQUFFO1FBQzNILFFBQVEsRUFBRSxZQUFZLENBQUMsUUFBUSxJQUFJLEdBQUcsRUFBRSx1Q0FBdUM7UUFDL0UsR0FBRyxZQUFZO0tBQ2hCLENBQUM7QUFDSixDQUFDIn0=
|