BREAKING CHANGE(smart-proxy): remove route helper APIs and standardize route configuration on plain route objects
This commit is contained in:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user