# SmartProxy Project Hints ## Project Overview - Package: `@push.rocks/smartproxy` – high-performance proxy supporting HTTP(S), TCP, WebSocket, and ACME integration. - Written in TypeScript, compiled output in `dist_ts/`, uses ESM with NodeNext resolution. ## Important: ACME Configuration in v19.0.0 - **Breaking Change**: ACME configuration must be placed within individual route TLS settings, not at the top level - Route-level ACME config is the ONLY way to enable SmartAcme initialization - SmartCertManager requires email in route config for certificate acquisition - Top-level ACME configuration is ignored in v19.0.0 ## Repository Structure - `ts/` – TypeScript source files: - `index.ts` exports main modules. - `plugins.ts` centralizes native and third-party imports. - Subdirectories: `networkproxy/`, `nftablesproxy/`, `port80handler/`, `redirect/`, `smartproxy/`. - Key classes: `ProxyRouter` (`classes.router.ts`), `SmartProxy` (`classes.smartproxy.ts`), plus handlers/managers. - `dist_ts/` – transpiled `.js` and `.d.ts` files mirroring `ts/` structure. - `test/` – test suites in TypeScript: - `test.router.ts` – routing logic (hostname matching, wildcards, path parameters, config management). - `test.smartproxy.ts` – proxy behavior tests (TCP forwarding, SNI handling, concurrency, chaining, timeouts). - `test/helpers/` – utilities (e.g., certificates). - `assets/certs/` – placeholder certificates for ACME and TLS. ## Development Setup - Requires `pnpm` (v10+). - Install dependencies: `pnpm install`. - Build: `pnpm build` (runs `tsbuild --web --allowimplicitany`). - Test: `pnpm test` (runs `tstest test/`). - Format: `pnpm format` (runs `gitzone format`). ## Testing Framework - Uses `@push.rocks/tapbundle` (`tap`, `expect`, `expactAsync`). - Test files: must start with `test.` and use `.ts` extension. - Run specific tests via `tsx`, e.g., `tsx test/test.router.ts`. ## Coding Conventions - Import modules via `plugins.ts`: ```ts import * as plugins from './plugins.ts'; const server = new plugins.http.Server(); ``` - Reference plugins with full path: `plugins.acme`, `plugins.smartdelay`, `plugins.minimatch`, etc. - Path patterns support globs (`*`) and parameters (`:param`) in `ProxyRouter`. - Wildcard hostname matching leverages `minimatch` patterns. ## Key Components - **ProxyRouter** - Methods: `routeReq`, `routeReqWithDetails`. - Hostname matching: case-insensitive, strips port, supports exact, wildcard, TLD, complex patterns. - Path routing: exact, wildcard, parameter extraction (`pathParams`), returns `pathMatch` and `pathRemainder`. - Config API: `setNewProxyConfigs`, `addProxyConfig`, `removeProxyConfig`, `getHostnames`, `getProxyConfigs`. - **SmartProxy** - Manages one or more `net.Server` instances to forward TCP streams. - Options: `preserveSourceIP`, `defaultAllowedIPs`, `globalPortRanges`, `sniEnabled`. - DomainConfigManager: round-robin selection for multiple target IPs. - Graceful shutdown in `stop()`, ensures no lingering servers or sockets. ## Notable Points - **TSConfig**: `module: NodeNext`, `verbatimModuleSyntax`, allows `.js` extension imports in TS. - Mermaid diagrams and architecture flows in `readme.md` illustrate component interactions and protocol flows. - CLI entrypoint (`cli.js`) supports command-line usage (ACME, proxy controls). - ACME and certificate handling via `Port80Handler` and `helpers.certificates.ts`. ## ACME/Certificate Configuration Example (v19.0.0) ```typescript const proxy = new SmartProxy({ routes: [{ name: 'example.com', match: { domains: 'example.com', ports: 443 }, action: { type: 'forward', target: { host: 'localhost', port: 8080 }, tls: { mode: 'terminate', certificate: 'auto', acme: { // ACME config MUST be here, not at top level email: 'ssl@example.com', useProduction: false, challengePort: 80 } } } }] }); ``` ## TODOs / Considerations - Ensure import extensions in source match build outputs (`.ts` vs `.js`). - Update `plugins.ts` when adding new dependencies. - Maintain test coverage for new routing or proxy features. - Keep `ts/` and `dist_ts/` in sync after refactors. - Consider implementing top-level ACME config support for backward compatibility ## HTTP-01 ACME Challenge Fix (v19.3.8) ### Issue Non-TLS connections on ports configured in `useHttpProxy` were not being forwarded to HttpProxy. This caused ACME HTTP-01 challenges to fail when the ACME port (usually 80) was included in `useHttpProxy`. ### Root Cause In the `RouteConnectionHandler.handleForwardAction` method, only connections with TLS settings (mode: 'terminate' or 'terminate-and-reencrypt') were being forwarded to HttpProxy. Non-TLS connections were always handled as direct connections, even when the port was configured for HttpProxy. ### Solution Added a check for non-TLS connections on ports listed in `useHttpProxy`: ```typescript // No TLS settings - check if this port should use HttpProxy const isHttpProxyPort = this.settings.useHttpProxy?.includes(record.localPort); if (isHttpProxyPort && this.httpProxyBridge.getHttpProxy()) { // Forward non-TLS connections to HttpProxy if configured this.httpProxyBridge.forwardToHttpProxy(/*...*/); return; } ``` ### Test Coverage - `test/test.http-fix-unit.ts` - Unit tests verifying the fix - Tests confirm that non-TLS connections on HttpProxy ports are properly forwarded - Tests verify that non-HttpProxy ports still use direct connections ### Configuration Example ```typescript const proxy = new SmartProxy({ useHttpProxy: [80], // Enable HttpProxy for port 80 httpProxyPort: 8443, acme: { email: 'ssl@example.com', port: 80 }, routes: [ // Your routes here ] }); ```