@push.rocks/smartproxy 21.1.7 → 22.6.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.
Files changed (155) hide show
  1. package/changelog.md +109 -0
  2. package/dist_rust/rustproxy +0 -0
  3. package/dist_ts/00_commitinfo_data.js +1 -1
  4. package/dist_ts/core/utils/shared-security-manager.d.ts +17 -0
  5. package/dist_ts/core/utils/shared-security-manager.js +66 -1
  6. package/dist_ts/index.d.ts +1 -5
  7. package/dist_ts/index.js +3 -9
  8. package/dist_ts/protocols/common/fragment-handler.js +5 -1
  9. package/dist_ts/proxies/http-proxy/default-certificates.d.ts +54 -0
  10. package/dist_ts/proxies/http-proxy/default-certificates.js +127 -0
  11. package/dist_ts/proxies/http-proxy/http-proxy.d.ts +1 -1
  12. package/dist_ts/proxies/http-proxy/http-proxy.js +9 -14
  13. package/dist_ts/proxies/http-proxy/index.d.ts +5 -1
  14. package/dist_ts/proxies/http-proxy/index.js +6 -2
  15. package/dist_ts/proxies/http-proxy/security-manager.d.ts +4 -12
  16. package/dist_ts/proxies/http-proxy/security-manager.js +66 -99
  17. package/dist_ts/proxies/index.d.ts +1 -5
  18. package/dist_ts/proxies/index.js +2 -6
  19. package/dist_ts/proxies/nftables-proxy/index.d.ts +1 -0
  20. package/dist_ts/proxies/nftables-proxy/index.js +2 -1
  21. package/dist_ts/proxies/nftables-proxy/nftables-proxy.d.ts +4 -26
  22. package/dist_ts/proxies/nftables-proxy/nftables-proxy.js +84 -236
  23. package/dist_ts/proxies/nftables-proxy/utils/index.d.ts +9 -0
  24. package/dist_ts/proxies/nftables-proxy/utils/index.js +12 -0
  25. package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.d.ts +66 -0
  26. package/dist_ts/proxies/nftables-proxy/utils/nft-command-executor.js +131 -0
  27. package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.d.ts +39 -0
  28. package/dist_ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.js +112 -0
  29. package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.d.ts +59 -0
  30. package/dist_ts/proxies/nftables-proxy/utils/nft-rule-validator.js +130 -0
  31. package/dist_ts/proxies/smart-proxy/certificate-manager.js +4 -3
  32. package/dist_ts/proxies/smart-proxy/connection-manager.d.ts +13 -2
  33. package/dist_ts/proxies/smart-proxy/connection-manager.js +16 -6
  34. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +35 -10
  35. package/dist_ts/proxies/smart-proxy/index.d.ts +5 -10
  36. package/dist_ts/proxies/smart-proxy/index.js +7 -13
  37. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -3
  38. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +17 -0
  39. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +72 -9
  40. package/dist_ts/proxies/smart-proxy/route-preprocessor.d.ts +37 -0
  41. package/dist_ts/proxies/smart-proxy/route-preprocessor.js +103 -0
  42. package/dist_ts/proxies/smart-proxy/rust-binary-locator.d.ts +23 -0
  43. package/dist_ts/proxies/smart-proxy/rust-binary-locator.js +104 -0
  44. package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.d.ts +74 -0
  45. package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.js +146 -0
  46. package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.d.ts +49 -0
  47. package/dist_ts/proxies/smart-proxy/rust-proxy-bridge.js +259 -0
  48. package/dist_ts/proxies/smart-proxy/security-manager.d.ts +14 -12
  49. package/dist_ts/proxies/smart-proxy/security-manager.js +80 -74
  50. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +39 -157
  51. package/dist_ts/proxies/smart-proxy/smart-proxy.js +224 -622
  52. package/dist_ts/proxies/smart-proxy/socket-handler-server.d.ts +45 -0
  53. package/dist_ts/proxies/smart-proxy/socket-handler-server.js +253 -0
  54. package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +2 -9
  55. package/dist_ts/proxies/smart-proxy/tls-manager.js +3 -26
  56. package/dist_ts/proxies/smart-proxy/utils/index.d.ts +1 -1
  57. package/dist_ts/proxies/smart-proxy/utils/index.js +3 -4
  58. package/dist_ts/proxies/smart-proxy/utils/route-helpers/api-helpers.d.ts +49 -0
  59. package/dist_ts/proxies/smart-proxy/utils/route-helpers/api-helpers.js +108 -0
  60. package/dist_ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.d.ts +57 -0
  61. package/dist_ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.js +89 -0
  62. package/dist_ts/proxies/smart-proxy/utils/route-helpers/http-helpers.d.ts +17 -0
  63. package/dist_ts/proxies/smart-proxy/utils/route-helpers/http-helpers.js +32 -0
  64. package/dist_ts/proxies/smart-proxy/utils/route-helpers/https-helpers.d.ts +68 -0
  65. package/dist_ts/proxies/smart-proxy/utils/route-helpers/https-helpers.js +117 -0
  66. package/dist_ts/proxies/smart-proxy/utils/route-helpers/index.d.ts +17 -0
  67. package/dist_ts/proxies/smart-proxy/utils/route-helpers/index.js +27 -0
  68. package/dist_ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.d.ts +63 -0
  69. package/dist_ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.js +105 -0
  70. package/dist_ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.d.ts +83 -0
  71. package/dist_ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.js +126 -0
  72. package/dist_ts/proxies/smart-proxy/utils/route-helpers/security-helpers.d.ts +47 -0
  73. package/dist_ts/proxies/smart-proxy/utils/route-helpers/security-helpers.js +66 -0
  74. package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.d.ts +70 -0
  75. package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.js +287 -0
  76. package/dist_ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.d.ts +46 -0
  77. package/dist_ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.js +67 -0
  78. package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +4 -457
  79. package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +6 -950
  80. package/dist_ts/proxies/smart-proxy/utils/route-utils.js +2 -2
  81. package/dist_ts/proxies/smart-proxy/utils/route-validator.d.ts +67 -1
  82. package/dist_ts/proxies/smart-proxy/utils/route-validator.js +251 -3
  83. package/dist_ts/routing/index.d.ts +1 -1
  84. package/dist_ts/routing/index.js +3 -3
  85. package/dist_ts/routing/models/http-types.d.ts +119 -4
  86. package/dist_ts/routing/models/http-types.js +93 -5
  87. package/npmextra.json +12 -6
  88. package/package.json +34 -24
  89. package/readme.hints.md +184 -1
  90. package/readme.md +580 -266
  91. package/ts/00_commitinfo_data.ts +1 -1
  92. package/ts/core/utils/shared-security-manager.ts +98 -13
  93. package/ts/index.ts +4 -12
  94. package/ts/protocols/common/fragment-handler.ts +4 -0
  95. package/ts/proxies/index.ts +1 -9
  96. package/ts/proxies/nftables-proxy/index.ts +1 -0
  97. package/ts/proxies/nftables-proxy/nftables-proxy.ts +116 -290
  98. package/ts/proxies/nftables-proxy/utils/index.ts +38 -0
  99. package/ts/proxies/nftables-proxy/utils/nft-command-executor.ts +162 -0
  100. package/ts/proxies/nftables-proxy/utils/nft-port-spec-normalizer.ts +125 -0
  101. package/ts/proxies/nftables-proxy/utils/nft-rule-validator.ts +156 -0
  102. package/ts/proxies/smart-proxy/index.ts +6 -13
  103. package/ts/proxies/smart-proxy/models/interfaces.ts +6 -5
  104. package/ts/proxies/smart-proxy/route-preprocessor.ts +122 -0
  105. package/ts/proxies/smart-proxy/rust-binary-locator.ts +112 -0
  106. package/ts/proxies/smart-proxy/rust-metrics-adapter.ts +161 -0
  107. package/ts/proxies/smart-proxy/rust-proxy-bridge.ts +310 -0
  108. package/ts/proxies/smart-proxy/smart-proxy.ts +282 -800
  109. package/ts/proxies/smart-proxy/socket-handler-server.ts +279 -0
  110. package/ts/proxies/smart-proxy/utils/index.ts +3 -5
  111. package/ts/proxies/smart-proxy/utils/route-helpers/api-helpers.ts +144 -0
  112. package/ts/proxies/smart-proxy/utils/route-helpers/dynamic-helpers.ts +124 -0
  113. package/ts/proxies/smart-proxy/utils/route-helpers/http-helpers.ts +40 -0
  114. package/ts/proxies/smart-proxy/utils/route-helpers/https-helpers.ts +163 -0
  115. package/ts/proxies/smart-proxy/utils/route-helpers/index.ts +62 -0
  116. package/ts/proxies/smart-proxy/utils/route-helpers/load-balancer-helpers.ts +154 -0
  117. package/ts/proxies/smart-proxy/utils/route-helpers/nftables-helpers.ts +202 -0
  118. package/ts/proxies/smart-proxy/utils/route-helpers/security-helpers.ts +96 -0
  119. package/ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.ts +337 -0
  120. package/ts/proxies/smart-proxy/utils/route-helpers/websocket-helpers.ts +98 -0
  121. package/ts/proxies/smart-proxy/utils/route-helpers.ts +5 -1302
  122. package/ts/proxies/smart-proxy/utils/route-utils.ts +1 -1
  123. package/ts/proxies/smart-proxy/utils/route-validator.ts +274 -4
  124. package/ts/routing/index.ts +2 -2
  125. package/ts/routing/models/http-types.ts +147 -4
  126. package/ts/proxies/http-proxy/certificate-manager.ts +0 -244
  127. package/ts/proxies/http-proxy/connection-pool.ts +0 -228
  128. package/ts/proxies/http-proxy/context-creator.ts +0 -145
  129. package/ts/proxies/http-proxy/function-cache.ts +0 -279
  130. package/ts/proxies/http-proxy/handlers/index.ts +0 -5
  131. package/ts/proxies/http-proxy/http-proxy.ts +0 -675
  132. package/ts/proxies/http-proxy/http-request-handler.ts +0 -331
  133. package/ts/proxies/http-proxy/http2-request-handler.ts +0 -255
  134. package/ts/proxies/http-proxy/index.ts +0 -13
  135. package/ts/proxies/http-proxy/models/http-types.ts +0 -148
  136. package/ts/proxies/http-proxy/models/index.ts +0 -5
  137. package/ts/proxies/http-proxy/models/types.ts +0 -125
  138. package/ts/proxies/http-proxy/request-handler.ts +0 -878
  139. package/ts/proxies/http-proxy/security-manager.ts +0 -433
  140. package/ts/proxies/http-proxy/websocket-handler.ts +0 -581
  141. package/ts/proxies/smart-proxy/acme-state-manager.ts +0 -112
  142. package/ts/proxies/smart-proxy/cert-store.ts +0 -92
  143. package/ts/proxies/smart-proxy/certificate-manager.ts +0 -894
  144. package/ts/proxies/smart-proxy/connection-manager.ts +0 -796
  145. package/ts/proxies/smart-proxy/http-proxy-bridge.ts +0 -187
  146. package/ts/proxies/smart-proxy/metrics-collector.ts +0 -453
  147. package/ts/proxies/smart-proxy/nftables-manager.ts +0 -271
  148. package/ts/proxies/smart-proxy/port-manager.ts +0 -358
  149. package/ts/proxies/smart-proxy/route-connection-handler.ts +0 -1640
  150. package/ts/proxies/smart-proxy/route-orchestrator.ts +0 -297
  151. package/ts/proxies/smart-proxy/security-manager.ts +0 -257
  152. package/ts/proxies/smart-proxy/throughput-tracker.ts +0 -138
  153. package/ts/proxies/smart-proxy/timeout-manager.ts +0 -196
  154. package/ts/proxies/smart-proxy/tls-manager.ts +0 -207
  155. package/ts/proxies/smart-proxy/utils/route-validators.ts +0 -283
