@push.rocks/smartproxy 16.0.2 → 16.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +147 -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 -3
- 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 +195 -86
- 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 +78 -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
|
@@ -6,7 +6,7 @@ import { SecurityManager } from './security-manager.js';
|
|
|
6
6
|
import { TlsManager } from './tls-manager.js';
|
|
7
7
|
import { NetworkProxyBridge } from './network-proxy-bridge.js';
|
|
8
8
|
import { TimeoutManager } from './timeout-manager.js';
|
|
9
|
-
|
|
9
|
+
import { PortManager } from './port-manager.js';
|
|
10
10
|
import { RouteManager } from './route-manager.js';
|
|
11
11
|
import { RouteConnectionHandler } from './route-connection-handler.js';
|
|
12
12
|
|
|
@@ -39,7 +39,8 @@ import type { IRouteConfig } from './models/route-types.js';
|
|
|
39
39
|
* - Advanced options (timeout, headers, etc.)
|
|
40
40
|
*/
|
|
41
41
|
export class SmartProxy extends plugins.EventEmitter {
|
|
42
|
-
|
|
42
|
+
// Port manager handles dynamic listener management
|
|
43
|
+
private portManager: PortManager;
|
|
43
44
|
private connectionLogger: NodeJS.Timeout | null = null;
|
|
44
45
|
private isShuttingDown: boolean = false;
|
|
45
46
|
|
|
@@ -49,8 +50,7 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
49
50
|
private tlsManager: TlsManager;
|
|
50
51
|
private networkProxyBridge: NetworkProxyBridge;
|
|
51
52
|
private timeoutManager: TimeoutManager;
|
|
52
|
-
//
|
|
53
|
-
private routeManager: RouteManager;
|
|
53
|
+
public routeManager: RouteManager; // Made public for route management
|
|
54
54
|
private routeConnectionHandler: RouteConnectionHandler;
|
|
55
55
|
|
|
56
56
|
// Port80Handler for ACME certificate management
|
|
@@ -151,8 +151,6 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
151
151
|
// Create the route manager
|
|
152
152
|
this.routeManager = new RouteManager(this.settings);
|
|
153
153
|
|
|
154
|
-
// Create port range manager
|
|
155
|
-
// this.portRangeManager = new PortRangeManager(this.settings);
|
|
156
154
|
|
|
157
155
|
// Create other required components
|
|
158
156
|
this.tlsManager = new TlsManager(this.settings);
|
|
@@ -168,6 +166,9 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
168
166
|
this.timeoutManager,
|
|
169
167
|
this.routeManager
|
|
170
168
|
);
|
|
169
|
+
|
|
170
|
+
// Initialize port manager
|
|
171
|
+
this.portManager = new PortManager(this.settings, this.routeConnectionHandler);
|
|
171
172
|
}
|
|
172
173
|
|
|
173
174
|
/**
|
|
@@ -271,33 +272,8 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
271
272
|
// Get listening ports from RouteManager
|
|
272
273
|
const listeningPorts = this.routeManager.getListeningPorts();
|
|
273
274
|
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
const server = plugins.net.createServer((socket) => {
|
|
277
|
-
// Check if shutting down
|
|
278
|
-
if (this.isShuttingDown) {
|
|
279
|
-
socket.end();
|
|
280
|
-
socket.destroy();
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Delegate to route connection handler
|
|
285
|
-
this.routeConnectionHandler.handleConnection(socket);
|
|
286
|
-
}).on('error', (err: Error) => {
|
|
287
|
-
console.log(`Server Error on port ${port}: ${err.message}`);
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
server.listen(port, () => {
|
|
291
|
-
const isNetworkProxyPort = this.settings.useNetworkProxy?.includes(port);
|
|
292
|
-
console.log(
|
|
293
|
-
`SmartProxy -> OK: Now listening on port ${port}${
|
|
294
|
-
isNetworkProxyPort ? ' (NetworkProxy forwarding enabled)' : ''
|
|
295
|
-
}`
|
|
296
|
-
);
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
this.netServers.push(server);
|
|
300
|
-
}
|
|
275
|
+
// Start port listeners using the PortManager
|
|
276
|
+
await this.portManager.addPorts(listeningPorts);
|
|
301
277
|
|
|
302
278
|
// Set up periodic connection logging and inactivity checks
|
|
303
279
|
this.connectionLogger = setInterval(() => {
|
|
@@ -383,6 +359,7 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
383
359
|
public async stop() {
|
|
384
360
|
console.log('SmartProxy shutting down...');
|
|
385
361
|
this.isShuttingDown = true;
|
|
362
|
+
this.portManager.setShuttingDown(true);
|
|
386
363
|
|
|
387
364
|
// Stop CertProvisioner if active
|
|
388
365
|
if (this.certProvisioner) {
|
|
@@ -401,31 +378,14 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
401
378
|
}
|
|
402
379
|
}
|
|
403
380
|
|
|
404
|
-
// Stop accepting new connections
|
|
405
|
-
const closeServerPromises: Promise<void>[] = this.netServers.map(
|
|
406
|
-
(server) =>
|
|
407
|
-
new Promise<void>((resolve) => {
|
|
408
|
-
if (!server.listening) {
|
|
409
|
-
resolve();
|
|
410
|
-
return;
|
|
411
|
-
}
|
|
412
|
-
server.close((err) => {
|
|
413
|
-
if (err) {
|
|
414
|
-
console.log(`Error closing server: ${err.message}`);
|
|
415
|
-
}
|
|
416
|
-
resolve();
|
|
417
|
-
});
|
|
418
|
-
})
|
|
419
|
-
);
|
|
420
|
-
|
|
421
381
|
// Stop the connection logger
|
|
422
382
|
if (this.connectionLogger) {
|
|
423
383
|
clearInterval(this.connectionLogger);
|
|
424
384
|
this.connectionLogger = null;
|
|
425
385
|
}
|
|
426
386
|
|
|
427
|
-
//
|
|
428
|
-
await
|
|
387
|
+
// Stop all port listeners
|
|
388
|
+
await this.portManager.closeAll();
|
|
429
389
|
console.log('All servers closed. Cleaning up active connections...');
|
|
430
390
|
|
|
431
391
|
// Clean up all active connections
|
|
@@ -434,8 +394,6 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
434
394
|
// Stop NetworkProxy
|
|
435
395
|
await this.networkProxyBridge.stop();
|
|
436
396
|
|
|
437
|
-
// Clear all servers
|
|
438
|
-
this.netServers = [];
|
|
439
397
|
|
|
440
398
|
console.log('SmartProxy shutdown complete.');
|
|
441
399
|
}
|
|
@@ -479,6 +437,12 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
479
437
|
// Update routes in RouteManager
|
|
480
438
|
this.routeManager.updateRoutes(newRoutes);
|
|
481
439
|
|
|
440
|
+
// Get the new set of required ports
|
|
441
|
+
const requiredPorts = this.routeManager.getListeningPorts();
|
|
442
|
+
|
|
443
|
+
// Update port listeners to match the new configuration
|
|
444
|
+
await this.portManager.updatePorts(requiredPorts);
|
|
445
|
+
|
|
482
446
|
// If NetworkProxy is initialized, resync the configurations
|
|
483
447
|
if (this.networkProxyBridge.getNetworkProxy()) {
|
|
484
448
|
await this.networkProxyBridge.syncRoutesToNetworkProxy(newRoutes);
|
|
@@ -609,6 +573,41 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
609
573
|
return true;
|
|
610
574
|
}
|
|
611
575
|
|
|
576
|
+
/**
|
|
577
|
+
* Add a new listening port without changing the route configuration
|
|
578
|
+
*
|
|
579
|
+
* This allows you to add a port listener without updating routes.
|
|
580
|
+
* Useful for preparing to listen on a port before adding routes for it.
|
|
581
|
+
*
|
|
582
|
+
* @param port The port to start listening on
|
|
583
|
+
* @returns Promise that resolves when the port is listening
|
|
584
|
+
*/
|
|
585
|
+
public async addListeningPort(port: number): Promise<void> {
|
|
586
|
+
return this.portManager.addPort(port);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Stop listening on a specific port without changing the route configuration
|
|
591
|
+
*
|
|
592
|
+
* This allows you to stop a port listener without updating routes.
|
|
593
|
+
* Useful for temporary maintenance or port changes.
|
|
594
|
+
*
|
|
595
|
+
* @param port The port to stop listening on
|
|
596
|
+
* @returns Promise that resolves when the port is closed
|
|
597
|
+
*/
|
|
598
|
+
public async removeListeningPort(port: number): Promise<void> {
|
|
599
|
+
return this.portManager.removePort(port);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Get a list of all ports currently being listened on
|
|
604
|
+
*
|
|
605
|
+
* @returns Array of port numbers
|
|
606
|
+
*/
|
|
607
|
+
public getListeningPorts(): number[] {
|
|
608
|
+
return this.portManager.getListeningPorts();
|
|
609
|
+
}
|
|
610
|
+
|
|
612
611
|
/**
|
|
613
612
|
* Get statistics about current connections
|
|
614
613
|
*/
|
|
@@ -638,7 +637,9 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
638
637
|
terminationStats,
|
|
639
638
|
acmeEnabled: !!this.port80Handler,
|
|
640
639
|
port80HandlerPort: this.port80Handler ? this.settings.acme?.port : null,
|
|
641
|
-
routes: this.routeManager.getListeningPorts().length
|
|
640
|
+
routes: this.routeManager.getListeningPorts().length,
|
|
641
|
+
listeningPorts: this.portManager.getListeningPorts(),
|
|
642
|
+
activePorts: this.portManager.getListeningPorts().length
|
|
642
643
|
};
|
|
643
644
|
}
|
|
644
645
|
|
|
@@ -14,9 +14,11 @@
|
|
|
14
14
|
* - Static file server routes (createStaticFileRoute)
|
|
15
15
|
* - API routes (createApiRoute)
|
|
16
16
|
* - WebSocket routes (createWebSocketRoute)
|
|
17
|
+
* - Port mapping routes (createPortMappingRoute, createOffsetPortMappingRoute)
|
|
18
|
+
* - Dynamic routing (createDynamicRoute, createSmartLoadBalancer)
|
|
17
19
|
*/
|
|
18
20
|
|
|
19
|
-
import type { IRouteConfig, IRouteMatch, IRouteAction, IRouteTarget, TPortRange } from '../models/route-types.js';
|
|
21
|
+
import type { IRouteConfig, IRouteMatch, IRouteAction, IRouteTarget, TPortRange, IRouteContext } from '../models/route-types.js';
|
|
20
22
|
|
|
21
23
|
/**
|
|
22
24
|
* Create an HTTP-only route configuration
|
|
@@ -452,4 +454,168 @@ export function createWebSocketRoute(
|
|
|
452
454
|
priority: options.priority || 100, // Higher priority for WebSocket routes
|
|
453
455
|
...options
|
|
454
456
|
};
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Create a helper function that applies a port offset
|
|
461
|
+
* @param offset The offset to apply to the matched port
|
|
462
|
+
* @returns A function that adds the offset to the matched port
|
|
463
|
+
*/
|
|
464
|
+
export function createPortOffset(offset: number): (context: IRouteContext) => number {
|
|
465
|
+
return (context: IRouteContext) => context.port + offset;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Create a port mapping route with context-based port function
|
|
470
|
+
* @param options Port mapping route options
|
|
471
|
+
* @returns Route configuration object
|
|
472
|
+
*/
|
|
473
|
+
export function createPortMappingRoute(options: {
|
|
474
|
+
sourcePortRange: TPortRange;
|
|
475
|
+
targetHost: string | string[] | ((context: IRouteContext) => string | string[]);
|
|
476
|
+
portMapper: (context: IRouteContext) => number;
|
|
477
|
+
name?: string;
|
|
478
|
+
domains?: string | string[];
|
|
479
|
+
priority?: number;
|
|
480
|
+
[key: string]: any;
|
|
481
|
+
}): IRouteConfig {
|
|
482
|
+
// Create route match
|
|
483
|
+
const match: IRouteMatch = {
|
|
484
|
+
ports: options.sourcePortRange,
|
|
485
|
+
domains: options.domains
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
// Create route action
|
|
489
|
+
const action: IRouteAction = {
|
|
490
|
+
type: 'forward',
|
|
491
|
+
target: {
|
|
492
|
+
host: options.targetHost,
|
|
493
|
+
port: options.portMapper
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// Create the route config
|
|
498
|
+
return {
|
|
499
|
+
match,
|
|
500
|
+
action,
|
|
501
|
+
name: options.name || `Port Mapping Route for ${options.domains || 'all domains'}`,
|
|
502
|
+
priority: options.priority,
|
|
503
|
+
...options
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Create a simple offset port mapping route
|
|
509
|
+
* @param options Offset port mapping route options
|
|
510
|
+
* @returns Route configuration object
|
|
511
|
+
*/
|
|
512
|
+
export function createOffsetPortMappingRoute(options: {
|
|
513
|
+
ports: TPortRange;
|
|
514
|
+
targetHost: string | string[];
|
|
515
|
+
offset: number;
|
|
516
|
+
name?: string;
|
|
517
|
+
domains?: string | string[];
|
|
518
|
+
priority?: number;
|
|
519
|
+
[key: string]: any;
|
|
520
|
+
}): IRouteConfig {
|
|
521
|
+
return createPortMappingRoute({
|
|
522
|
+
sourcePortRange: options.ports,
|
|
523
|
+
targetHost: options.targetHost,
|
|
524
|
+
portMapper: (context) => context.port + options.offset,
|
|
525
|
+
name: options.name || `Offset Mapping (${options.offset > 0 ? '+' : ''}${options.offset}) for ${options.domains || 'all domains'}`,
|
|
526
|
+
domains: options.domains,
|
|
527
|
+
priority: options.priority,
|
|
528
|
+
...options
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Create a dynamic route with context-based host and port mapping
|
|
534
|
+
* @param options Dynamic route options
|
|
535
|
+
* @returns Route configuration object
|
|
536
|
+
*/
|
|
537
|
+
export function createDynamicRoute(options: {
|
|
538
|
+
ports: TPortRange;
|
|
539
|
+
targetHost: (context: IRouteContext) => string | string[];
|
|
540
|
+
portMapper: (context: IRouteContext) => number;
|
|
541
|
+
name?: string;
|
|
542
|
+
domains?: string | string[];
|
|
543
|
+
path?: string;
|
|
544
|
+
clientIp?: string[];
|
|
545
|
+
priority?: number;
|
|
546
|
+
[key: string]: any;
|
|
547
|
+
}): IRouteConfig {
|
|
548
|
+
// Create route match
|
|
549
|
+
const match: IRouteMatch = {
|
|
550
|
+
ports: options.ports,
|
|
551
|
+
domains: options.domains,
|
|
552
|
+
path: options.path,
|
|
553
|
+
clientIp: options.clientIp
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
// Create route action
|
|
557
|
+
const action: IRouteAction = {
|
|
558
|
+
type: 'forward',
|
|
559
|
+
target: {
|
|
560
|
+
host: options.targetHost,
|
|
561
|
+
port: options.portMapper
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
// Create the route config
|
|
566
|
+
return {
|
|
567
|
+
match,
|
|
568
|
+
action,
|
|
569
|
+
name: options.name || `Dynamic Route for ${options.domains || 'all domains'}`,
|
|
570
|
+
priority: options.priority,
|
|
571
|
+
...options
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Create a smart load balancer with dynamic domain-based backend selection
|
|
577
|
+
* @param options Smart load balancer options
|
|
578
|
+
* @returns Route configuration object
|
|
579
|
+
*/
|
|
580
|
+
export function createSmartLoadBalancer(options: {
|
|
581
|
+
ports: TPortRange;
|
|
582
|
+
domainTargets: Record<string, string | string[]>;
|
|
583
|
+
portMapper: (context: IRouteContext) => number;
|
|
584
|
+
name?: string;
|
|
585
|
+
defaultTarget?: string | string[];
|
|
586
|
+
priority?: number;
|
|
587
|
+
[key: string]: any;
|
|
588
|
+
}): IRouteConfig {
|
|
589
|
+
// Extract all domain keys to create the match criteria
|
|
590
|
+
const domains = Object.keys(options.domainTargets);
|
|
591
|
+
|
|
592
|
+
// Create the smart host selector function
|
|
593
|
+
const hostSelector = (context: IRouteContext) => {
|
|
594
|
+
const domain = context.domain || '';
|
|
595
|
+
return options.domainTargets[domain] || options.defaultTarget || 'localhost';
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
// Create route match
|
|
599
|
+
const match: IRouteMatch = {
|
|
600
|
+
ports: options.ports,
|
|
601
|
+
domains
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
// Create route action
|
|
605
|
+
const action: IRouteAction = {
|
|
606
|
+
type: 'forward',
|
|
607
|
+
target: {
|
|
608
|
+
host: hostSelector,
|
|
609
|
+
port: options.portMapper
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
// Create the route config
|
|
614
|
+
return {
|
|
615
|
+
match,
|
|
616
|
+
action,
|
|
617
|
+
name: options.name || `Smart Load Balancer for ${domains.join(', ')}`,
|
|
618
|
+
priority: options.priority,
|
|
619
|
+
...options
|
|
620
|
+
};
|
|
455
621
|
}
|
|
@@ -9,14 +9,24 @@ import type { IRouteConfig, IRouteMatch, IRouteAction, TPortRange } from '../mod
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Validates a port range or port number
|
|
12
|
-
* @param port Port number or port
|
|
12
|
+
* @param port Port number, port range, or port function
|
|
13
13
|
* @returns True if valid, false otherwise
|
|
14
14
|
*/
|
|
15
|
-
export function isValidPort(port:
|
|
15
|
+
export function isValidPort(port: any): boolean {
|
|
16
16
|
if (typeof port === 'number') {
|
|
17
17
|
return port > 0 && port < 65536; // Valid port range is 1-65535
|
|
18
18
|
} else if (Array.isArray(port)) {
|
|
19
|
-
return port.every(p =>
|
|
19
|
+
return port.every(p =>
|
|
20
|
+
(typeof p === 'number' && p > 0 && p < 65536) ||
|
|
21
|
+
(typeof p === 'object' && 'from' in p && 'to' in p &&
|
|
22
|
+
p.from > 0 && p.from < 65536 && p.to > 0 && p.to < 65536)
|
|
23
|
+
);
|
|
24
|
+
} else if (typeof port === 'function') {
|
|
25
|
+
// For function-based ports, we can't validate the result at config time
|
|
26
|
+
// so we just check that it's a function
|
|
27
|
+
return true;
|
|
28
|
+
} else if (typeof port === 'object' && 'from' in port && 'to' in port) {
|
|
29
|
+
return port.from > 0 && port.from < 65536 && port.to > 0 && port.to < 65536;
|
|
20
30
|
}
|
|
21
31
|
return false;
|
|
22
32
|
}
|
|
@@ -100,11 +110,20 @@ export function validateRouteAction(action: IRouteAction): { valid: boolean; err
|
|
|
100
110
|
// Validate target host
|
|
101
111
|
if (!action.target.host) {
|
|
102
112
|
errors.push('Target host is required');
|
|
113
|
+
} else if (typeof action.target.host !== 'string' &&
|
|
114
|
+
!Array.isArray(action.target.host) &&
|
|
115
|
+
typeof action.target.host !== 'function') {
|
|
116
|
+
errors.push('Target host must be a string, array of strings, or function');
|
|
103
117
|
}
|
|
104
118
|
|
|
105
119
|
// Validate target port
|
|
106
|
-
if (
|
|
107
|
-
errors.push('
|
|
120
|
+
if (action.target.port === undefined) {
|
|
121
|
+
errors.push('Target port is required');
|
|
122
|
+
} else if (typeof action.target.port !== 'number' &&
|
|
123
|
+
typeof action.target.port !== 'function') {
|
|
124
|
+
errors.push('Target port must be a number or a function');
|
|
125
|
+
} else if (typeof action.target.port === 'number' && !isValidPort(action.target.port)) {
|
|
126
|
+
errors.push('Target port must be between 1 and 65535');
|
|
108
127
|
}
|
|
109
128
|
}
|
|
110
129
|
|