5.8 KiB
5.8 KiB
Implementation Hints and Learnings
SmartProxy Usage
New Route-Based Architecture (v18+)
- SmartProxy now uses a route-based configuration system
- Routes define match criteria and actions instead of simple port-to-port forwarding
- All traffic types (HTTP, HTTPS, TCP, WebSocket) are configured through routes
// NEW: Route-based SmartProxy configuration
const smartProxy = new plugins.smartproxy.SmartProxy({
routes: [
{
name: 'https-traffic',
match: {
ports: 443,
domains: ['example.com', '*.example.com']
},
action: {
type: 'forward',
target: {
host: 'backend.server.com',
port: 8080
}
},
tls: {
mode: 'terminate',
certificate: 'auto'
}
}
],
defaults: {
target: {
host: 'fallback.server.com',
port: 8080
}
},
acme: {
accountEmail: 'admin@example.com',
enabled: true,
useProduction: true
}
});
Migration from Old to New
// OLD configuration style (deprecated)
{
fromPort: 443,
toPort: 8080,
targetIP: 'backend.server.com',
domainConfigs: [...]
}
// NEW route-based style
{
routes: [{
name: 'main-route',
match: { ports: 443 },
action: {
type: 'forward',
target: { host: 'backend.server.com', port: 8080 }
}
}]
}
Direct Component Usage
- Use SmartProxy components directly instead of creating your own wrappers
- SmartProxy already includes Port80Handler and NetworkProxy functionality
- When using SmartProxy, configure it directly rather than instantiating Port80Handler or NetworkProxy separately
Certificate Management
- SmartProxy has built-in ACME certificate management
- Configure it in the
acme
property of SmartProxy options - Use
accountEmail
(notemail
) for the ACME contact email - SmartProxy handles both HTTP-01 challenges and certificate application automatically
qenv Usage
Direct Usage
- Use qenv directly instead of creating environment variable wrappers
- Instantiate qenv with appropriate basePath and nogitPath:
const qenv = new plugins.qenv.Qenv('./', '.nogit/');
const value = await qenv.getEnvVarOnDemand('ENV_VAR_NAME');
TypeScript Interfaces
SmartProxy Interfaces
- Always check the interfaces from the node_modules to ensure correct property names
- Important interfaces for the new architecture:
ISmartProxyOptions
: Main configuration withroutes
arrayIRouteConfig
: Individual route configurationIRouteMatch
: Match criteria for routesIRouteTarget
: Target configuration for forwardingIAcmeOptions
: ACME certificate configurationTTlsMode
: TLS handling modes ('passthrough' | 'terminate' | 'terminate-and-reencrypt')
New Route Configuration
interface IRouteConfig {
name: string;
match: {
ports: number | number[];
domains?: string | string[];
path?: string;
headers?: Record<string, string | RegExp>;
};
action: {
type: 'forward' | 'redirect' | 'block' | 'static';
target?: {
host: string | string[] | ((context) => string);
port: number | 'preserve' | ((context) => number);
};
};
tls?: {
mode: TTlsMode;
certificate?: 'auto' | { key: string; cert: string; };
};
security?: {
authentication?: IRouteAuthentication;
rateLimit?: IRouteRateLimit;
ipAllowList?: string[];
ipBlockList?: string[];
};
}
Required Properties
- For
ISmartProxyOptions
,routes
array is the main configuration - For
IAcmeOptions
, useaccountEmail
for the contact email - Routes must have
name
,match
, andaction
properties
Testing
Test Structure
- Follow the project's test structure, using
@push.rocks/tapbundle
- Use
expect(value).toEqual(expected)
for equality checks - Use
expect(value).toBeTruthy()
for boolean assertions
tap.test('test description', async () => {
const result = someFunction();
expect(result.property).toEqual('expected value');
expect(result.valid).toBeTruthy();
});
Cleanup
- Include a cleanup test to ensure proper test resource handling
- Add a
stop
test to forcefully end the test when needed:
tap.test('stop', async () => {
await tap.stopForcefully();
});
Architecture Principles
Simplicity
- Prefer direct usage of libraries instead of creating wrappers
- Don't reinvent functionality that already exists in dependencies
- Keep interfaces clean and focused, avoiding unnecessary abstraction layers
Component Integration
- Leverage built-in integrations between components (like SmartProxy's ACME handling)
- Use parallel operations for performance (like in the
stop()
method) - Separate concerns clearly (HTTP handling vs. SMTP handling)
Email Integration with SmartProxy
Architecture
- Email traffic is routed through SmartProxy using automatic route generation
- Email server runs on internal ports and receives forwarded traffic from SmartProxy
- SmartProxy handles external ports (25, 587, 465) and forwards to internal ports
Email Route Generation
// Email configuration automatically generates SmartProxy routes
emailConfig: {
ports: [25, 587, 465],
hostname: 'mail.example.com',
domainRules: [...]
}
// Generates routes like:
{
name: 'smtp-route',
match: { ports: [25] },
action: {
type: 'forward',
target: { host: 'localhost', port: 10025 }
},
tls: { mode: 'passthrough' } // STARTTLS handled by email server
}
Port Mapping
- External port 25 → Internal port 10025 (SMTP)
- External port 587 → Internal port 10587 (Submission)
- External port 465 → Internal port 10465 (SMTPS)
TLS Handling
- Ports 25 and 587: Use 'passthrough' mode (STARTTLS handled by email server)
- Port 465: Use 'terminate' mode (SmartProxy handles TLS termination)
- Domain-specific TLS can be configured per email rule