@@ -0,0 +1,279 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import { logger } from '../../core/utils/logger.js';
3
+ import type { IRouteConfig, IRouteContext } from './models/route-types.js';
4
+ import type { RoutePreprocessor } from './route-preprocessor.js';
5
+
6
+ /**
7
+ * Unix domain socket server that receives relayed connections from the Rust proxy.
8
+ *
9
+ * When Rust encounters a route of type `socket-handler`, it connects to this
10
+ * Unix socket, sends a JSON metadata line, then proxies the raw TCP bytes.
11
+ * This server reads the metadata, finds the original JS handler, builds an
12
+ * IRouteContext, and hands the socket to the handler.
13
+ */
14
+ export class SocketHandlerServer {
15
+ private server: plugins.net.Server | null = null;
16
+ private socketPath: string;
17
+ private preprocessor: RoutePreprocessor;
18
+ private activeSockets = new Set<plugins.net.Socket>();
19
+
20
+ constructor(preprocessor: RoutePreprocessor) {
21
+ this.preprocessor = preprocessor;
22
+ this.socketPath = `/tmp/smartproxy-relay-${process.pid}.sock`;
23
+ }
24
+
25
+ /**
26
+ * The Unix socket path this server listens on.
27
+ */
28
+ public getSocketPath(): string {
29
+ return this.socketPath;
30
+ }
31
+
32
+ /**
33
+ * Start listening for relayed connections from Rust.
34
+ */
35
+ public async start(): Promise<void> {
36
+ // Clean up stale socket file
37
+ try {
38
+ await plugins.fs.promises.unlink(this.socketPath);
39
+ } catch {
40
+ // Ignore if doesn't exist
41
+ }
42
+
43
+ return new Promise<void>((resolve, reject) => {
44
+ this.server = plugins.net.createServer((socket) => {
45
+ this.activeSockets.add(socket);
46
+ socket.on('close', () => this.activeSockets.delete(socket));
47
+ this.handleConnection(socket);
48
+ });
49
+
50
+ this.server.on('error', (err) => {
51
+ logger.log('error', `SocketHandlerServer error: ${err.message}`, { component: 'socket-handler-server' });
52
+ });
53
+
54
+ this.server.listen(this.socketPath, () => {
55
+ logger.log('info', `SocketHandlerServer listening on ${this.socketPath}`, { component: 'socket-handler-server' });
56
+ resolve();
57
+ });
58
+
59
+ this.server.on('error', reject);
60
+ });
61
+ }
62
+
63
+ /**
64
+ * Stop the server and clean up.
65
+ */
66
+ public async stop(): Promise<void> {
67
+ // Destroy all active connections first
68
+ for (const socket of this.activeSockets) {
69
+ socket.destroy();
70
+ }
71
+ this.activeSockets.clear();
72
+
73
+ if (this.server) {
74
+ return new Promise<void>((resolve) => {
75
+ this.server!.close(() => {
76
+ this.server = null;
77
+ // Clean up socket file
78
+ plugins.fs.unlink(this.socketPath, () => resolve());
79
+ });
80
+ });
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Handle an incoming relayed connection from Rust.
86
+ *
87
+ * Protocol: Rust sends a single JSON line with metadata, then raw bytes follow.
88
+ * JSON format: { "routeKey": "my-route", "remoteIP": "1.2.3.4", "remotePort": 12345,
89
+ * "localPort": 443, "isTLS": true, "domain": "example.com" }
90
+ */
91
+ private handleConnection(socket: plugins.net.Socket): void {
92
+ let metadataBuffer = '';
93
+ let metadataParsed = false;
94
+
95
+ const onData = (chunk: Buffer) => {
96
+ if (metadataParsed) return;
97
+
98
+ metadataBuffer += chunk.toString('utf8');
99
+ const newlineIndex = metadataBuffer.indexOf('\n');
100
+
101
+ if (newlineIndex === -1) {
102
+ // Haven't received full metadata line yet
103
+ if (metadataBuffer.length > 8192) {
104
+ logger.log('error', 'Socket handler metadata too large, closing', { component: 'socket-handler-server' });
105
+ socket.destroy();
106
+ }
107
+ return;
108
+ }
109
+
110
+ metadataParsed = true;
111
+ socket.removeListener('data', onData);
112
+ socket.pause(); // Prevent data loss between handler removal and pipe setup
113
+
114
+ const metadataJson = metadataBuffer.slice(0, newlineIndex);
115
+ const remainingData = metadataBuffer.slice(newlineIndex + 1);
116
+
117
+ let metadata: any;
118
+ try {
119
+ metadata = JSON.parse(metadataJson);
120
+ } catch {
121
+ logger.log('error', `Invalid socket handler metadata JSON: ${metadataJson.slice(0, 200)}`, { component: 'socket-handler-server' });
122
+ socket.destroy();
123
+ return;
124
+ }
125
+
126
+ this.dispatchToHandler(socket, metadata, remainingData);
127
+ };
128
+
129
+ socket.on('data', onData);
130
+ socket.on('error', (err) => {
131
+ logger.log('error', `Socket handler relay error: ${err.message}`, { component: 'socket-handler-server' });
132
+ });
133
+ }
134
+
135
+ /**
136
+ * Dispatch a relayed connection to the appropriate JS handler.
137
+ */
138
+ private dispatchToHandler(socket: plugins.net.Socket, metadata: any, remainingData: string): void {
139
+ const routeKey = metadata.routeKey as string;
140
+ if (!routeKey) {
141
+ logger.log('error', 'Socket handler relay missing routeKey', { component: 'socket-handler-server' });
142
+ socket.destroy();
143
+ return;
144
+ }
145
+
146
+ const originalRoute = this.preprocessor.getOriginalRoute(routeKey);
147
+ if (!originalRoute) {
148
+ logger.log('error', `No handler found for route: ${routeKey}`, { component: 'socket-handler-server' });
149
+ socket.destroy();
150
+ return;
151
+ }
152
+
153
+ // Build route context
154
+ const context: IRouteContext = {
155
+ port: metadata.localPort || 0,
156
+ domain: metadata.domain,
157
+ clientIp: metadata.remoteIP || 'unknown',
158
+ serverIp: '0.0.0.0',
159
+ path: metadata.path,
160
+ isTls: metadata.isTLS || false,
161
+ tlsVersion: metadata.tlsVersion,
162
+ routeName: originalRoute.name,
163
+ routeId: originalRoute.id,
164
+ timestamp: Date.now(),
165
+ connectionId: metadata.connectionId || `relay-${Date.now()}`,
166
+ };
167
+
168
+ // If there was remaining data after the metadata line, push it back
169
+ if (remainingData.length > 0) {
170
+ socket.unshift(Buffer.from(remainingData, 'utf8'));
171
+ }
172
+
173
+ const handler = originalRoute.action.socketHandler;
174
+ if (handler) {
175
+ // Route has an explicit socket handler callback
176
+ try {
177
+ const result = handler(socket, context);
178
+ // If the handler is async, wait for it to finish setup before resuming.
179
+ // This prevents data loss when async handlers need to do work before
180
+ // attaching their `data` listeners.
181
+ if (result && typeof (result as any).then === 'function') {
182
+ (result as any).then(() => {
183
+ socket.resume();
184
+ }).catch((err: any) => {
185
+ logger.log('error', `Async socket handler rejected for route ${routeKey}: ${err.message}`, { component: 'socket-handler-server' });
186
+ socket.destroy();
187
+ });
188
+ } else {
189
+ // Synchronous handler — listeners are already attached, safe to resume.
190
+ socket.resume();
191
+ }
192
+ } catch (err: any) {
193
+ logger.log('error', `Socket handler threw for route ${routeKey}: ${err.message}`, { component: 'socket-handler-server' });
194
+ socket.destroy();
195
+ }
196
+ return;
197
+ }
198
+
199
+ // Route has dynamic host/port functions - resolve and forward
200
+ if (originalRoute.action.targets && originalRoute.action.targets.length > 0) {
201
+ this.forwardDynamicRoute(socket, originalRoute, context);
202
+ return;
203
+ }
204
+
205
+ logger.log('error', `Route ${routeKey} has no socketHandler and no targets`, { component: 'socket-handler-server' });
206
+ socket.destroy();
207
+ }
208
+
209
+ /**
210
+ * Forward a connection to a dynamically resolved target.
211
+ * Used for routes with function-based host/port that Rust cannot handle.
212
+ */
213
+ private forwardDynamicRoute(socket: plugins.net.Socket, route: IRouteConfig, context: IRouteContext): void {
214
+ const targets = route.action.targets!;
215
+ // Pick a target (round-robin would be ideal, but simple random for now)
216
+ const target = targets[Math.floor(Math.random() * targets.length)];
217
+
218
+ // Resolve host
219
+ let host: string;
220
+ if (typeof target.host === 'function') {
221
+ try {
222
+ const result = target.host(context);
223
+ host = Array.isArray(result) ? result[Math.floor(Math.random() * result.length)] : result;
224
+ } catch (err: any) {
225
+ logger.log('error', `Dynamic host function failed: ${err.message}`, { component: 'socket-handler-server' });
226
+ socket.destroy();
227
+ return;
228
+ }
229
+ } else if (typeof target.host === 'string') {
230
+ host = target.host;
231
+ } else if (Array.isArray(target.host)) {
232
+ host = target.host[Math.floor(Math.random() * target.host.length)];
233
+ } else {
234
+ host = 'localhost';
235
+ }
236
+
237
+ // Resolve port
238
+ let port: number;
239
+ if (typeof target.port === 'function') {
240
+ try {
241
+ port = target.port(context);
242
+ } catch (err: any) {
243
+ logger.log('error', `Dynamic port function failed: ${err.message}`, { component: 'socket-handler-server' });
244
+ socket.destroy();
245
+ return;
246
+ }
247
+ } else if (typeof target.port === 'number') {
248
+ port = target.port;
249
+ } else {
250
+ port = context.port;
251
+ }
252
+
253
+ logger.log('debug', `Dynamic forward: ${context.clientIp} -> ${host}:${port}`, { component: 'socket-handler-server' });
254
+
255
+ // Connect to the resolved target
256
+ const backend = plugins.net.connect(port, host, () => {
257
+ // Pipe bidirectionally
258
+ socket.pipe(backend);
259
+ backend.pipe(socket);
260
+ });
261
+
262
+ backend.on('error', (err) => {
263
+ logger.log('error', `Dynamic forward backend error: ${err.message}`, { component: 'socket-handler-server' });
264
+ socket.destroy();
265
+ });
266
+
267
+ socket.on('error', () => {
268
+ backend.destroy();
269
+ });
270
+
271
+ socket.on('close', () => {
272
+ backend.destroy();
273
+ });
274
+
275
+ backend.on('close', () => {
276
+ socket.destroy();
277
+ });
278
+ }
279
+ }
@@ -8,8 +8,8 @@
8
8
  // Export route helpers for creating route configurations
9
9
  export * from './route-helpers.js';
10
10
 
11
- // Export route validators for validating route configurations
12
- export * from './route-validators.js';
11
+ // Export route validator (class-based and functional API)
12
+ export * from './route-validator.js';
13
13
 
14
14
  // Export route utilities for route operations
15
15
  export * from './route-utils.js';
@@ -20,6 +20,4 @@ export {
20
20
  addRateLimiting,
21
21
  addBasicAuth,
22
22
  addJwtAuth
23
- } from './route-helpers.js';
24
-
25
- // Migration utilities have been removed as they are no longer needed
23
+ } from './route-helpers.js';
@@ -0,0 +1,144 @@
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
+ }
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Dynamic Route Helper Functions
3
+ *
4
+ * This module provides utility functions for creating dynamic routes
5
+ * with context-based host and port mapping.
6
+ */
7
+
8
+ import type { IRouteConfig, IRouteMatch, IRouteAction, TPortRange, IRouteContext } from '../../models/route-types.js';
9
+
10
+ /**
11
+ * Create a helper function that applies a port offset
12
+ * @param offset The offset to apply to the matched port
13
+ * @returns A function that adds the offset to the matched port
14
+ */
15
+ export function createPortOffset(offset: number): (context: IRouteContext) => number {
16
+ return (context: IRouteContext) => context.port + offset;
17
+ }
18
+
19
+ /**
20
+ * Create a port mapping route with context-based port function
21
+ * @param options Port mapping route options
22
+ * @returns Route configuration object
23
+ */
24
+ export function createPortMappingRoute(options: {
25
+ sourcePortRange: TPortRange;
26
+ targetHost: string | string[] | ((context: IRouteContext) => string | string[]);
27
+ portMapper: (context: IRouteContext) => number;
28
+ name?: string;
29
+ domains?: string | string[];
30
+ priority?: number;
31
+ [key: string]: any;
32
+ }): IRouteConfig {
33
+ // Create route match
34
+ const match: IRouteMatch = {
35
+ ports: options.sourcePortRange,
36
+ domains: options.domains
37
+ };
38
+
39
+ // Create route action
40
+ const action: IRouteAction = {
41
+ type: 'forward',
42
+ targets: [{
43
+ host: options.targetHost,
44
+ port: options.portMapper
45
+ }]
46
+ };
47
+
48
+ // Create the route config
49
+ return {
50
+ match,
51
+ action,
52
+ name: options.name || `Port Mapping Route for ${options.domains || 'all domains'}`,
53
+ priority: options.priority,
54
+ ...options
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Create a simple offset port mapping route
60
+ * @param options Offset port mapping route options
61
+ * @returns Route configuration object
62
+ */
63
+ export function createOffsetPortMappingRoute(options: {
64
+ ports: TPortRange;
65
+ targetHost: string | string[];
66
+ offset: number;
67
+ name?: string;
68
+ domains?: string | string[];
69
+ priority?: number;
70
+ [key: string]: any;
71
+ }): IRouteConfig {
72
+ return createPortMappingRoute({
73
+ sourcePortRange: options.ports,
74
+ targetHost: options.targetHost,
75
+ portMapper: (context) => context.port + options.offset,
76
+ name: options.name || `Offset Mapping (${options.offset > 0 ? '+' : ''}${options.offset}) for ${options.domains || 'all domains'}`,
77
+ domains: options.domains,
78
+ priority: options.priority,
79
+ ...options
80
+ });
81
+ }
82
+
83
+ /**
84
+ * Create a dynamic route with context-based host and port mapping
85
+ * @param options Dynamic route options
86
+ * @returns Route configuration object
87
+ */
88
+ export function createDynamicRoute(options: {
89
+ ports: TPortRange;
90
+ targetHost: (context: IRouteContext) => string | string[];
91
+ portMapper: (context: IRouteContext) => number;
92
+ name?: string;
93
+ domains?: string | string[];
94
+ path?: string;
95
+ clientIp?: string[];
96
+ priority?: number;
97
+ [key: string]: any;
98
+ }): IRouteConfig {
99
+ // Create route match
100
+ const match: IRouteMatch = {
101
+ ports: options.ports,
102
+ domains: options.domains,
103
+ path: options.path,
104
+ clientIp: options.clientIp
105
+ };
106
+
107
+ // Create route action
108
+ const action: IRouteAction = {
109
+ type: 'forward',
110
+ targets: [{
111
+ host: options.targetHost,
112
+ port: options.portMapper
113
+ }]
114
+ };
115
+
116
+ // Create the route config
117
+ return {
118
+ match,
119
+ action,
120
+ name: options.name || `Dynamic Route for ${options.domains || 'all domains'}`,
121
+ priority: options.priority,
122
+ ...options
123
+ };
124
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * HTTP Route Helper Functions
3
+ *
4
+ * This module provides utility functions for creating HTTP route configurations.
5
+ */
6
+
7
+ import type { IRouteConfig, IRouteMatch, IRouteAction } from '../../models/route-types.js';
8
+
9
+ /**
10
+ * Create an HTTP-only route configuration
11
+ * @param domains Domain(s) to match
12
+ * @param target Target host and port
13
+ * @param options Additional route options
14
+ * @returns Route configuration object
15
+ */
16
+ export function createHttpRoute(
17
+ domains: string | string[],
18
+ target: { host: string | string[]; port: number },
19
+ options: Partial<IRouteConfig> = {}
20
+ ): IRouteConfig {
21
+ // Create route match
22
+ const match: IRouteMatch = {
23
+ ports: options.match?.ports || 80,
24
+ domains
25
+ };
26
+
27
+ // Create route action
28
+ const action: IRouteAction = {
29
+ type: 'forward',
30
+ targets: [target]
31
+ };
32
+
33
+ // Create the route config
34
+ return {
35
+ match,
36
+ action,
37
+ name: options.name || `HTTP Route for ${Array.isArray(domains) ? domains.join(', ') : domains}`,
38
+ ...options
39
+ };
40
+ }