@push.rocks/smartproxy 26.2.4 → 27.0.0
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 +16 -0
- package/dist_rust/rustproxy_linux_amd64 +0 -0
- package/dist_rust/rustproxy_linux_arm64 +0 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/core/models/wrapped-socket.js +4 -1
- package/dist_ts/core/routing/route-manager.js +9 -7
- package/dist_ts/plugins.d.ts +2 -1
- package/dist_ts/plugins.js +3 -2
- package/dist_ts/proxies/smart-proxy/datagram-handler-server.js +7 -5
- package/dist_ts/proxies/smart-proxy/route-preprocessor.js +6 -8
- package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.js +186 -184
- package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.d.ts +0 -1
- package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.js +2 -4
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +9 -4
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +70 -10
- package/dist_ts/proxies/smart-proxy/socket-handler-server.js +5 -3
- package/dist_ts/proxies/smart-proxy/utils/concurrency-semaphore.js +4 -3
- package/dist_ts/proxies/smart-proxy/utils/index.d.ts +2 -3
- package/dist_ts/proxies/smart-proxy/utils/index.js +4 -6
- package/dist_ts/proxies/smart-proxy/utils/mutex.js +3 -5
- package/dist_ts/proxies/smart-proxy/utils/route-validator.js +7 -7
- package/dist_ts/proxies/smart-proxy/utils/{route-helpers/socket-handlers.d.ts → socket-handlers.d.ts} +2 -10
- package/dist_ts/proxies/smart-proxy/utils/socket-handlers.js +268 -0
- package/dist_ts/routing/models/http-types.js +5 -1
- package/package.json +2 -1
- package/readme.hints.md +42 -20
- package/readme.md +165 -163
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/plugins.ts +2 -0
- package/ts/proxies/smart-proxy/rust-proxy-bridge.ts +0 -5
- package/ts/proxies/smart-proxy/smart-proxy.ts +67 -5
- package/ts/proxies/smart-proxy/utils/index.ts +3 -11
- package/ts/proxies/smart-proxy/utils/{route-helpers/socket-handlers.ts → socket-handlers.ts} +3 -31
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/api-helpers.d.ts +0 -49
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/api-helpers.js +0 -108
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.d.ts +0 -57
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.js +0 -90
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/http-helpers.d.ts +0 -17
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/http-helpers.js +0 -32
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/https-helpers.d.ts +0 -68
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/https-helpers.js +0 -117
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/index.d.ts +0 -17
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/index.js +0 -27
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.d.ts +0 -63
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.js +0 -105
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.d.ts +0 -83
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.js +0 -126
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/security-helpers.d.ts +0 -47
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/security-helpers.js +0 -66
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.js +0 -286
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.d.ts +0 -46
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.js +0 -67
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +0 -9
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +0 -11
- package/ts/proxies/smart-proxy/utils/route-helpers/api-helpers.ts +0 -144
- package/ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.ts +0 -125
- package/ts/proxies/smart-proxy/utils/route-helpers/http-helpers.ts +0 -40
- package/ts/proxies/smart-proxy/utils/route-helpers/https-helpers.ts +0 -163
- package/ts/proxies/smart-proxy/utils/route-helpers/index.ts +0 -62
- package/ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.ts +0 -154
- package/ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.ts +0 -202
- package/ts/proxies/smart-proxy/utils/route-helpers/security-helpers.ts +0 -96
- package/ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.ts +0 -98
- package/ts/proxies/smart-proxy/utils/route-helpers.ts +0 -11
|
@@ -1,286 +0,0 @@
|
|
|
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 { createSocketTracker } from '../../../../core/utils/socket-tracker.js';
|
|
9
|
-
/**
|
|
10
|
-
* Minimal HTTP request parser for socket handlers.
|
|
11
|
-
* Parses method, path, and optionally headers from a raw buffer.
|
|
12
|
-
*/
|
|
13
|
-
function parseHttpRequest(data, extractHeaders = false) {
|
|
14
|
-
const str = data.toString('utf8');
|
|
15
|
-
const headerEnd = str.indexOf('\r\n\r\n');
|
|
16
|
-
const isComplete = headerEnd !== -1;
|
|
17
|
-
const headerSection = isComplete ? str.slice(0, headerEnd) : str;
|
|
18
|
-
const lines = headerSection.split('\r\n');
|
|
19
|
-
const requestLine = lines[0];
|
|
20
|
-
if (!requestLine)
|
|
21
|
-
return null;
|
|
22
|
-
const parts = requestLine.split(' ');
|
|
23
|
-
if (parts.length < 2)
|
|
24
|
-
return null;
|
|
25
|
-
const method = parts[0];
|
|
26
|
-
const path = parts[1];
|
|
27
|
-
// Quick check: valid HTTP method
|
|
28
|
-
const validMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS', 'CONNECT', 'TRACE'];
|
|
29
|
-
if (!validMethods.includes(method))
|
|
30
|
-
return null;
|
|
31
|
-
const headers = {};
|
|
32
|
-
if (extractHeaders) {
|
|
33
|
-
for (let i = 1; i < lines.length; i++) {
|
|
34
|
-
const colonIdx = lines[i].indexOf(':');
|
|
35
|
-
if (colonIdx > 0) {
|
|
36
|
-
const name = lines[i].slice(0, colonIdx).trim().toLowerCase();
|
|
37
|
-
const value = lines[i].slice(colonIdx + 1).trim();
|
|
38
|
-
headers[name] = value;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
const body = isComplete ? str.slice(headerEnd + 4) : undefined;
|
|
43
|
-
return { method, path, headers, isComplete, body };
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Pre-built socket handlers for common use cases
|
|
47
|
-
*/
|
|
48
|
-
export const SocketHandlers = {
|
|
49
|
-
/**
|
|
50
|
-
* Simple echo server handler
|
|
51
|
-
*/
|
|
52
|
-
echo: (socket, context) => {
|
|
53
|
-
socket.write('ECHO SERVER READY\n');
|
|
54
|
-
socket.on('data', data => socket.write(data));
|
|
55
|
-
},
|
|
56
|
-
/**
|
|
57
|
-
* TCP proxy handler
|
|
58
|
-
*/
|
|
59
|
-
proxy: (targetHost, targetPort) => (socket, context) => {
|
|
60
|
-
const target = plugins.net.connect(targetPort, targetHost);
|
|
61
|
-
socket.pipe(target);
|
|
62
|
-
target.pipe(socket);
|
|
63
|
-
socket.on('close', () => target.destroy());
|
|
64
|
-
target.on('close', () => socket.destroy());
|
|
65
|
-
target.on('error', (err) => {
|
|
66
|
-
console.error('Proxy target error:', err);
|
|
67
|
-
socket.destroy();
|
|
68
|
-
});
|
|
69
|
-
},
|
|
70
|
-
/**
|
|
71
|
-
* Line-based protocol handler
|
|
72
|
-
*/
|
|
73
|
-
lineProtocol: (handler) => (socket, context) => {
|
|
74
|
-
let buffer = '';
|
|
75
|
-
socket.on('data', (data) => {
|
|
76
|
-
buffer += data.toString();
|
|
77
|
-
const lines = buffer.split('\n');
|
|
78
|
-
buffer = lines.pop() || '';
|
|
79
|
-
lines.forEach(line => {
|
|
80
|
-
if (line.trim()) {
|
|
81
|
-
handler(line.trim(), socket);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
},
|
|
86
|
-
/**
|
|
87
|
-
* Simple HTTP response handler (for testing)
|
|
88
|
-
*/
|
|
89
|
-
httpResponse: (statusCode, body) => (socket, context) => {
|
|
90
|
-
const response = [
|
|
91
|
-
`HTTP/1.1 ${statusCode} ${statusCode === 200 ? 'OK' : 'Error'}`,
|
|
92
|
-
'Content-Type: text/plain',
|
|
93
|
-
`Content-Length: ${body.length}`,
|
|
94
|
-
'Connection: close',
|
|
95
|
-
'',
|
|
96
|
-
body
|
|
97
|
-
].join('\r\n');
|
|
98
|
-
socket.write(response);
|
|
99
|
-
socket.end();
|
|
100
|
-
},
|
|
101
|
-
/**
|
|
102
|
-
* Block connection immediately
|
|
103
|
-
*/
|
|
104
|
-
block: (message) => (socket, context) => {
|
|
105
|
-
const finalMessage = message || `Connection blocked from ${context.clientIp}`;
|
|
106
|
-
if (finalMessage) {
|
|
107
|
-
socket.write(finalMessage);
|
|
108
|
-
}
|
|
109
|
-
socket.end();
|
|
110
|
-
},
|
|
111
|
-
/**
|
|
112
|
-
* HTTP block response
|
|
113
|
-
*/
|
|
114
|
-
httpBlock: (statusCode = 403, message) => (socket, context) => {
|
|
115
|
-
const defaultMessage = `Access forbidden for ${context.domain || context.clientIp}`;
|
|
116
|
-
const finalMessage = message || defaultMessage;
|
|
117
|
-
const response = [
|
|
118
|
-
`HTTP/1.1 ${statusCode} ${finalMessage}`,
|
|
119
|
-
'Content-Type: text/plain',
|
|
120
|
-
`Content-Length: ${finalMessage.length}`,
|
|
121
|
-
'Connection: close',
|
|
122
|
-
'',
|
|
123
|
-
finalMessage
|
|
124
|
-
].join('\r\n');
|
|
125
|
-
socket.write(response);
|
|
126
|
-
socket.end();
|
|
127
|
-
},
|
|
128
|
-
/**
|
|
129
|
-
* HTTP redirect handler
|
|
130
|
-
*/
|
|
131
|
-
httpRedirect: (locationTemplate, statusCode = 301) => (socket, context) => {
|
|
132
|
-
const tracker = createSocketTracker(socket);
|
|
133
|
-
const handleData = (data) => {
|
|
134
|
-
const parsed = parseHttpRequest(data);
|
|
135
|
-
if (parsed) {
|
|
136
|
-
const path = parsed.path || '/';
|
|
137
|
-
const domain = context.domain || 'localhost';
|
|
138
|
-
const port = context.port;
|
|
139
|
-
const finalLocation = locationTemplate
|
|
140
|
-
.replace('{domain}', domain)
|
|
141
|
-
.replace('{port}', String(port))
|
|
142
|
-
.replace('{path}', path)
|
|
143
|
-
.replace('{clientIp}', context.clientIp);
|
|
144
|
-
const message = `Redirecting to ${finalLocation}`;
|
|
145
|
-
const response = [
|
|
146
|
-
`HTTP/1.1 ${statusCode} ${statusCode === 301 ? 'Moved Permanently' : 'Found'}`,
|
|
147
|
-
`Location: ${finalLocation}`,
|
|
148
|
-
'Content-Type: text/plain',
|
|
149
|
-
`Content-Length: ${message.length}`,
|
|
150
|
-
'Connection: close',
|
|
151
|
-
'',
|
|
152
|
-
message
|
|
153
|
-
].join('\r\n');
|
|
154
|
-
socket.write(response);
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
socket.write('HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n');
|
|
158
|
-
}
|
|
159
|
-
socket.end();
|
|
160
|
-
tracker.cleanup();
|
|
161
|
-
};
|
|
162
|
-
socket.once('data', handleData);
|
|
163
|
-
tracker.addListener('error', (err) => {
|
|
164
|
-
tracker.safeDestroy(err);
|
|
165
|
-
});
|
|
166
|
-
tracker.addListener('close', () => {
|
|
167
|
-
tracker.cleanup();
|
|
168
|
-
});
|
|
169
|
-
},
|
|
170
|
-
/**
|
|
171
|
-
* HTTP server handler for ACME challenges and other HTTP needs
|
|
172
|
-
*/
|
|
173
|
-
httpServer: (handler) => (socket, context) => {
|
|
174
|
-
const tracker = createSocketTracker(socket);
|
|
175
|
-
let requestParsed = false;
|
|
176
|
-
let responseTimer = null;
|
|
177
|
-
const processData = (data) => {
|
|
178
|
-
if (requestParsed)
|
|
179
|
-
return;
|
|
180
|
-
const parsed = parseHttpRequest(data, true);
|
|
181
|
-
if (!parsed || !parsed.isComplete) {
|
|
182
|
-
return; // Not a complete HTTP request yet
|
|
183
|
-
}
|
|
184
|
-
requestParsed = true;
|
|
185
|
-
socket.removeListener('data', processData);
|
|
186
|
-
const req = {
|
|
187
|
-
method: parsed.method,
|
|
188
|
-
url: parsed.path,
|
|
189
|
-
headers: parsed.headers,
|
|
190
|
-
body: parsed.body || ''
|
|
191
|
-
};
|
|
192
|
-
let statusCode = 200;
|
|
193
|
-
const responseHeaders = {};
|
|
194
|
-
let ended = false;
|
|
195
|
-
const res = {
|
|
196
|
-
status: (code) => {
|
|
197
|
-
statusCode = code;
|
|
198
|
-
},
|
|
199
|
-
header: (name, value) => {
|
|
200
|
-
responseHeaders[name] = value;
|
|
201
|
-
},
|
|
202
|
-
send: (data) => {
|
|
203
|
-
if (ended)
|
|
204
|
-
return;
|
|
205
|
-
ended = true;
|
|
206
|
-
if (responseTimer) {
|
|
207
|
-
clearTimeout(responseTimer);
|
|
208
|
-
responseTimer = null;
|
|
209
|
-
}
|
|
210
|
-
if (!responseHeaders['content-type']) {
|
|
211
|
-
responseHeaders['content-type'] = 'text/plain';
|
|
212
|
-
}
|
|
213
|
-
responseHeaders['content-length'] = String(data.length);
|
|
214
|
-
responseHeaders['connection'] = 'close';
|
|
215
|
-
const statusText = statusCode === 200 ? 'OK' :
|
|
216
|
-
statusCode === 404 ? 'Not Found' :
|
|
217
|
-
statusCode === 500 ? 'Internal Server Error' : 'Response';
|
|
218
|
-
let response = `HTTP/1.1 ${statusCode} ${statusText}\r\n`;
|
|
219
|
-
for (const [name, value] of Object.entries(responseHeaders)) {
|
|
220
|
-
response += `${name}: ${value}\r\n`;
|
|
221
|
-
}
|
|
222
|
-
response += '\r\n';
|
|
223
|
-
response += data;
|
|
224
|
-
socket.write(response);
|
|
225
|
-
socket.end();
|
|
226
|
-
},
|
|
227
|
-
end: () => {
|
|
228
|
-
if (ended)
|
|
229
|
-
return;
|
|
230
|
-
ended = true;
|
|
231
|
-
socket.write('HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: close\r\n\r\n');
|
|
232
|
-
socket.end();
|
|
233
|
-
}
|
|
234
|
-
};
|
|
235
|
-
try {
|
|
236
|
-
handler(req, res);
|
|
237
|
-
responseTimer = setTimeout(() => {
|
|
238
|
-
if (!ended) {
|
|
239
|
-
res.send('');
|
|
240
|
-
}
|
|
241
|
-
responseTimer = null;
|
|
242
|
-
}, 1000);
|
|
243
|
-
tracker.addTimer(responseTimer);
|
|
244
|
-
}
|
|
245
|
-
catch (error) {
|
|
246
|
-
if (!ended) {
|
|
247
|
-
res.status(500);
|
|
248
|
-
res.send('Internal Server Error');
|
|
249
|
-
}
|
|
250
|
-
tracker.safeDestroy(error instanceof Error ? error : new Error('Handler error'));
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
tracker.addListener('data', processData);
|
|
254
|
-
tracker.addListener('error', (err) => {
|
|
255
|
-
if (!requestParsed) {
|
|
256
|
-
tracker.safeDestroy(err);
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
tracker.addListener('close', () => {
|
|
260
|
-
if (responseTimer) {
|
|
261
|
-
clearTimeout(responseTimer);
|
|
262
|
-
responseTimer = null;
|
|
263
|
-
}
|
|
264
|
-
tracker.cleanup();
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
/**
|
|
269
|
-
* Create a socket handler route configuration
|
|
270
|
-
*/
|
|
271
|
-
export function createSocketHandlerRoute(domains, ports, handler, options = {}) {
|
|
272
|
-
return {
|
|
273
|
-
name: options.name || 'socket-handler-route',
|
|
274
|
-
priority: options.priority !== undefined ? options.priority : 50,
|
|
275
|
-
match: {
|
|
276
|
-
domains,
|
|
277
|
-
ports,
|
|
278
|
-
...(options.path && { path: options.path })
|
|
279
|
-
},
|
|
280
|
-
action: {
|
|
281
|
-
type: 'socket-handler',
|
|
282
|
-
socketHandler: handler
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic29ja2V0LWhhbmRsZXJzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vdHMvcHJveGllcy9zbWFydC1wcm94eS91dGlscy9yb3V0ZS1oZWxwZXJzL3NvY2tldC1oYW5kbGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7R0FLRztBQUVILE9BQU8sS0FBSyxPQUFPLE1BQU0sd0JBQXdCLENBQUM7QUFFbEQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMENBQTBDLENBQUM7QUFFL0U7OztHQUdHO0FBQ0gsU0FBUyxnQkFBZ0IsQ0FBQyxJQUFZLEVBQUUsaUJBQTBCLEtBQUs7SUFPckUsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNsQyxNQUFNLFNBQVMsR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzFDLE1BQU0sVUFBVSxHQUFHLFNBQVMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUNwQyxNQUFNLGFBQWEsR0FBRyxVQUFVLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7SUFDakUsTUFBTSxLQUFLLEdBQUcsYUFBYSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUMxQyxNQUFNLFdBQVcsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDN0IsSUFBSSxDQUFDLFdBQVc7UUFBRSxPQUFPLElBQUksQ0FBQztJQUU5QixNQUFNLEtBQUssR0FBRyxXQUFXLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3JDLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFFbEMsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hCLE1BQU0s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
|
|
@@ -1,46 +0,0 @@
|
|
|
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;
|
|
@@ -1,67 +0,0 @@
|
|
|
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=
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Route Helper Functions
|
|
3
|
-
*
|
|
4
|
-
* This file re-exports all route helper functions for backwards compatibility.
|
|
5
|
-
* The actual implementations have been split into focused modules in the route-helpers/ directory.
|
|
6
|
-
*
|
|
7
|
-
* @see ./route-helpers/index.ts for the modular exports
|
|
8
|
-
*/
|
|
9
|
-
export * from './route-helpers/index.js';
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Route Helper Functions
|
|
3
|
-
*
|
|
4
|
-
* This file re-exports all route helper functions for backwards compatibility.
|
|
5
|
-
* The actual implementations have been split into focused modules in the route-helpers/ directory.
|
|
6
|
-
*
|
|
7
|
-
* @see ./route-helpers/index.ts for the modular exports
|
|
8
|
-
*/
|
|
9
|
-
// Re-export everything from the modular helpers
|
|
10
|
-
export * from './route-helpers/index.js';
|
|
11
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUtaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL3Byb3hpZXMvc21hcnQtcHJveHkvdXRpbHMvcm91dGUtaGVscGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7OztHQU9HO0FBRUgsZ0RBQWdEO0FBQ2hELGNBQWMsMEJBQTBCLENBQUMifQ==
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* API Route Helper Functions
|
|
3
|
-
*
|
|
4
|
-
* This module provides utility functions for creating API route configurations.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { IRouteConfig, IRouteMatch, IRouteAction } from '../../models/route-types.js';
|
|
8
|
-
import { mergeRouteConfigs } from '../route-utils.js';
|
|
9
|
-
import { createHttpRoute } from './http-helpers.js';
|
|
10
|
-
import { createHttpsTerminateRoute } from './https-helpers.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Create an API route configuration
|
|
14
|
-
* @param domains Domain(s) to match
|
|
15
|
-
* @param apiPath API base path (e.g., "/api")
|
|
16
|
-
* @param target Target host and port
|
|
17
|
-
* @param options Additional route options
|
|
18
|
-
* @returns Route configuration object
|
|
19
|
-
*/
|
|
20
|
-
export function createApiRoute(
|
|
21
|
-
domains: string | string[],
|
|
22
|
-
apiPath: string,
|
|
23
|
-
target: { host: string | string[]; port: number },
|
|
24
|
-
options: {
|
|
25
|
-
useTls?: boolean;
|
|
26
|
-
certificate?: 'auto' | { key: string; cert: string };
|
|
27
|
-
addCorsHeaders?: boolean;
|
|
28
|
-
httpPort?: number | number[];
|
|
29
|
-
httpsPort?: number | number[];
|
|
30
|
-
name?: string;
|
|
31
|
-
[key: string]: any;
|
|
32
|
-
} = {}
|
|
33
|
-
): IRouteConfig {
|
|
34
|
-
// Normalize API path
|
|
35
|
-
const normalizedPath = apiPath.startsWith('/') ? apiPath : `/${apiPath}`;
|
|
36
|
-
const pathWithWildcard = normalizedPath.endsWith('/')
|
|
37
|
-
? `${normalizedPath}*`
|
|
38
|
-
: `${normalizedPath}/*`;
|
|
39
|
-
|
|
40
|
-
// Create route match
|
|
41
|
-
const match: IRouteMatch = {
|
|
42
|
-
ports: options.useTls
|
|
43
|
-
? (options.httpsPort || 443)
|
|
44
|
-
: (options.httpPort || 80),
|
|
45
|
-
domains,
|
|
46
|
-
path: pathWithWildcard
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// Create route action
|
|
50
|
-
const action: IRouteAction = {
|
|
51
|
-
type: 'forward',
|
|
52
|
-
targets: [target]
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// Add TLS configuration if using HTTPS
|
|
56
|
-
if (options.useTls) {
|
|
57
|
-
action.tls = {
|
|
58
|
-
mode: 'terminate',
|
|
59
|
-
certificate: options.certificate || 'auto'
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Add CORS headers if requested
|
|
64
|
-
const headers: Record<string, Record<string, string>> = {};
|
|
65
|
-
if (options.addCorsHeaders) {
|
|
66
|
-
headers.response = {
|
|
67
|
-
'Access-Control-Allow-Origin': '*',
|
|
68
|
-
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
|
69
|
-
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
|
70
|
-
'Access-Control-Max-Age': '86400'
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Create the route config
|
|
75
|
-
return {
|
|
76
|
-
match,
|
|
77
|
-
action,
|
|
78
|
-
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
79
|
-
name: options.name || `API Route ${normalizedPath} for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
|
|
80
|
-
priority: options.priority || 100, // Higher priority for specific path matches
|
|
81
|
-
...options
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Create an API Gateway route pattern
|
|
87
|
-
* @param domains Domain(s) to match
|
|
88
|
-
* @param apiBasePath Base path for API endpoints (e.g., '/api')
|
|
89
|
-
* @param target Target host and port
|
|
90
|
-
* @param options Additional route options
|
|
91
|
-
* @returns API route configuration
|
|
92
|
-
*/
|
|
93
|
-
export function createApiGatewayRoute(
|
|
94
|
-
domains: string | string[],
|
|
95
|
-
apiBasePath: string,
|
|
96
|
-
target: { host: string | string[]; port: number },
|
|
97
|
-
options: {
|
|
98
|
-
useTls?: boolean;
|
|
99
|
-
certificate?: 'auto' | { key: string; cert: string };
|
|
100
|
-
addCorsHeaders?: boolean;
|
|
101
|
-
[key: string]: any;
|
|
102
|
-
} = {}
|
|
103
|
-
): IRouteConfig {
|
|
104
|
-
// Normalize apiBasePath to ensure it starts with / and doesn't end with /
|
|
105
|
-
const normalizedPath = apiBasePath.startsWith('/')
|
|
106
|
-
? apiBasePath
|
|
107
|
-
: `/${apiBasePath}`;
|
|
108
|
-
|
|
109
|
-
// Add wildcard to path to match all API endpoints
|
|
110
|
-
const apiPath = normalizedPath.endsWith('/')
|
|
111
|
-
? `${normalizedPath}*`
|
|
112
|
-
: `${normalizedPath}/*`;
|
|
113
|
-
|
|
114
|
-
// Create base route
|
|
115
|
-
const baseRoute = options.useTls
|
|
116
|
-
? createHttpsTerminateRoute(domains, target, {
|
|
117
|
-
certificate: options.certificate || 'auto'
|
|
118
|
-
})
|
|
119
|
-
: createHttpRoute(domains, target);
|
|
120
|
-
|
|
121
|
-
// Add API-specific configurations
|
|
122
|
-
const apiRoute: Partial<IRouteConfig> = {
|
|
123
|
-
match: {
|
|
124
|
-
...baseRoute.match,
|
|
125
|
-
path: apiPath
|
|
126
|
-
},
|
|
127
|
-
name: options.name || `API Gateway: ${apiPath} -> ${Array.isArray(target.host) ? target.host.join(', ') : target.host}:${target.port}`,
|
|
128
|
-
priority: options.priority || 100 // Higher priority for specific path matching
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
// Add CORS headers if requested
|
|
132
|
-
if (options.addCorsHeaders) {
|
|
133
|
-
apiRoute.headers = {
|
|
134
|
-
response: {
|
|
135
|
-
'Access-Control-Allow-Origin': '*',
|
|
136
|
-
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
|
137
|
-
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
|
138
|
-
'Access-Control-Max-Age': '86400'
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return mergeRouteConfigs(baseRoute, apiRoute);
|
|
144
|
-
}
|