# 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 ```typescript // 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 ```typescript // 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` (not `email`) 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: ```typescript 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 with `routes` array - `IRouteConfig`: Individual route configuration - `IRouteMatch`: Match criteria for routes - `IRouteTarget`: Target configuration for forwarding - `IAcmeOptions`: ACME certificate configuration - `TTlsMode`: TLS handling modes ('passthrough' | 'terminate' | 'terminate-and-reencrypt') ### New Route Configuration ```typescript interface IRouteConfig { name: string; match: { ports: number | number[]; domains?: string | string[]; path?: string; headers?: Record; }; 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`, use `accountEmail` for the contact email - Routes must have `name`, `match`, and `action` 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 ```typescript 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: ```typescript 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 ```typescript // 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