BREAKING CHANGE(smart-proxy): remove route helper APIs and standardize route configuration on plain route objects

This commit is contained in:
2026-03-26 20:45:41 +00:00
parent 47140e5403
commit 788ccea81e
32 changed files with 1159 additions and 2840 deletions

View File

@@ -2,146 +2,101 @@ import * as path from 'path';
import { tap, expect } from '@git.zone/tstest/tapbundle';
import { SmartProxy } from '../ts/proxies/smart-proxy/index.js';
import {
createHttpRoute,
createHttpsTerminateRoute,
createHttpsPassthroughRoute,
createHttpToHttpsRedirect,
createCompleteHttpsServer,
createLoadBalancerRoute,
createApiRoute,
createWebSocketRoute
} from '../ts/proxies/smart-proxy/utils/route-helpers.js';
import { SocketHandlers } from '../ts/proxies/smart-proxy/utils/socket-handlers.js';
import type { IRouteConfig } from '../ts/proxies/smart-proxy/models/route-types.js';
// Test to demonstrate various route configurations using the new helpers
tap.test('Route-based configuration examples', async (tools) => {
// Example 1: HTTP-only configuration
const httpOnlyRoute = createHttpRoute(
'http.example.com',
{
host: 'localhost',
port: 3000
},
{
name: 'Basic HTTP Route'
}
);
const httpOnlyRoute: IRouteConfig = {
match: { ports: 80, domains: 'http.example.com' },
action: { type: 'forward', targets: [{ host: 'localhost', port: 3000 }] },
name: 'Basic HTTP Route'
};
console.log('HTTP-only route created successfully:', httpOnlyRoute.name);
expect(httpOnlyRoute.action.type).toEqual('forward');
expect(httpOnlyRoute.match.domains).toEqual('http.example.com');
// Example 2: HTTPS Passthrough (SNI) configuration
const httpsPassthroughRoute = createHttpsPassthroughRoute(
'pass.example.com',
{
host: ['10.0.0.1', '10.0.0.2'], // Round-robin target IPs
port: 443
},
{
name: 'HTTPS Passthrough Route'
}
);
const httpsPassthroughRoute: IRouteConfig = {
match: { ports: 443, domains: 'pass.example.com' },
action: { type: 'forward', targets: [{ host: '10.0.0.1', port: 443 }, { host: '10.0.0.2', port: 443 }], tls: { mode: 'passthrough' } },
name: 'HTTPS Passthrough Route'
};
expect(httpsPassthroughRoute).toBeTruthy();
expect(httpsPassthroughRoute.action.tls?.mode).toEqual('passthrough');
expect(Array.isArray(httpsPassthroughRoute.action.targets)).toBeTrue();
// Example 3: HTTPS Termination to HTTP Backend
const terminateToHttpRoute = createHttpsTerminateRoute(
'secure.example.com',
{
host: 'localhost',
port: 8080
},
{
certificate: 'auto',
name: 'HTTPS Termination to HTTP Backend'
}
);
const terminateToHttpRoute: IRouteConfig = {
match: { ports: 443, domains: 'secure.example.com' },
action: { type: 'forward', targets: [{ host: 'localhost', port: 8080 }], tls: { mode: 'terminate', certificate: 'auto' } },
name: 'HTTPS Termination to HTTP Backend'
};
// Create the HTTP to HTTPS redirect for this domain
const httpToHttpsRedirect = createHttpToHttpsRedirect(
'secure.example.com',
443,
{
name: 'HTTP to HTTPS Redirect for secure.example.com'
}
);
const httpToHttpsRedirect: IRouteConfig = {
match: { ports: 80, domains: 'secure.example.com' },
action: { type: 'socket-handler', socketHandler: SocketHandlers.httpRedirect('https://{domain}:443{path}', 301) },
name: 'HTTP to HTTPS Redirect for secure.example.com'
};
expect(terminateToHttpRoute).toBeTruthy();
expect(terminateToHttpRoute.action.tls?.mode).toEqual('terminate');
expect(httpToHttpsRedirect.action.type).toEqual('socket-handler');
// Example 4: Load Balancer with HTTPS
const loadBalancerRoute = createLoadBalancerRoute(
'proxy.example.com',
['internal-api-1.local', 'internal-api-2.local'],
8443,
{
tls: {
mode: 'terminate-and-reencrypt',
certificate: 'auto'
},
name: 'Load Balanced HTTPS Route'
}
);
const loadBalancerRoute: IRouteConfig = {
match: { ports: 443, domains: 'proxy.example.com' },
action: {
type: 'forward',
targets: [
{ host: 'internal-api-1.local', port: 8443 },
{ host: 'internal-api-2.local', port: 8443 }
],
tls: { mode: 'terminate-and-reencrypt', certificate: 'auto' }
},
name: 'Load Balanced HTTPS Route'
};
expect(loadBalancerRoute).toBeTruthy();
expect(loadBalancerRoute.action.tls?.mode).toEqual('terminate-and-reencrypt');
expect(Array.isArray(loadBalancerRoute.action.targets)).toBeTrue();
// Example 5: API Route
const apiRoute = createApiRoute(
'api.example.com',
'/api',
{ host: 'localhost', port: 8081 },
{
name: 'API Route',
useTls: true,
addCorsHeaders: true
}
);
const apiRoute: IRouteConfig = {
match: { ports: 443, domains: 'api.example.com', path: '/api' },
action: {
type: 'forward',
targets: [{ host: 'localhost', port: 8081 }],
tls: { mode: 'terminate', certificate: 'auto' }
},
name: 'API Route'
};
expect(apiRoute.action.type).toEqual('forward');
expect(apiRoute.match.path).toBeTruthy();
// Example 6: Complete HTTPS Server with HTTP Redirect
const httpsServerRoutes = createCompleteHttpsServer(
'complete.example.com',
{
host: 'localhost',
port: 8080
const httpsRoute: IRouteConfig = {
match: { ports: 443, domains: 'complete.example.com' },
action: { type: 'forward', targets: [{ host: 'localhost', port: 8080 }], tls: { mode: 'terminate', certificate: 'auto' } },
name: 'Complete HTTPS Server'
};
const httpsRedirectRoute: IRouteConfig = {
match: { ports: 80, domains: 'complete.example.com' },
action: { type: 'socket-handler', socketHandler: SocketHandlers.httpRedirect('https://{domain}:443{path}', 301) },
name: 'Complete HTTPS Server - Redirect'
};
const webSocketRoute: IRouteConfig = {
match: { ports: 443, domains: 'ws.example.com', path: '/ws' },
action: {
type: 'forward',
targets: [{ host: 'localhost', port: 8082 }],
tls: { mode: 'terminate', certificate: 'auto' },
websocket: { enabled: true }
},
{
certificate: 'auto',
name: 'Complete HTTPS Server'
}
);
expect(Array.isArray(httpsServerRoutes)).toBeTrue();
expect(httpsServerRoutes.length).toEqual(2); // HTTPS route and HTTP redirect
expect(httpsServerRoutes[0].action.tls?.mode).toEqual('terminate');
expect(httpsServerRoutes[1].action.type).toEqual('socket-handler');
// Example 7: Static File Server - removed (use nginx/apache behind proxy)
// Example 8: WebSocket Route
const webSocketRoute = createWebSocketRoute(
'ws.example.com',
'/ws',
{ host: 'localhost', port: 8082 },
{
useTls: true,
name: 'WebSocket Route'
}
);
name: 'WebSocket Route'
};
expect(webSocketRoute.action.type).toEqual('forward');
expect(webSocketRoute.action.websocket?.enabled).toBeTrue();
// Create a SmartProxy instance with all routes
const allRoutes: IRouteConfig[] = [
httpOnlyRoute,
httpsPassthroughRoute,
@@ -149,19 +104,17 @@ tap.test('Route-based configuration examples', async (tools) => {
httpToHttpsRedirect,
loadBalancerRoute,
apiRoute,
...httpsServerRoutes,
httpsRoute,
httpsRedirectRoute,
webSocketRoute
];
// We're not actually starting the SmartProxy in this test,
// just verifying that the configuration is valid
const smartProxy = new SmartProxy({
routes: allRoutes
});
// Just verify that all routes are configured correctly
console.log(`Created ${allRoutes.length} example routes`);
expect(allRoutes.length).toEqual(9); // One less without static file route
expect(allRoutes.length).toEqual(9);
});
export default tap.start();
export default tap.start();