fix(typescript): Refactor types and interfaces to use consistent I prefix and update related tests
This commit is contained in:
		| @@ -1,5 +1,13 @@ | ||||
| # Changelog | ||||
|  | ||||
| ## 2025-05-09 - 13.1.1 - fix(typescript) | ||||
| Refactor types and interfaces to use consistent 'I' prefix and update related tests | ||||
|  | ||||
| - Replaced DomainConfig with IDomainConfig and SmartProxyOptions with ISmartProxyOptions in various modules | ||||
| - Renamed SmartProxyCertProvisionObject to TSmartProxyCertProvisionObject for clarity | ||||
| - Standardized type names (e.g. ForwardConfig → IForwardConfig, Logger → ILogger) across proxy, forwarding, and certificate modules | ||||
| - Updated tests and helper functions to reflect new type names and ensure compatibility | ||||
|  | ||||
| ## 2025-05-09 - 13.1.0 - feat(docs) | ||||
| Update README to reflect new modular architecture and expanded core utilities: add Project Architecture Overview, update export paths and API references, and mark plan tasks as completed | ||||
|  | ||||
|   | ||||
| @@ -1,9 +1,10 @@ | ||||
| import { tap, expect } from '@push.rocks/tapbundle'; | ||||
| import * as plugins from '../ts/plugins.js'; | ||||
| import { CertProvisioner } from '../ts/certificate/providers/cert-provisioner.js'; | ||||
| import type { DomainConfig } from '../ts/forwarding/config/forwarding-types.js'; | ||||
| import type { SmartProxyCertProvisionObject } from '../ts/certificate/models/certificate-types.js'; | ||||
| import type { CertificateData } from '../ts/certificate/models/certificate-types.js'; | ||||
| import type { IDomainConfig } from '../ts/forwarding/config/domain-config.js'; | ||||
| import type { ICertificateData } from '../ts/certificate/models/certificate-types.js'; | ||||
| // Import SmartProxyCertProvisionObject type alias | ||||
| import type { TSmartProxyCertProvisionObject } from '../ts/certificate/providers/cert-provisioner.js'; | ||||
|  | ||||
| // Fake Port80Handler stub | ||||
| class FakePort80Handler extends plugins.EventEmitter { | ||||
| @@ -19,15 +20,15 @@ class FakePort80Handler extends plugins.EventEmitter { | ||||
|  | ||||
| // Fake NetworkProxyBridge stub | ||||
| class FakeNetworkProxyBridge { | ||||
|   public appliedCerts: CertificateData[] = []; | ||||
|   applyExternalCertificate(cert: CertificateData) { | ||||
|   public appliedCerts: ICertificateData[] = []; | ||||
|   applyExternalCertificate(cert: ICertificateData) { | ||||
|     this.appliedCerts.push(cert); | ||||
|   } | ||||
| } | ||||
|  | ||||
| tap.test('CertProvisioner handles static provisioning', async () => { | ||||
|   const domain = 'static.com'; | ||||
|   const domainConfigs: DomainConfig[] = [{ | ||||
|   const domainConfigs: IDomainConfig[] = [{ | ||||
|     domains: [domain], | ||||
|     forwarding: { | ||||
|       type: 'https-terminate-to-https', | ||||
| @@ -37,7 +38,7 @@ tap.test('CertProvisioner handles static provisioning', async () => { | ||||
|   const fakePort80 = new FakePort80Handler(); | ||||
|   const fakeBridge = new FakeNetworkProxyBridge(); | ||||
|   // certProvider returns static certificate | ||||
|   const certProvider = async (d: string): Promise<SmartProxyCertProvisionObject> => { | ||||
|   const certProvider = async (d: string): Promise<TSmartProxyCertProvisionObject> => { | ||||
|     expect(d).toEqual(domain); | ||||
|     return { | ||||
|       domainName: domain, | ||||
| @@ -75,7 +76,7 @@ tap.test('CertProvisioner handles static provisioning', async () => { | ||||
|  | ||||
| tap.test('CertProvisioner handles http01 provisioning', async () => { | ||||
|   const domain = 'http01.com'; | ||||
|   const domainConfigs: DomainConfig[] = [{ | ||||
|   const domainConfigs: IDomainConfig[] = [{ | ||||
|     domains: [domain], | ||||
|     forwarding: { | ||||
|       type: 'https-terminate-to-http', | ||||
| @@ -85,7 +86,7 @@ tap.test('CertProvisioner handles http01 provisioning', async () => { | ||||
|   const fakePort80 = new FakePort80Handler(); | ||||
|   const fakeBridge = new FakeNetworkProxyBridge(); | ||||
|   // certProvider returns http01 directive | ||||
|   const certProvider = async (): Promise<SmartProxyCertProvisionObject> => 'http01'; | ||||
|   const certProvider = async (): Promise<TSmartProxyCertProvisionObject> => 'http01'; | ||||
|   const prov = new CertProvisioner( | ||||
|     domainConfigs, | ||||
|     fakePort80 as any, | ||||
| @@ -106,7 +107,7 @@ tap.test('CertProvisioner handles http01 provisioning', async () => { | ||||
|  | ||||
| tap.test('CertProvisioner on-demand http01 renewal', async () => { | ||||
|   const domain = 'renew.com'; | ||||
|   const domainConfigs: DomainConfig[] = [{ | ||||
|   const domainConfigs: IDomainConfig[] = [{ | ||||
|     domains: [domain], | ||||
|     forwarding: { | ||||
|       type: 'https-terminate-to-http', | ||||
| @@ -115,7 +116,7 @@ tap.test('CertProvisioner on-demand http01 renewal', async () => { | ||||
|   }]; | ||||
|   const fakePort80 = new FakePort80Handler(); | ||||
|   const fakeBridge = new FakeNetworkProxyBridge(); | ||||
|   const certProvider = async (): Promise<SmartProxyCertProvisionObject> => 'http01'; | ||||
|   const certProvider = async (): Promise<TSmartProxyCertProvisionObject> => 'http01'; | ||||
|   const prov = new CertProvisioner( | ||||
|     domainConfigs, | ||||
|     fakePort80 as any, | ||||
| @@ -132,7 +133,7 @@ tap.test('CertProvisioner on-demand http01 renewal', async () => { | ||||
|  | ||||
| tap.test('CertProvisioner on-demand static provisioning', async () => { | ||||
|   const domain = 'ondemand.com'; | ||||
|   const domainConfigs: DomainConfig[] = [{ | ||||
|   const domainConfigs: IDomainConfig[] = [{ | ||||
|     domains: [domain], | ||||
|     forwarding: { | ||||
|       type: 'https-terminate-to-https', | ||||
| @@ -141,7 +142,7 @@ tap.test('CertProvisioner on-demand static provisioning', async () => { | ||||
|   }]; | ||||
|   const fakePort80 = new FakePort80Handler(); | ||||
|   const fakeBridge = new FakeNetworkProxyBridge(); | ||||
|   const certProvider = async (): Promise<SmartProxyCertProvisionObject> => ({ | ||||
|   const certProvider = async (): Promise<TSmartProxyCertProvisionObject> => ({ | ||||
|     domainName: domain, | ||||
|     publicKey: 'PKEY', | ||||
|     privateKey: 'PRIV', | ||||
|   | ||||
| @@ -2,8 +2,8 @@ import * as plugins from '../ts/plugins.js'; | ||||
| import { tap, expect } from '@push.rocks/tapbundle'; | ||||
|  | ||||
| import { SmartProxy } from '../ts/proxies/smart-proxy/index.js'; | ||||
| import type { DomainConfig } from '../ts/forwarding/config/forwarding-types.js'; | ||||
| import type { ForwardingType } from '../ts/forwarding/config/forwarding-types.js'; | ||||
| import type { TForwardingType } from '../ts/forwarding/config/forwarding-types.js'; | ||||
| import type { IDomainConfig } from '../ts/forwarding/config/domain-config.js'; | ||||
| import { | ||||
|   httpOnly, | ||||
|   httpsPassthrough, | ||||
| @@ -14,7 +14,7 @@ import { | ||||
| // Test to demonstrate various forwarding configurations | ||||
| tap.test('Forwarding configuration examples', async (tools) => { | ||||
|   // Example 1: HTTP-only configuration | ||||
|   const httpOnlyConfig: DomainConfig = { | ||||
|   const httpOnlyConfig: IDomainConfig = { | ||||
|     domains: ['http.example.com'], | ||||
|     forwarding: httpOnly({ | ||||
|       target: { | ||||
| @@ -30,7 +30,7 @@ tap.test('Forwarding configuration examples', async (tools) => { | ||||
|   expect(httpOnlyConfig.forwarding.type).toEqual('http-only'); | ||||
|  | ||||
|   // Example 2: HTTPS Passthrough (SNI) | ||||
|   const httpsPassthroughConfig: DomainConfig = { | ||||
|   const httpsPassthroughConfig: IDomainConfig = { | ||||
|     domains: ['pass.example.com'], | ||||
|     forwarding: httpsPassthrough({ | ||||
|       target: { | ||||
| @@ -47,7 +47,7 @@ tap.test('Forwarding configuration examples', async (tools) => { | ||||
|   expect(Array.isArray(httpsPassthroughConfig.forwarding.target.host)).toBeTrue(); | ||||
|  | ||||
|   // Example 3: HTTPS Termination to HTTP Backend | ||||
|   const terminateToHttpConfig: DomainConfig = { | ||||
|   const terminateToHttpConfig: IDomainConfig = { | ||||
|     domains: ['secure.example.com'], | ||||
|     forwarding: tlsTerminateToHttp({ | ||||
|       target: { | ||||
| @@ -75,7 +75,7 @@ tap.test('Forwarding configuration examples', async (tools) => { | ||||
|   expect(terminateToHttpConfig.forwarding.http?.redirectToHttps).toBeTrue(); | ||||
|  | ||||
|   // Example 4: HTTPS Termination to HTTPS Backend | ||||
|   const terminateToHttpsConfig: DomainConfig = { | ||||
|   const terminateToHttpsConfig: IDomainConfig = { | ||||
|     domains: ['proxy.example.com'], | ||||
|     forwarding: tlsTerminateToHttps({ | ||||
|       target: { | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { tap, expect } from '@push.rocks/tapbundle'; | ||||
| import * as plugins from '../ts/plugins.js'; | ||||
| import type { ForwardConfig, ForwardingType } from '../ts/forwarding/config/forwarding-types.js'; | ||||
| import type { IForwardConfig, TForwardingType } from '../ts/forwarding/config/forwarding-types.js'; | ||||
|  | ||||
| // First, import the components directly to avoid issues with compiled modules | ||||
| import { ForwardingHandlerFactory } from '../ts/forwarding/factory/forwarding-factory.js'; | ||||
| @@ -17,7 +17,7 @@ const helpers = { | ||||
|  | ||||
| tap.test('ForwardingHandlerFactory - apply defaults based on type', async () => { | ||||
|       // HTTP-only defaults | ||||
|       const httpConfig: ForwardConfig = { | ||||
|       const httpConfig: IForwardConfig = { | ||||
|         type: 'http-only', | ||||
|         target: { host: 'localhost', port: 3000 } | ||||
|       }; | ||||
| @@ -26,7 +26,7 @@ tap.test('ForwardingHandlerFactory - apply defaults based on type', async () => | ||||
|       expect(expandedHttpConfig.http?.enabled).toEqual(true); | ||||
|        | ||||
|       // HTTPS-passthrough defaults | ||||
|       const passthroughConfig: ForwardConfig = { | ||||
|       const passthroughConfig: IForwardConfig = { | ||||
|         type: 'https-passthrough', | ||||
|         target: { host: 'localhost', port: 443 } | ||||
|       }; | ||||
| @@ -36,7 +36,7 @@ tap.test('ForwardingHandlerFactory - apply defaults based on type', async () => | ||||
|       expect(expandedPassthroughConfig.http?.enabled).toEqual(false); | ||||
|        | ||||
|       // HTTPS-terminate-to-http defaults | ||||
|       const terminateToHttpConfig: ForwardConfig = { | ||||
|       const terminateToHttpConfig: IForwardConfig = { | ||||
|         type: 'https-terminate-to-http', | ||||
|         target: { host: 'localhost', port: 3000 } | ||||
|       }; | ||||
| @@ -48,7 +48,7 @@ tap.test('ForwardingHandlerFactory - apply defaults based on type', async () => | ||||
|       expect(expandedTerminateToHttpConfig.acme?.maintenance).toEqual(true); | ||||
|        | ||||
|       // HTTPS-terminate-to-https defaults | ||||
|       const terminateToHttpsConfig: ForwardConfig = { | ||||
|       const terminateToHttpsConfig: IForwardConfig = { | ||||
|         type: 'https-terminate-to-https', | ||||
|         target: { host: 'localhost', port: 8443 } | ||||
|       }; | ||||
| @@ -62,7 +62,7 @@ tap.test('ForwardingHandlerFactory - apply defaults based on type', async () => | ||||
|      | ||||
| tap.test('ForwardingHandlerFactory - validate configuration', async () => { | ||||
|       // Valid configuration | ||||
|       const validConfig: ForwardConfig = { | ||||
|       const validConfig: IForwardConfig = { | ||||
|         type: 'http-only', | ||||
|         target: { host: 'localhost', port: 3000 } | ||||
|       }; | ||||
| @@ -77,7 +77,7 @@ tap.test('ForwardingHandlerFactory - validate configuration', async () => { | ||||
|       expect(() => ForwardingHandlerFactory.validateConfig(invalidConfig1)).toThrow(); | ||||
|        | ||||
|       // Invalid configuration - invalid port | ||||
|       const invalidConfig2: ForwardConfig = { | ||||
|       const invalidConfig2: IForwardConfig = { | ||||
|         type: 'http-only', | ||||
|         target: { host: 'localhost', port: 0 } | ||||
|       }; | ||||
| @@ -85,7 +85,7 @@ tap.test('ForwardingHandlerFactory - validate configuration', async () => { | ||||
|       expect(() => ForwardingHandlerFactory.validateConfig(invalidConfig2)).toThrow(); | ||||
|        | ||||
|       // Invalid configuration - HTTP disabled for HTTP-only | ||||
|       const invalidConfig3: ForwardConfig = { | ||||
|       const invalidConfig3: IForwardConfig = { | ||||
|         type: 'http-only', | ||||
|         target: { host: 'localhost', port: 3000 }, | ||||
|         http: { enabled: false } | ||||
| @@ -94,7 +94,7 @@ tap.test('ForwardingHandlerFactory - validate configuration', async () => { | ||||
|       expect(() => ForwardingHandlerFactory.validateConfig(invalidConfig3)).toThrow(); | ||||
|        | ||||
|       // Invalid configuration - HTTP enabled for HTTPS passthrough | ||||
|       const invalidConfig4: ForwardConfig = { | ||||
|       const invalidConfig4: IForwardConfig = { | ||||
|         type: 'https-passthrough', | ||||
|         target: { host: 'localhost', port: 443 }, | ||||
|         http: { enabled: true } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { tap, expect } from '@push.rocks/tapbundle'; | ||||
| import * as plugins from '../ts/plugins.js'; | ||||
| import type { ForwardConfig } from '../ts/forwarding/config/forwarding-types.js'; | ||||
| import type { IForwardConfig } from '../ts/forwarding/config/forwarding-types.js'; | ||||
|  | ||||
| // First, import the components directly to avoid issues with compiled modules | ||||
| import { ForwardingHandlerFactory } from '../ts/forwarding/factory/forwarding-factory.js'; | ||||
| @@ -17,7 +17,7 @@ const helpers = { | ||||
|  | ||||
| tap.test('ForwardingHandlerFactory - apply defaults based on type', async () => { | ||||
|       // HTTP-only defaults | ||||
|       const httpConfig: ForwardConfig = { | ||||
|       const httpConfig: IForwardConfig = { | ||||
|         type: 'http-only', | ||||
|         target: { host: 'localhost', port: 3000 } | ||||
|       }; | ||||
| @@ -26,7 +26,7 @@ tap.test('ForwardingHandlerFactory - apply defaults based on type', async () => | ||||
|       expect(expandedHttpConfig.http?.enabled).toEqual(true); | ||||
|  | ||||
|       // HTTPS-passthrough defaults | ||||
|       const passthroughConfig: ForwardConfig = { | ||||
|       const passthroughConfig: IForwardConfig = { | ||||
|         type: 'https-passthrough', | ||||
|         target: { host: 'localhost', port: 443 } | ||||
|       }; | ||||
| @@ -36,7 +36,7 @@ tap.test('ForwardingHandlerFactory - apply defaults based on type', async () => | ||||
|       expect(expandedPassthroughConfig.http?.enabled).toEqual(false); | ||||
|  | ||||
|       // HTTPS-terminate-to-http defaults | ||||
|       const terminateToHttpConfig: ForwardConfig = { | ||||
|       const terminateToHttpConfig: IForwardConfig = { | ||||
|         type: 'https-terminate-to-http', | ||||
|         target: { host: 'localhost', port: 3000 } | ||||
|       }; | ||||
| @@ -48,7 +48,7 @@ tap.test('ForwardingHandlerFactory - apply defaults based on type', async () => | ||||
|       expect(expandedTerminateToHttpConfig.acme?.maintenance).toEqual(true); | ||||
|  | ||||
|       // HTTPS-terminate-to-https defaults | ||||
|       const terminateToHttpsConfig: ForwardConfig = { | ||||
|       const terminateToHttpsConfig: IForwardConfig = { | ||||
|         type: 'https-terminate-to-https', | ||||
|         target: { host: 'localhost', port: 8443 } | ||||
|       }; | ||||
| @@ -62,7 +62,7 @@ tap.test('ForwardingHandlerFactory - apply defaults based on type', async () => | ||||
|      | ||||
| tap.test('ForwardingHandlerFactory - validate configuration', async () => { | ||||
|       // Valid configuration | ||||
|       const validConfig: ForwardConfig = { | ||||
|       const validConfig: IForwardConfig = { | ||||
|         type: 'http-only', | ||||
|         target: { host: 'localhost', port: 3000 } | ||||
|       }; | ||||
| @@ -77,7 +77,7 @@ tap.test('ForwardingHandlerFactory - validate configuration', async () => { | ||||
|       expect(() => ForwardingHandlerFactory.validateConfig(invalidConfig1)).toThrow(); | ||||
|        | ||||
|       // Invalid configuration - invalid port | ||||
|       const invalidConfig2: ForwardConfig = { | ||||
|       const invalidConfig2: IForwardConfig = { | ||||
|         type: 'http-only', | ||||
|         target: { host: 'localhost', port: 0 } | ||||
|       }; | ||||
|   | ||||
| @@ -282,10 +282,20 @@ tap.test('should support optional source IP preservation in chained proxies', as | ||||
| // Test round-robin behavior for multiple target hosts in a domain config. | ||||
| tap.test('should use round robin for multiple target hosts in domain config', async () => { | ||||
|   // Create a domain config with multiple hosts in the target | ||||
|   const domainConfig = { | ||||
|   const domainConfig: { | ||||
|     domains: string[]; | ||||
|     forwarding: { | ||||
|       type: 'http-only'; | ||||
|       target: { | ||||
|         host: string[]; | ||||
|         port: number; | ||||
|       }; | ||||
|       http: { enabled: boolean }; | ||||
|     } | ||||
|   } = { | ||||
|     domains: ['rr.test'], | ||||
|     forwarding: { | ||||
|       type: 'http-only', | ||||
|       type: 'http-only' as const, | ||||
|       target: { | ||||
|         host: ['hostA', 'hostB'], // Array of hosts for round-robin | ||||
|         port: 80 | ||||
|   | ||||
| @@ -3,6 +3,6 @@ | ||||
|  */ | ||||
| export const commitinfo = { | ||||
|   name: '@push.rocks/smartproxy', | ||||
|   version: '13.1.0', | ||||
|   version: '13.1.1', | ||||
|   description: 'A powerful proxy package that effectively handles high traffic, with features such as SSL/TLS support, port proxying, WebSocket handling, dynamic routing with authentication options, and automatic ACME certificate management.' | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import * as fs from 'fs'; | ||||
| import * as path from 'path'; | ||||
| import type { AcmeOptions } from '../models/certificate-types.js'; | ||||
| import type { IAcmeOptions } from '../models/certificate-types.js'; | ||||
| import { ensureCertificateDirectory } from '../utils/certificate-helpers.js'; | ||||
| // We'll need to update this import when we move the Port80Handler | ||||
| import { Port80Handler } from '../../http/port80/port80-handler.js'; | ||||
| @@ -12,7 +12,7 @@ import { Port80Handler } from '../../http/port80/port80-handler.js'; | ||||
|  * @returns A new Port80Handler instance | ||||
|  */ | ||||
| export function buildPort80Handler( | ||||
|   options: AcmeOptions | ||||
|   options: IAcmeOptions | ||||
| ): Port80Handler { | ||||
|   if (options.certificateStore) { | ||||
|     ensureCertificateDirectory(options.certificateStore); | ||||
| @@ -32,7 +32,7 @@ export function createDefaultAcmeOptions( | ||||
|   email: string, | ||||
|   certificateStore: string, | ||||
|   useProduction: boolean = false | ||||
| ): AcmeOptions { | ||||
| ): IAcmeOptions { | ||||
|   return { | ||||
|     accountEmail: email, | ||||
|     enabled: true, | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import type { AcmeOptions, CertificateData } from '../models/certificate-types.js'; | ||||
| import type { IAcmeOptions, ICertificateData } from '../models/certificate-types.js'; | ||||
| import { CertificateEvents } from '../events/certificate-events.js'; | ||||
|  | ||||
| /** | ||||
|  * Manages ACME challenges and certificate validation | ||||
|  */ | ||||
| export class AcmeChallengeHandler extends plugins.EventEmitter { | ||||
|   private options: AcmeOptions; | ||||
|   private options: IAcmeOptions; | ||||
|   private client: any; // ACME client from plugins | ||||
|   private pendingChallenges: Map<string, any>; | ||||
|  | ||||
| @@ -14,7 +14,7 @@ export class AcmeChallengeHandler extends plugins.EventEmitter { | ||||
|    * Creates a new ACME challenge handler | ||||
|    * @param options ACME configuration options | ||||
|    */ | ||||
|   constructor(options: AcmeOptions) { | ||||
|   constructor(options: IAcmeOptions) { | ||||
|     super(); | ||||
|     this.options = options; | ||||
|     this.pendingChallenges = new Map(); | ||||
|   | ||||
| @@ -25,8 +25,8 @@ export * from './storage/file-storage.js'; | ||||
| // Convenience function to create a certificate provisioner with common settings | ||||
| import { CertProvisioner } from './providers/cert-provisioner.js'; | ||||
| import { buildPort80Handler } from './acme/acme-factory.js'; | ||||
| import type { AcmeOptions, DomainForwardConfig } from './models/certificate-types.js'; | ||||
| import type { DomainConfig } from '../forwarding/config/domain-config.js'; | ||||
| import type { IAcmeOptions, IDomainForwardConfig } from './models/certificate-types.js'; | ||||
| import type { IDomainConfig } from '../forwarding/config/domain-config.js'; | ||||
|  | ||||
| /** | ||||
|  * Creates a complete certificate provisioning system with default settings | ||||
| @@ -37,8 +37,8 @@ import type { DomainConfig } from '../forwarding/config/domain-config.js'; | ||||
|  * @returns Configured CertProvisioner | ||||
|  */ | ||||
| export function createCertificateProvisioner( | ||||
|   domainConfigs: DomainConfig[], | ||||
|   acmeOptions: AcmeOptions, | ||||
|   domainConfigs: IDomainConfig[], | ||||
|   acmeOptions: IAcmeOptions, | ||||
|   networkProxyBridge: any, // Placeholder until NetworkProxyBridge is migrated | ||||
|   certProvider?: any // Placeholder until cert provider type is properly defined | ||||
| ): CertProvisioner { | ||||
|   | ||||
| @@ -84,4 +84,5 @@ export interface IAcmeOptions { | ||||
|   certificateStore?: string;      // Directory to store certificates | ||||
|   skipConfiguredCerts?: boolean;  // Skip domains with existing certificates | ||||
|   domainForwards?: IDomainForwardConfig[]; // Domain-specific forwarding configs | ||||
| } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,34 +1,34 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import type { DomainConfig } from '../../forwarding/config/domain-config.js'; | ||||
| import type { CertificateData, DomainForwardConfig, DomainOptions } from '../models/certificate-types.js'; | ||||
| import type { IDomainConfig } from '../../forwarding/config/domain-config.js'; | ||||
| import type { ICertificateData, IDomainForwardConfig, IDomainOptions } from '../models/certificate-types.js'; | ||||
| import { Port80HandlerEvents, CertProvisionerEvents } from '../events/certificate-events.js'; | ||||
| import { Port80Handler } from '../../http/port80/port80-handler.js'; | ||||
| // We need to define this interface until we migrate NetworkProxyBridge | ||||
| interface NetworkProxyBridge { | ||||
|   applyExternalCertificate(certData: CertificateData): void; | ||||
| interface INetworkProxyBridge { | ||||
|   applyExternalCertificate(certData: ICertificateData): void; | ||||
| } | ||||
|  | ||||
| // This will be imported after NetworkProxyBridge is migrated | ||||
| // import type { NetworkProxyBridge } from '../../proxies/smart-proxy/network-proxy-bridge.js'; | ||||
|  | ||||
| // For backward compatibility | ||||
| export type ISmartProxyCertProvisionObject = plugins.tsclass.network.ICert | 'http01'; | ||||
| export type TSmartProxyCertProvisionObject = plugins.tsclass.network.ICert | 'http01'; | ||||
|  | ||||
| /** | ||||
|  * Type for static certificate provisioning | ||||
|  */ | ||||
| export type CertProvisionObject = plugins.tsclass.network.ICert | 'http01' | 'dns01'; | ||||
| export type TCertProvisionObject = plugins.tsclass.network.ICert | 'http01' | 'dns01'; | ||||
|  | ||||
| /** | ||||
|  * CertProvisioner manages certificate provisioning and renewal workflows, | ||||
|  * unifying static certificates and HTTP-01 challenges via Port80Handler. | ||||
|  */ | ||||
| export class CertProvisioner extends plugins.EventEmitter { | ||||
|   private domainConfigs: DomainConfig[]; | ||||
|   private domainConfigs: IDomainConfig[]; | ||||
|   private port80Handler: Port80Handler; | ||||
|   private networkProxyBridge: NetworkProxyBridge; | ||||
|   private certProvisionFunction?: (domain: string) => Promise<CertProvisionObject>; | ||||
|   private forwardConfigs: DomainForwardConfig[]; | ||||
|   private networkProxyBridge: INetworkProxyBridge; | ||||
|   private certProvisionFunction?: (domain: string) => Promise<TCertProvisionObject>; | ||||
|   private forwardConfigs: IDomainForwardConfig[]; | ||||
|   private renewThresholdDays: number; | ||||
|   private renewCheckIntervalHours: number; | ||||
|   private autoRenew: boolean; | ||||
| @@ -47,14 +47,14 @@ export class CertProvisioner extends plugins.EventEmitter { | ||||
|    * @param forwardConfigs Domain forwarding configurations for ACME challenges | ||||
|    */ | ||||
|   constructor( | ||||
|     domainConfigs: DomainConfig[], | ||||
|     domainConfigs: IDomainConfig[], | ||||
|     port80Handler: Port80Handler, | ||||
|     networkProxyBridge: NetworkProxyBridge, | ||||
|     certProvider?: (domain: string) => Promise<CertProvisionObject>, | ||||
|     networkProxyBridge: INetworkProxyBridge, | ||||
|     certProvider?: (domain: string) => Promise<TCertProvisionObject>, | ||||
|     renewThresholdDays: number = 30, | ||||
|     renewCheckIntervalHours: number = 24, | ||||
|     autoRenew: boolean = true, | ||||
|     forwardConfigs: DomainForwardConfig[] = [] | ||||
|     forwardConfigs: IDomainForwardConfig[] = [] | ||||
|   ) { | ||||
|     super(); | ||||
|     this.domainConfigs = domainConfigs; | ||||
| @@ -92,11 +92,11 @@ export class CertProvisioner extends plugins.EventEmitter { | ||||
|    */ | ||||
|   private setupEventSubscriptions(): void { | ||||
|     // We need to reimplement subscribeToPort80Handler here | ||||
|     this.port80Handler.on(Port80HandlerEvents.CERTIFICATE_ISSUED, (data: CertificateData) => { | ||||
|     this.port80Handler.on(Port80HandlerEvents.CERTIFICATE_ISSUED, (data: ICertificateData) => { | ||||
|       this.emit(CertProvisionerEvents.CERTIFICATE_ISSUED, { ...data, source: 'http01', isRenewal: false }); | ||||
|     }); | ||||
|  | ||||
|     this.port80Handler.on(Port80HandlerEvents.CERTIFICATE_RENEWED, (data: CertificateData) => { | ||||
|     this.port80Handler.on(Port80HandlerEvents.CERTIFICATE_RENEWED, (data: ICertificateData) => { | ||||
|       this.emit(CertProvisionerEvents.CERTIFICATE_RENEWED, { ...data, source: 'http01', isRenewal: true }); | ||||
|     }); | ||||
|  | ||||
| @@ -110,7 +110,7 @@ export class CertProvisioner extends plugins.EventEmitter { | ||||
|    */ | ||||
|   private setupForwardingConfigs(): void { | ||||
|     for (const config of this.forwardConfigs) { | ||||
|       const domainOptions: DomainOptions = { | ||||
|       const domainOptions: IDomainOptions = { | ||||
|         domainName: config.domain, | ||||
|         sslRedirect: config.sslRedirect || false, | ||||
|         acmeMaintenance: false, | ||||
| @@ -138,7 +138,7 @@ export class CertProvisioner extends plugins.EventEmitter { | ||||
|    */ | ||||
|   private async provisionDomain(domain: string): Promise<void> { | ||||
|     const isWildcard = domain.includes('*'); | ||||
|     let provision: CertProvisionObject = 'http01'; | ||||
|     let provision: TCertProvisionObject = 'http01'; | ||||
|  | ||||
|     // Try to get a certificate from the provision function | ||||
|     if (this.certProvisionFunction) { | ||||
| @@ -174,7 +174,7 @@ export class CertProvisioner extends plugins.EventEmitter { | ||||
|       // Static certificate (e.g., DNS-01 provisioned or user-provided) | ||||
|       this.provisionMap.set(domain, 'static'); | ||||
|       const certObj = provision as plugins.tsclass.network.ICert; | ||||
|       const certData: CertificateData = { | ||||
|       const certData: ICertificateData = { | ||||
|         domain: certObj.domainName, | ||||
|         certificate: certObj.publicKey, | ||||
|         privateKey: certObj.privateKey, | ||||
| @@ -235,7 +235,7 @@ export class CertProvisioner extends plugins.EventEmitter { | ||||
|  | ||||
|       if (provision !== 'http01' && provision !== 'dns01') { | ||||
|         const certObj = provision as plugins.tsclass.network.ICert; | ||||
|         const certData: CertificateData = { | ||||
|         const certData: ICertificateData = { | ||||
|           domain: certObj.domainName, | ||||
|           certificate: certObj.publicKey, | ||||
|           privateKey: certObj.privateKey, | ||||
| @@ -267,7 +267,7 @@ export class CertProvisioner extends plugins.EventEmitter { | ||||
|     const isWildcard = domain.includes('*'); | ||||
|  | ||||
|     // Determine provisioning method | ||||
|     let provision: CertProvisionObject = 'http01'; | ||||
|     let provision: TCertProvisionObject = 'http01'; | ||||
|  | ||||
|     if (this.certProvisionFunction) { | ||||
|       provision = await this.certProvisionFunction(domain); | ||||
| @@ -288,7 +288,7 @@ export class CertProvisioner extends plugins.EventEmitter { | ||||
|     } else { | ||||
|       // Static certificate (e.g., DNS-01 provisioned) supports wildcards | ||||
|       const certObj = provision as plugins.tsclass.network.ICert; | ||||
|       const certData: CertificateData = { | ||||
|       const certData: ICertificateData = { | ||||
|         domain: certObj.domainName, | ||||
|         certificate: certObj.publicKey, | ||||
|         privateKey: certObj.privateKey, | ||||
| @@ -311,7 +311,7 @@ export class CertProvisioner extends plugins.EventEmitter { | ||||
|     sslRedirect?: boolean; | ||||
|     acmeMaintenance?: boolean; | ||||
|   }): Promise<void> { | ||||
|     const domainOptions: DomainOptions = { | ||||
|     const domainOptions: IDomainOptions = { | ||||
|       domainName: domain, | ||||
|       sslRedirect: options?.sslRedirect || true, | ||||
|       acmeMaintenance: options?.acmeMaintenance || true | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import * as fs from 'fs'; | ||||
| import * as path from 'path'; | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import type { CertificateData, Certificates } from '../models/certificate-types.js'; | ||||
| import type { ICertificateData, ICertificates } from '../models/certificate-types.js'; | ||||
| import { ensureCertificateDirectory } from '../utils/certificate-helpers.js'; | ||||
|  | ||||
| /** | ||||
| @@ -21,10 +21,10 @@ export class FileStorage { | ||||
|    | ||||
|   /** | ||||
|    * Save a certificate to the file system | ||||
|    * @param domain Domain name  | ||||
|    * @param domain Domain name | ||||
|    * @param certData Certificate data to save | ||||
|    */ | ||||
|   public async saveCertificate(domain: string, certData: CertificateData): Promise<void> { | ||||
|   public async saveCertificate(domain: string, certData: ICertificateData): Promise<void> { | ||||
|     const sanitizedDomain = this.sanitizeDomain(domain); | ||||
|     const certDir = path.join(this.storageDir, sanitizedDomain); | ||||
|     ensureCertificateDirectory(certDir); | ||||
| @@ -57,7 +57,7 @@ export class FileStorage { | ||||
|    * @param domain Domain name | ||||
|    * @returns Certificate data if found, null otherwise | ||||
|    */ | ||||
|   public async loadCertificate(domain: string): Promise<CertificateData | null> { | ||||
|   public async loadCertificate(domain: string): Promise<ICertificateData | null> { | ||||
|     const sanitizedDomain = this.sanitizeDomain(domain); | ||||
|     const certDir = path.join(this.storageDir, sanitizedDomain); | ||||
|      | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import * as fs from 'fs'; | ||||
| import * as path from 'path'; | ||||
| import { fileURLToPath } from 'url'; | ||||
| import type { Certificates } from '../models/certificate-types.js'; | ||||
| import type { ICertificates } from '../models/certificate-types.js'; | ||||
|  | ||||
| const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||||
|  | ||||
| @@ -9,7 +9,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||||
|  * Loads the default SSL certificates from the assets directory | ||||
|  * @returns The certificate key pair | ||||
|  */ | ||||
| export function loadDefaultCertificates(): Certificates { | ||||
| export function loadDefaultCertificates(): ICertificates { | ||||
|   try { | ||||
|     // Need to adjust path from /ts/certificate/utils to /assets/certs | ||||
|     const certPath = path.join(__dirname, '..', '..', '..', 'assets', 'certs'); | ||||
|   | ||||
| @@ -6,7 +6,7 @@ import type { | ||||
| } from './types.js'; | ||||
|  | ||||
| import type { | ||||
|   ForwardConfig as IForwardConfig | ||||
|   IForwardConfig | ||||
| } from '../forwarding/config/forwarding-types.js'; | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| import type { ForwardConfig } from './forwarding-types.js'; | ||||
| import type { IForwardConfig } from './forwarding-types.js'; | ||||
|  | ||||
| /** | ||||
|  * Domain configuration with unified forwarding configuration | ||||
|  */ | ||||
| export interface DomainConfig { | ||||
| export interface IDomainConfig { | ||||
|   // Core properties - domain patterns | ||||
|   domains: string[]; | ||||
|  | ||||
|   // Unified forwarding configuration | ||||
|   forwarding: ForwardConfig; | ||||
|   forwarding: IForwardConfig; | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -16,8 +16,8 @@ export interface DomainConfig { | ||||
|  */ | ||||
| export function createDomainConfig( | ||||
|   domains: string | string[], | ||||
|   forwarding: ForwardConfig | ||||
| ): DomainConfig { | ||||
|   forwarding: IForwardConfig | ||||
| ): IDomainConfig { | ||||
|   // Normalize domains to an array | ||||
|   const domainArray = Array.isArray(domains) ? domains : [domains]; | ||||
|  | ||||
| @@ -25,7 +25,4 @@ export function createDomainConfig( | ||||
|     domains: domainArray, | ||||
|     forwarding | ||||
|   }; | ||||
| } | ||||
|  | ||||
| // Backwards compatibility | ||||
| export interface IDomainConfig extends DomainConfig {} | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import type { DomainConfig } from './domain-config.js'; | ||||
| import type { IDomainConfig } from './domain-config.js'; | ||||
| import { ForwardingHandler } from '../handlers/base-handler.js'; | ||||
| import { ForwardingHandlerEvents } from './forwarding-types.js'; | ||||
| import { ForwardingHandlerFactory } from '../factory/forwarding-factory.js'; | ||||
| @@ -21,14 +21,14 @@ export enum DomainManagerEvents { | ||||
|  * Manages domains and their forwarding handlers | ||||
|  */ | ||||
| export class DomainManager extends plugins.EventEmitter { | ||||
|   private domainConfigs: DomainConfig[] = []; | ||||
|   private domainConfigs: IDomainConfig[] = []; | ||||
|   private domainHandlers: Map<string, ForwardingHandler> = new Map(); | ||||
|    | ||||
|  | ||||
|   /** | ||||
|    * Create a new DomainManager | ||||
|    * @param initialDomains Optional initial domain configurations | ||||
|    */ | ||||
|   constructor(initialDomains?: DomainConfig[]) { | ||||
|   constructor(initialDomains?: IDomainConfig[]) { | ||||
|     super(); | ||||
|      | ||||
|     if (initialDomains) { | ||||
| @@ -40,7 +40,7 @@ export class DomainManager extends plugins.EventEmitter { | ||||
|    * Set or replace all domain configurations | ||||
|    * @param configs Array of domain configurations | ||||
|    */ | ||||
|   public async setDomainConfigs(configs: DomainConfig[]): Promise<void> { | ||||
|   public async setDomainConfigs(configs: IDomainConfig[]): Promise<void> { | ||||
|     // Clear existing handlers | ||||
|     this.domainHandlers.clear(); | ||||
|      | ||||
| @@ -57,7 +57,7 @@ export class DomainManager extends plugins.EventEmitter { | ||||
|    * Add a new domain configuration | ||||
|    * @param config The domain configuration to add | ||||
|    */ | ||||
|   public async addDomainConfig(config: DomainConfig): Promise<void> { | ||||
|   public async addDomainConfig(config: IDomainConfig): Promise<void> { | ||||
|     // Check if any of these domains already exist | ||||
|     for (const domain of config.domains) { | ||||
|       if (this.domainHandlers.has(domain)) { | ||||
| @@ -193,7 +193,7 @@ export class DomainManager extends plugins.EventEmitter { | ||||
|    * Create handlers for a domain configuration | ||||
|    * @param config The domain configuration | ||||
|    */ | ||||
|   private async createHandlersForDomain(config: DomainConfig): Promise<void> { | ||||
|   private async createHandlersForDomain(config: IDomainConfig): Promise<void> { | ||||
|     try { | ||||
|       // Create a handler for this forwarding configuration | ||||
|       const handler = ForwardingHandlerFactory.createHandler(config.forwarding); | ||||
| @@ -221,7 +221,7 @@ export class DomainManager extends plugins.EventEmitter { | ||||
|    * @param handler The handler | ||||
|    * @param config The domain configuration for this handler | ||||
|    */ | ||||
|   private setupHandlerEvents(handler: ForwardingHandler, config: DomainConfig): void { | ||||
|   private setupHandlerEvents(handler: ForwardingHandler, config: IDomainConfig): void { | ||||
|     // Forward relevant events | ||||
|     handler.on(ForwardingHandlerEvents.CERTIFICATE_NEEDED, (data) => { | ||||
|       this.emit(DomainManagerEvents.CERTIFICATE_NEEDED, { | ||||
| @@ -277,7 +277,7 @@ export class DomainManager extends plugins.EventEmitter { | ||||
|    * Get all domain configurations | ||||
|    * @returns Array of domain configurations | ||||
|    */ | ||||
|   public getDomainConfigs(): DomainConfig[] { | ||||
|   public getDomainConfigs(): IDomainConfig[] { | ||||
|     return [...this.domainConfigs]; | ||||
|   } | ||||
| } | ||||
| @@ -3,7 +3,7 @@ import type * as plugins from '../../plugins.js'; | ||||
| /** | ||||
|  * The primary forwarding types supported by SmartProxy | ||||
|  */ | ||||
| export type ForwardingType = | ||||
| export type TForwardingType = | ||||
|   | 'http-only'                // HTTP forwarding only (no HTTPS) | ||||
|   | 'https-passthrough'        // Pass-through TLS traffic (SNI forwarding) | ||||
|   | 'https-terminate-to-http'  // Terminate TLS and forward to HTTP backend | ||||
| @@ -12,7 +12,7 @@ export type ForwardingType = | ||||
| /** | ||||
|  * Target configuration for forwarding | ||||
|  */ | ||||
| export interface TargetConfig { | ||||
| export interface ITargetConfig { | ||||
|   host: string | string[];  // Support single host or round-robin | ||||
|   port: number; | ||||
| } | ||||
| @@ -20,7 +20,7 @@ export interface TargetConfig { | ||||
| /** | ||||
|  * HTTP-specific options for forwarding | ||||
|  */ | ||||
| export interface HttpOptions { | ||||
| export interface IHttpOptions { | ||||
|   enabled?: boolean;                 // Whether HTTP is enabled | ||||
|   redirectToHttps?: boolean;         // Redirect HTTP to HTTPS | ||||
|   headers?: Record<string, string>;  // Custom headers for HTTP responses | ||||
| @@ -29,7 +29,7 @@ export interface HttpOptions { | ||||
| /** | ||||
|  * HTTPS-specific options for forwarding | ||||
|  */ | ||||
| export interface HttpsOptions { | ||||
| export interface IHttpsOptions { | ||||
|   customCert?: {                    // Use custom cert instead of auto-provisioned | ||||
|     key: string; | ||||
|     cert: string; | ||||
| @@ -40,8 +40,8 @@ export interface HttpsOptions { | ||||
| /** | ||||
|  * ACME certificate handling options | ||||
|  */ | ||||
| export interface AcmeForwardingOptions { | ||||
|   enabled?: boolean;                // Enable ACME certificate provisioning   | ||||
| export interface IAcmeForwardingOptions { | ||||
|   enabled?: boolean;                // Enable ACME certificate provisioning | ||||
|   maintenance?: boolean;            // Auto-renew certificates | ||||
|   production?: boolean;             // Use production ACME servers | ||||
|   forwardChallenges?: {             // Forward ACME challenges | ||||
| @@ -54,7 +54,7 @@ export interface AcmeForwardingOptions { | ||||
| /** | ||||
|  * Security options for forwarding | ||||
|  */ | ||||
| export interface SecurityOptions { | ||||
| export interface ISecurityOptions { | ||||
|   allowedIps?: string[];            // IPs allowed to connect | ||||
|   blockedIps?: string[];            // IPs blocked from connecting | ||||
|   maxConnections?: number;          // Max simultaneous connections | ||||
| @@ -63,7 +63,7 @@ export interface SecurityOptions { | ||||
| /** | ||||
|  * Advanced options for forwarding | ||||
|  */ | ||||
| export interface AdvancedOptions { | ||||
| export interface IAdvancedOptions { | ||||
|   portRanges?: Array<{ from: number; to: number }>; // Allowed port ranges | ||||
|   networkProxyPort?: number;        // Custom NetworkProxy port if using terminate mode | ||||
|   keepAlive?: boolean;              // Enable TCP keepalive | ||||
| @@ -74,21 +74,21 @@ export interface AdvancedOptions { | ||||
| /** | ||||
|  * Unified forwarding configuration interface | ||||
|  */ | ||||
| export interface ForwardConfig { | ||||
| export interface IForwardConfig { | ||||
|   // Define the primary forwarding type - use-case driven approach | ||||
|   type: ForwardingType; | ||||
|    | ||||
|   type: TForwardingType; | ||||
|  | ||||
|   // Target configuration | ||||
|   target: TargetConfig; | ||||
|    | ||||
|   target: ITargetConfig; | ||||
|  | ||||
|   // Protocol options | ||||
|   http?: HttpOptions; | ||||
|   https?: HttpsOptions; | ||||
|   acme?: AcmeForwardingOptions; | ||||
|    | ||||
|   http?: IHttpOptions; | ||||
|   https?: IHttpsOptions; | ||||
|   acme?: IAcmeForwardingOptions; | ||||
|  | ||||
|   // Security and advanced options | ||||
|   security?: SecurityOptions; | ||||
|   advanced?: AdvancedOptions; | ||||
|   security?: ISecurityOptions; | ||||
|   advanced?: IAdvancedOptions; | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -118,8 +118,8 @@ export interface IForwardingHandler extends plugins.EventEmitter { | ||||
|  * Helper function types for common forwarding patterns | ||||
|  */ | ||||
| export const httpOnly = ( | ||||
|   partialConfig: Partial<ForwardConfig> & Pick<ForwardConfig, 'target'> | ||||
| ): ForwardConfig => ({ | ||||
|   partialConfig: Partial<IForwardConfig> & Pick<IForwardConfig, 'target'> | ||||
| ): IForwardConfig => ({ | ||||
|   type: 'http-only', | ||||
|   target: partialConfig.target, | ||||
|   http: { enabled: true, ...(partialConfig.http || {}) }, | ||||
| @@ -128,8 +128,8 @@ export const httpOnly = ( | ||||
| }); | ||||
|  | ||||
| export const tlsTerminateToHttp = ( | ||||
|   partialConfig: Partial<ForwardConfig> & Pick<ForwardConfig, 'target'> | ||||
| ): ForwardConfig => ({ | ||||
|   partialConfig: Partial<IForwardConfig> & Pick<IForwardConfig, 'target'> | ||||
| ): IForwardConfig => ({ | ||||
|   type: 'https-terminate-to-http', | ||||
|   target: partialConfig.target, | ||||
|   https: { ...(partialConfig.https || {}) }, | ||||
| @@ -140,8 +140,8 @@ export const tlsTerminateToHttp = ( | ||||
| }); | ||||
|  | ||||
| export const tlsTerminateToHttps = ( | ||||
|   partialConfig: Partial<ForwardConfig> & Pick<ForwardConfig, 'target'> | ||||
| ): ForwardConfig => ({ | ||||
|   partialConfig: Partial<IForwardConfig> & Pick<IForwardConfig, 'target'> | ||||
| ): IForwardConfig => ({ | ||||
|   type: 'https-terminate-to-https', | ||||
|   target: partialConfig.target, | ||||
|   https: { ...(partialConfig.https || {}) }, | ||||
| @@ -152,20 +152,11 @@ export const tlsTerminateToHttps = ( | ||||
| }); | ||||
|  | ||||
| export const httpsPassthrough = ( | ||||
|   partialConfig: Partial<ForwardConfig> & Pick<ForwardConfig, 'target'> | ||||
| ): ForwardConfig => ({ | ||||
|   partialConfig: Partial<IForwardConfig> & Pick<IForwardConfig, 'target'> | ||||
| ): IForwardConfig => ({ | ||||
|   type: 'https-passthrough', | ||||
|   target: partialConfig.target, | ||||
|   https: { forwardSni: true, ...(partialConfig.https || {}) }, | ||||
|   ...(partialConfig.security ? { security: partialConfig.security } : {}), | ||||
|   ...(partialConfig.advanced ? { advanced: partialConfig.advanced } : {}) | ||||
| }); | ||||
|  | ||||
| // Backwards compatibility interfaces with 'I' prefix | ||||
| export interface ITargetConfig extends TargetConfig {} | ||||
| export interface IHttpOptions extends HttpOptions {} | ||||
| export interface IHttpsOptions extends HttpsOptions {} | ||||
| export interface IAcmeForwardingOptions extends AcmeForwardingOptions {} | ||||
| export interface ISecurityOptions extends SecurityOptions {} | ||||
| export interface IAdvancedOptions extends AdvancedOptions {} | ||||
| export interface IForwardConfig extends ForwardConfig {} | ||||
| }); | ||||
| @@ -1,5 +1,5 @@ | ||||
| import type { ForwardConfig } from '../config/forwarding-types.js'; | ||||
| import type { ForwardingHandler } from '../handlers/base-handler.js'; | ||||
| import type { IForwardConfig } from '../config/forwarding-types.js'; | ||||
| import { ForwardingHandler } from '../handlers/base-handler.js'; | ||||
| import { HttpForwardingHandler } from '../handlers/http-handler.js'; | ||||
| import { HttpsPassthroughHandler } from '../handlers/https-passthrough-handler.js'; | ||||
| import { HttpsTerminateToHttpHandler } from '../handlers/https-terminate-to-http-handler.js'; | ||||
| @@ -14,35 +14,35 @@ export class ForwardingHandlerFactory { | ||||
|    * @param config The forwarding configuration | ||||
|    * @returns The appropriate forwarding handler | ||||
|    */ | ||||
|   public static createHandler(config: ForwardConfig): ForwardingHandler { | ||||
|   public static createHandler(config: IForwardConfig): ForwardingHandler { | ||||
|     // Create the appropriate handler based on the forwarding type | ||||
|     switch (config.type) { | ||||
|       case 'http-only': | ||||
|         return new HttpForwardingHandler(config); | ||||
|          | ||||
|  | ||||
|       case 'https-passthrough': | ||||
|         return new HttpsPassthroughHandler(config); | ||||
|          | ||||
|  | ||||
|       case 'https-terminate-to-http': | ||||
|         return new HttpsTerminateToHttpHandler(config); | ||||
|          | ||||
|  | ||||
|       case 'https-terminate-to-https': | ||||
|         return new HttpsTerminateToHttpsHandler(config); | ||||
|          | ||||
|  | ||||
|       default: | ||||
|         // Type system should prevent this, but just in case: | ||||
|         throw new Error(`Unknown forwarding type: ${(config as any).type}`); | ||||
|     } | ||||
|   } | ||||
|    | ||||
|  | ||||
|   /** | ||||
|    * Apply default values to a forwarding configuration based on its type | ||||
|    * @param config The original forwarding configuration | ||||
|    * @returns A configuration with defaults applied | ||||
|    */ | ||||
|   public static applyDefaults(config: ForwardConfig): ForwardConfig { | ||||
|   public static applyDefaults(config: IForwardConfig): IForwardConfig { | ||||
|     // Create a deep copy of the configuration | ||||
|     const result: ForwardConfig = JSON.parse(JSON.stringify(config)); | ||||
|     const result: IForwardConfig = JSON.parse(JSON.stringify(config)); | ||||
|      | ||||
|     // Apply defaults based on forwarding type | ||||
|     switch (config.type) { | ||||
| @@ -112,7 +112,7 @@ export class ForwardingHandlerFactory { | ||||
|    * @param config The configuration to validate | ||||
|    * @throws Error if the configuration is invalid | ||||
|    */ | ||||
|   public static validateConfig(config: ForwardConfig): void { | ||||
|   public static validateConfig(config: IForwardConfig): void { | ||||
|     // Validate common properties | ||||
|     if (!config.target) { | ||||
|       throw new Error('Forwarding configuration must include a target'); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import type { | ||||
|   ForwardConfig, | ||||
|   IForwardConfig, | ||||
|   IForwardingHandler | ||||
| } from '../config/forwarding-types.js'; | ||||
| import { ForwardingHandlerEvents } from '../config/forwarding-types.js'; | ||||
| @@ -13,7 +13,7 @@ export abstract class ForwardingHandler extends plugins.EventEmitter implements | ||||
|    * Create a new ForwardingHandler | ||||
|    * @param config The forwarding configuration | ||||
|    */ | ||||
|   constructor(protected config: ForwardConfig) { | ||||
|   constructor(protected config: IForwardConfig) { | ||||
|     super(); | ||||
|   } | ||||
|    | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import { ForwardingHandler } from './base-handler.js'; | ||||
| import type { ForwardConfig } from '../config/forwarding-types.js'; | ||||
| import type { IForwardConfig } from '../config/forwarding-types.js'; | ||||
| import { ForwardingHandlerEvents } from '../config/forwarding-types.js'; | ||||
|  | ||||
| /** | ||||
| @@ -11,14 +11,23 @@ export class HttpForwardingHandler extends ForwardingHandler { | ||||
|    * Create a new HTTP forwarding handler | ||||
|    * @param config The forwarding configuration | ||||
|    */ | ||||
|   constructor(config: ForwardConfig) { | ||||
|   constructor(config: IForwardConfig) { | ||||
|     super(config); | ||||
|      | ||||
|  | ||||
|     // Validate that this is an HTTP-only configuration | ||||
|     if (config.type !== 'http-only') { | ||||
|       throw new Error(`Invalid configuration type for HttpForwardingHandler: ${config.type}`); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Initialize the handler | ||||
|    * HTTP handler doesn't need special initialization | ||||
|    */ | ||||
|   public async initialize(): Promise<void> { | ||||
|     // Basic initialization from parent class | ||||
|     await super.initialize(); | ||||
|   } | ||||
|    | ||||
|   /** | ||||
|    * Handle a raw socket connection | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import { ForwardingHandler } from './base-handler.js'; | ||||
| import type { ForwardConfig } from '../config/forwarding-types.js'; | ||||
| import type { IForwardConfig } from '../config/forwarding-types.js'; | ||||
| import { ForwardingHandlerEvents } from '../config/forwarding-types.js'; | ||||
|  | ||||
| /** | ||||
| @@ -11,14 +11,23 @@ export class HttpsPassthroughHandler extends ForwardingHandler { | ||||
|    * Create a new HTTPS passthrough handler | ||||
|    * @param config The forwarding configuration | ||||
|    */ | ||||
|   constructor(config: ForwardConfig) { | ||||
|   constructor(config: IForwardConfig) { | ||||
|     super(config); | ||||
|      | ||||
|  | ||||
|     // Validate that this is an HTTPS passthrough configuration | ||||
|     if (config.type !== 'https-passthrough') { | ||||
|       throw new Error(`Invalid configuration type for HttpsPassthroughHandler: ${config.type}`); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Initialize the handler | ||||
|    * HTTPS passthrough handler doesn't need special initialization | ||||
|    */ | ||||
|   public async initialize(): Promise<void> { | ||||
|     // Basic initialization from parent class | ||||
|     await super.initialize(); | ||||
|   } | ||||
|    | ||||
|   /** | ||||
|    * Handle a TLS/SSL socket connection by forwarding it without termination | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import { ForwardingHandler } from './base-handler.js'; | ||||
| import type { ForwardConfig } from '../config/forwarding-types.js'; | ||||
| import type { IForwardConfig } from '../config/forwarding-types.js'; | ||||
| import { ForwardingHandlerEvents } from '../config/forwarding-types.js'; | ||||
|  | ||||
| /** | ||||
| @@ -14,7 +14,7 @@ export class HttpsTerminateToHttpHandler extends ForwardingHandler { | ||||
|    * Create a new HTTPS termination with HTTP backend handler | ||||
|    * @param config The forwarding configuration | ||||
|    */ | ||||
|   constructor(config: ForwardConfig) { | ||||
|   constructor(config: IForwardConfig) { | ||||
|     super(config); | ||||
|      | ||||
|     // Validate that this is an HTTPS terminate to HTTP configuration | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import { ForwardingHandler } from './base-handler.js'; | ||||
| import type { ForwardConfig } from '../config/forwarding-types.js'; | ||||
| import type { IForwardConfig } from '../config/forwarding-types.js'; | ||||
| import { ForwardingHandlerEvents } from '../config/forwarding-types.js'; | ||||
|  | ||||
| /** | ||||
| @@ -13,7 +13,7 @@ export class HttpsTerminateToHttpsHandler extends ForwardingHandler { | ||||
|    * Create a new HTTPS termination with HTTPS backend handler | ||||
|    * @param config The forwarding configuration | ||||
|    */ | ||||
|   constructor(config: ForwardConfig) { | ||||
|   constructor(config: IForwardConfig) { | ||||
|     super(config); | ||||
|      | ||||
|     // Validate that this is an HTTPS terminate to HTTPS configuration | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import type {  | ||||
|   ForwardConfig, | ||||
|   DomainOptions, | ||||
|   AcmeOptions | ||||
| import type { | ||||
|   IForwardConfig, | ||||
|   IDomainOptions, | ||||
|   IAcmeOptions | ||||
| } from '../../certificate/models/certificate-types.js'; | ||||
|  | ||||
| /** | ||||
| @@ -35,8 +35,8 @@ export enum HttpStatus { | ||||
| /** | ||||
|  * Represents a domain configuration with certificate status information | ||||
|  */ | ||||
| export interface DomainCertificate { | ||||
|   options: DomainOptions; | ||||
| export interface IDomainCertificate { | ||||
|   options: IDomainOptions; | ||||
|   certObtained: boolean; | ||||
|   obtainingInProgress: boolean; | ||||
|   certificate?: string; | ||||
| @@ -82,7 +82,7 @@ export class ServerError extends HttpError { | ||||
| /** | ||||
|  * Redirect configuration for HTTP requests | ||||
|  */ | ||||
| export interface RedirectConfig { | ||||
| export interface IRedirectConfig { | ||||
|   source: string;           // Source path or pattern | ||||
|   destination: string;      // Destination URL | ||||
|   type: HttpStatus;         // Redirect status code | ||||
| @@ -92,7 +92,7 @@ export interface RedirectConfig { | ||||
| /** | ||||
|  * HTTP router configuration | ||||
|  */ | ||||
| export interface RouterConfig { | ||||
| export interface IRouterConfig { | ||||
|   routes: Array<{ | ||||
|     path: string; | ||||
|     handler: (req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse) => void; | ||||
| @@ -102,5 +102,4 @@ export interface RouterConfig { | ||||
|  | ||||
| // Backward compatibility interfaces | ||||
| export { HttpError as Port80HandlerError }; | ||||
| export { CertificateError as CertError }; | ||||
| export type IDomainCertificate = DomainCertificate; | ||||
| export { CertificateError as CertError }; | ||||
| @@ -7,7 +7,7 @@ import * as plugins from '../../plugins.js'; | ||||
| /** | ||||
|  * Structure for SmartAcme certificate result | ||||
|  */ | ||||
| export interface SmartAcmeCert { | ||||
| export interface ISmartAcmeCert { | ||||
|   id?: string; | ||||
|   domainName: string; | ||||
|   created?: number | Date | string; | ||||
| @@ -20,7 +20,7 @@ export interface SmartAcmeCert { | ||||
| /** | ||||
|  * Structure for SmartAcme options | ||||
|  */ | ||||
| export interface SmartAcmeOptions { | ||||
| export interface ISmartAcmeOptions { | ||||
|   accountEmail: string; | ||||
|   certManager: ICertManager; | ||||
|   environment: 'production' | 'integration'; | ||||
| @@ -39,8 +39,8 @@ export interface SmartAcmeOptions { | ||||
|  */ | ||||
| export interface ICertManager { | ||||
|   init(): Promise<void>; | ||||
|   get(domainName: string): Promise<SmartAcmeCert | null>; | ||||
|   put(cert: SmartAcmeCert): Promise<SmartAcmeCert>; | ||||
|   get(domainName: string): Promise<ISmartAcmeCert | null>; | ||||
|   put(cert: ISmartAcmeCert): Promise<ISmartAcmeCert>; | ||||
|   delete(domainName: string): Promise<void>; | ||||
|   close?(): Promise<void>; | ||||
| } | ||||
| @@ -59,7 +59,7 @@ export interface IChallengeHandler<T> { | ||||
| /** | ||||
|  * HTTP-01 challenge type | ||||
|  */ | ||||
| export interface Http01Challenge { | ||||
| export interface IHttp01Challenge { | ||||
|   type: string; // 'http-01' | ||||
|   token: string; | ||||
|   keyAuthorization: string; | ||||
| @@ -69,17 +69,17 @@ export interface Http01Challenge { | ||||
| /** | ||||
|  * HTTP-01 Memory Handler Interface | ||||
|  */ | ||||
| export interface Http01MemoryHandler extends IChallengeHandler<Http01Challenge> { | ||||
| export interface IHttp01MemoryHandler extends IChallengeHandler<IHttp01Challenge> { | ||||
|   handleRequest(req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse, next?: () => void): void; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * SmartAcme main class interface | ||||
|  */ | ||||
| export interface SmartAcme { | ||||
| export interface ISmartAcme { | ||||
|   start(): Promise<void>; | ||||
|   stop(): Promise<void>; | ||||
|   getCertificateForDomain(domain: string): Promise<SmartAcmeCert>; | ||||
|   getCertificateForDomain(domain: string): Promise<ISmartAcmeCert>; | ||||
|   on?(event: string, listener: (data: any) => void): void; | ||||
|   eventEmitter?: plugins.EventEmitter; | ||||
| } | ||||
| @@ -4,15 +4,15 @@ import { | ||||
|   CertificateEvents | ||||
| } from '../../certificate/events/certificate-events.js'; | ||||
| import type { | ||||
|   CertificateData, | ||||
|   CertificateFailure, | ||||
|   CertificateExpiring | ||||
|   ICertificateData, | ||||
|   ICertificateFailure, | ||||
|   ICertificateExpiring | ||||
| } from '../../certificate/models/certificate-types.js'; | ||||
| import type { | ||||
|   SmartAcme, | ||||
|   SmartAcmeCert, | ||||
|   SmartAcmeOptions, | ||||
|   Http01MemoryHandler | ||||
|   ISmartAcme, | ||||
|   ISmartAcmeCert, | ||||
|   ISmartAcmeOptions, | ||||
|   IHttp01MemoryHandler | ||||
| } from './acme-interfaces.js'; | ||||
|  | ||||
| /** | ||||
| @@ -20,8 +20,8 @@ import type { | ||||
|  * It acts as a bridge between the HTTP server and the ACME challenge verification process | ||||
|  */ | ||||
| export class ChallengeResponder extends plugins.EventEmitter { | ||||
|   private smartAcme: SmartAcme | null = null; | ||||
|   private http01Handler: Http01MemoryHandler | null = null; | ||||
|   private smartAcme: ISmartAcme | null = null; | ||||
|   private http01Handler: IHttp01MemoryHandler | null = null; | ||||
|  | ||||
|   /** | ||||
|    * Creates a new challenge responder | ||||
| @@ -95,7 +95,7 @@ export class ChallengeResponder extends plugins.EventEmitter { | ||||
|       emitter.on('certificate', (data: any) => { | ||||
|         const isRenewal = !!data.isRenewal; | ||||
|  | ||||
|         const certData: CertificateData = { | ||||
|         const certData: ICertificateData = { | ||||
|           domain: data.domainName || data.domain, | ||||
|           certificate: data.publicKey || data.cert, | ||||
|           privateKey: data.privateKey || data.key, | ||||
| @@ -114,7 +114,7 @@ export class ChallengeResponder extends plugins.EventEmitter { | ||||
|       // Forward error events | ||||
|       emitter.on('error', (error: any) => { | ||||
|         const domain = error.domainName || error.domain || 'unknown'; | ||||
|         const failureData: CertificateFailure = { | ||||
|         const failureData: ICertificateFailure = { | ||||
|           domain, | ||||
|           error: error.message || String(error), | ||||
|           isRenewal: !!error.isRenewal | ||||
| @@ -171,7 +171,7 @@ export class ChallengeResponder extends plugins.EventEmitter { | ||||
|    * @param domain Domain name to request a certificate for | ||||
|    * @param isRenewal Whether this is a renewal request | ||||
|    */ | ||||
|   public async requestCertificate(domain: string, isRenewal: boolean = false): Promise<CertificateData> { | ||||
|   public async requestCertificate(domain: string, isRenewal: boolean = false): Promise<ICertificateData> { | ||||
|     if (!this.smartAcme) { | ||||
|       throw new Error('ACME client not initialized'); | ||||
|     } | ||||
| @@ -181,7 +181,7 @@ export class ChallengeResponder extends plugins.EventEmitter { | ||||
|       const certObj = await this.smartAcme.getCertificateForDomain(domain); | ||||
|        | ||||
|       // Convert the certificate object to our CertificateData format | ||||
|       const certData: CertificateData = { | ||||
|       const certData: ICertificateData = { | ||||
|         domain, | ||||
|         certificate: certObj.publicKey, | ||||
|         privateKey: certObj.privateKey, | ||||
| @@ -193,7 +193,7 @@ export class ChallengeResponder extends plugins.EventEmitter { | ||||
|       return certData; | ||||
|     } catch (error) { | ||||
|       // Create failure object | ||||
|       const failure: CertificateFailure = { | ||||
|       const failure: ICertificateFailure = { | ||||
|         domain, | ||||
|         error: error instanceof Error ? error.message : String(error), | ||||
|         isRenewal | ||||
| @@ -217,7 +217,7 @@ export class ChallengeResponder extends plugins.EventEmitter { | ||||
|    */ | ||||
|   public checkCertificateExpiry( | ||||
|     domain: string, | ||||
|     certificate: CertificateData, | ||||
|     certificate: ICertificateData, | ||||
|     thresholdDays: number = 30 | ||||
|   ): void { | ||||
|     if (!certificate.expiryDate) return; | ||||
| @@ -227,7 +227,7 @@ export class ChallengeResponder extends plugins.EventEmitter { | ||||
|     const daysDifference = Math.floor((expiryDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); | ||||
|      | ||||
|     if (daysDifference <= thresholdDays) { | ||||
|       const expiryInfo: CertificateExpiring = { | ||||
|       const expiryInfo: ICertificateExpiring = { | ||||
|         domain, | ||||
|         expiryDate, | ||||
|         daysRemaining: daysDifference | ||||
|   | ||||
| @@ -2,12 +2,12 @@ import * as plugins from '../../plugins.js'; | ||||
| import { IncomingMessage, ServerResponse } from 'http'; | ||||
| import { CertificateEvents } from '../../certificate/events/certificate-events.js'; | ||||
| import type { | ||||
|   ForwardConfig, | ||||
|   DomainOptions, | ||||
|   CertificateData, | ||||
|   CertificateFailure, | ||||
|   CertificateExpiring, | ||||
|   AcmeOptions | ||||
|   IForwardConfig, | ||||
|   IDomainOptions, | ||||
|   ICertificateData, | ||||
|   ICertificateFailure, | ||||
|   ICertificateExpiring, | ||||
|   IAcmeOptions | ||||
| } from '../../certificate/models/certificate-types.js'; | ||||
| import { | ||||
|   HttpEvents, | ||||
| @@ -16,7 +16,7 @@ import { | ||||
|   CertificateError, | ||||
|   ServerError, | ||||
| } from '../models/http-types.js'; | ||||
| import type { DomainCertificate } from '../models/http-types.js'; | ||||
| import type { IDomainCertificate } from '../models/http-types.js'; | ||||
| import { ChallengeResponder } from './challenge-responder.js'; | ||||
|  | ||||
| // Re-export for backward compatibility | ||||
| @@ -40,21 +40,21 @@ export const Port80HandlerEvents = CertificateEvents; | ||||
|  * Now with glob pattern support for domain matching | ||||
|  */ | ||||
| export class Port80Handler extends plugins.EventEmitter { | ||||
|   private domainCertificates: Map<string, DomainCertificate>; | ||||
|   private domainCertificates: Map<string, IDomainCertificate>; | ||||
|   private challengeResponder: ChallengeResponder | null = null; | ||||
|   private server: plugins.http.Server | null = null; | ||||
|  | ||||
|   // Renewal scheduling is handled externally by SmartProxy | ||||
|   private isShuttingDown: boolean = false; | ||||
|   private options: Required<AcmeOptions>; | ||||
|   private options: Required<IAcmeOptions>; | ||||
|  | ||||
|   /** | ||||
|    * Creates a new Port80Handler | ||||
|    * @param options Configuration options | ||||
|    */ | ||||
|   constructor(options: AcmeOptions = {}) { | ||||
|   constructor(options: IAcmeOptions = {}) { | ||||
|     super(); | ||||
|     this.domainCertificates = new Map<string, DomainCertificate>(); | ||||
|     this.domainCertificates = new Map<string, IDomainCertificate>(); | ||||
|  | ||||
|     // Default options | ||||
|     this.options = { | ||||
| @@ -80,19 +80,19 @@ export class Port80Handler extends plugins.EventEmitter { | ||||
|       ); | ||||
|  | ||||
|       // Forward certificate events from the challenge responder | ||||
|       this.challengeResponder.on(CertificateEvents.CERTIFICATE_ISSUED, (data: CertificateData) => { | ||||
|       this.challengeResponder.on(CertificateEvents.CERTIFICATE_ISSUED, (data: ICertificateData) => { | ||||
|         this.emit(CertificateEvents.CERTIFICATE_ISSUED, data); | ||||
|       }); | ||||
|  | ||||
|       this.challengeResponder.on(CertificateEvents.CERTIFICATE_RENEWED, (data: CertificateData) => { | ||||
|       this.challengeResponder.on(CertificateEvents.CERTIFICATE_RENEWED, (data: ICertificateData) => { | ||||
|         this.emit(CertificateEvents.CERTIFICATE_RENEWED, data); | ||||
|       }); | ||||
|  | ||||
|       this.challengeResponder.on(CertificateEvents.CERTIFICATE_FAILED, (error: CertificateFailure) => { | ||||
|       this.challengeResponder.on(CertificateEvents.CERTIFICATE_FAILED, (error: ICertificateFailure) => { | ||||
|         this.emit(CertificateEvents.CERTIFICATE_FAILED, error); | ||||
|       }); | ||||
|  | ||||
|       this.challengeResponder.on(CertificateEvents.CERTIFICATE_EXPIRING, (expiry: CertificateExpiring) => { | ||||
|       this.challengeResponder.on(CertificateEvents.CERTIFICATE_EXPIRING, (expiry: ICertificateExpiring) => { | ||||
|         this.emit(CertificateEvents.CERTIFICATE_EXPIRING, expiry); | ||||
|       }); | ||||
|     } | ||||
| @@ -198,7 +198,7 @@ export class Port80Handler extends plugins.EventEmitter { | ||||
|    * Adds a domain with configuration options | ||||
|    * @param options Domain configuration options | ||||
|    */ | ||||
|   public addDomain(options: DomainOptions): void { | ||||
|   public addDomain(options: IDomainOptions): void { | ||||
|     if (!options.domainName || typeof options.domainName !== 'string') { | ||||
|       throw new HttpError('Invalid domain name'); | ||||
|     } | ||||
| @@ -247,7 +247,7 @@ export class Port80Handler extends plugins.EventEmitter { | ||||
|    * Gets the certificate for a domain if it exists | ||||
|    * @param domain The domain to get the certificate for | ||||
|    */ | ||||
|   public getCertificate(domain: string): CertificateData | null { | ||||
|   public getCertificate(domain: string): ICertificateData | null { | ||||
|     // Can't get certificates for glob patterns | ||||
|     if (this.isGlobPattern(domain)) { | ||||
|       return null; | ||||
| @@ -283,7 +283,7 @@ export class Port80Handler extends plugins.EventEmitter { | ||||
|    * @param requestDomain The actual domain from the request | ||||
|    * @returns The domain info or null if not found | ||||
|    */ | ||||
|   private getDomainInfoForRequest(requestDomain: string): { domainInfo: DomainCertificate, pattern: string } | null { | ||||
|   private getDomainInfoForRequest(requestDomain: string): { domainInfo: IDomainCertificate, pattern: string } | null { | ||||
|     // Try direct match first | ||||
|     if (this.domainCertificates.has(requestDomain)) { | ||||
|       return { | ||||
| @@ -459,7 +459,7 @@ export class Port80Handler extends plugins.EventEmitter { | ||||
|   private forwardRequest( | ||||
|     req: plugins.http.IncomingMessage, | ||||
|     res: plugins.http.ServerResponse, | ||||
|     target: ForwardConfig, | ||||
|     target: IForwardConfig, | ||||
|     requestType: string | ||||
|   ): void { | ||||
|     const options = { | ||||
| @@ -612,7 +612,7 @@ export class Port80Handler extends plugins.EventEmitter { | ||||
|    * @param eventType The event type to emit | ||||
|    * @param data The certificate data | ||||
|    */ | ||||
|   private emitCertificateEvent(eventType: CertificateEvents, data: CertificateData): void { | ||||
|   private emitCertificateEvent(eventType: CertificateEvents, data: ICertificateData): void { | ||||
|     this.emit(eventType, data); | ||||
|   } | ||||
|    | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import type { ReverseProxyConfig } from '../../proxies/network-proxy/models/types.js'; | ||||
| import type { IReverseProxyConfig } from '../../proxies/network-proxy/models/types.js'; | ||||
|  | ||||
| /** | ||||
|  * Optional path pattern configuration that can be added to proxy configs | ||||
| @@ -15,7 +15,7 @@ export type IPathPatternConfig = PathPatternConfig; | ||||
|  * Interface for router result with additional metadata | ||||
|  */ | ||||
| export interface RouterResult { | ||||
|   config: ReverseProxyConfig; | ||||
|   config: IReverseProxyConfig; | ||||
|   pathMatch?: string; | ||||
|   pathParams?: Record<string, string>; | ||||
|   pathRemainder?: string; | ||||
| @@ -41,11 +41,11 @@ export type IRouterResult = RouterResult; | ||||
|  */ | ||||
| export class ProxyRouter { | ||||
|   // Store original configs for reference | ||||
|   private reverseProxyConfigs: ReverseProxyConfig[] = []; | ||||
|   private reverseProxyConfigs: IReverseProxyConfig[] = []; | ||||
|   // Default config to use when no match is found (optional) | ||||
|   private defaultConfig?: ReverseProxyConfig; | ||||
|   private defaultConfig?: IReverseProxyConfig; | ||||
|   // Store path patterns separately since they're not in the original interface | ||||
|   private pathPatterns: Map<ReverseProxyConfig, string> = new Map(); | ||||
|   private pathPatterns: Map<IReverseProxyConfig, string> = new Map(); | ||||
|   // Logger interface | ||||
|   private logger: { | ||||
|     error: (message: string, data?: any) => void; | ||||
| @@ -55,7 +55,7 @@ export class ProxyRouter { | ||||
|   }; | ||||
|  | ||||
|   constructor( | ||||
|     configs?: ReverseProxyConfig[], | ||||
|     configs?: IReverseProxyConfig[], | ||||
|     logger?: { | ||||
|       error: (message: string, data?: any) => void; | ||||
|       warn: (message: string, data?: any) => void; | ||||
| @@ -73,7 +73,7 @@ export class ProxyRouter { | ||||
|    * Sets a new set of reverse configs to be routed to | ||||
|    * @param reverseCandidatesArg Array of reverse proxy configurations | ||||
|    */ | ||||
|   public setNewProxyConfigs(reverseCandidatesArg: ReverseProxyConfig[]): void { | ||||
|   public setNewProxyConfigs(reverseCandidatesArg: IReverseProxyConfig[]): void { | ||||
|     this.reverseProxyConfigs = [...reverseCandidatesArg]; | ||||
|  | ||||
|     // Find default config if any (config with "*" as hostname) | ||||
| @@ -87,7 +87,7 @@ export class ProxyRouter { | ||||
|    * @param req The incoming HTTP request | ||||
|    * @returns The matching proxy config or undefined if no match found | ||||
|    */ | ||||
|   public routeReq(req: plugins.http.IncomingMessage): ReverseProxyConfig { | ||||
|   public routeReq(req: plugins.http.IncomingMessage): IReverseProxyConfig { | ||||
|     const result = this.routeReqWithDetails(req); | ||||
|     return result ? result.config : undefined; | ||||
|   } | ||||
| @@ -356,7 +356,7 @@ export class ProxyRouter { | ||||
|    * Gets all currently active proxy configurations | ||||
|    * @returns Array of all active configurations | ||||
|    */ | ||||
|   public getProxyConfigs(): ReverseProxyConfig[] { | ||||
|   public getProxyConfigs(): IReverseProxyConfig[] { | ||||
|     return [...this.reverseProxyConfigs]; | ||||
|   } | ||||
|    | ||||
| @@ -380,7 +380,7 @@ export class ProxyRouter { | ||||
|    * @param pathPattern Optional path pattern for route matching | ||||
|    */ | ||||
|   public addProxyConfig( | ||||
|     config: ReverseProxyConfig, | ||||
|     config: IReverseProxyConfig, | ||||
|     pathPattern?: string | ||||
|   ): void { | ||||
|     this.reverseProxyConfigs.push(config); | ||||
| @@ -398,7 +398,7 @@ export class ProxyRouter { | ||||
|    * @returns Boolean indicating if the config was found and updated | ||||
|    */ | ||||
|   public setPathPattern( | ||||
|     config: ReverseProxyConfig, | ||||
|     config: IReverseProxyConfig, | ||||
|     pathPattern: string | ||||
|   ): boolean { | ||||
|     const exists = this.reverseProxyConfigs.includes(config); | ||||
|   | ||||
| @@ -2,26 +2,26 @@ import * as plugins from '../../plugins.js'; | ||||
| import * as fs from 'fs'; | ||||
| import * as path from 'path'; | ||||
| import { fileURLToPath } from 'url'; | ||||
| import { type NetworkProxyOptions, type CertificateEntry, type Logger, createLogger } from './models/types.js'; | ||||
| import { type INetworkProxyOptions, type ICertificateEntry, type ILogger, createLogger } from './models/types.js'; | ||||
| import { Port80Handler } from '../../http/port80/port80-handler.js'; | ||||
| import { CertificateEvents } from '../../certificate/events/certificate-events.js'; | ||||
| import { buildPort80Handler } from '../../certificate/acme/acme-factory.js'; | ||||
| import { subscribeToPort80Handler } from '../../core/utils/event-utils.js'; | ||||
| import type { DomainOptions } from '../../certificate/models/certificate-types.js'; | ||||
| import type { IDomainOptions } from '../../certificate/models/certificate-types.js'; | ||||
|  | ||||
| /** | ||||
|  * Manages SSL certificates for NetworkProxy including ACME integration | ||||
|  */ | ||||
| export class CertificateManager { | ||||
|   private defaultCertificates: { key: string; cert: string }; | ||||
|   private certificateCache: Map<string, CertificateEntry> = new Map(); | ||||
|   private certificateCache: Map<string, ICertificateEntry> = new Map(); | ||||
|   private port80Handler: Port80Handler | null = null; | ||||
|   private externalPort80Handler: boolean = false; | ||||
|   private certificateStoreDir: string; | ||||
|   private logger: Logger; | ||||
|   private logger: ILogger; | ||||
|   private httpsServer: plugins.https.Server | null = null; | ||||
|  | ||||
|   constructor(private options: NetworkProxyOptions) { | ||||
|   constructor(private options: INetworkProxyOptions) { | ||||
|     this.certificateStoreDir = path.resolve(options.acme?.certificateStore || './certs'); | ||||
|     this.logger = createLogger(options.logLevel || 'info'); | ||||
|      | ||||
| @@ -219,9 +219,9 @@ export class CertificateManager { | ||||
|        | ||||
|       if (!certData) { | ||||
|         this.logger.info(`No certificate found for ${domain}, registering for issuance`); | ||||
|          | ||||
|  | ||||
|         // Register with new domain options format | ||||
|         const domainOptions: DomainOptions = { | ||||
|         const domainOptions: IDomainOptions = { | ||||
|           domainName: domain, | ||||
|           sslRedirect: true, | ||||
|           acmeMaintenance: true | ||||
| @@ -274,7 +274,7 @@ export class CertificateManager { | ||||
|   /** | ||||
|    * Gets a certificate for a domain | ||||
|    */ | ||||
|   public getCertificate(domain: string): CertificateEntry | undefined { | ||||
|   public getCertificate(domain: string): ICertificateEntry | undefined { | ||||
|     return this.certificateCache.get(domain); | ||||
|   } | ||||
|    | ||||
| @@ -300,7 +300,7 @@ export class CertificateManager { | ||||
|      | ||||
|     try { | ||||
|       // Use the new domain options format | ||||
|       const domainOptions: DomainOptions = { | ||||
|       const domainOptions: IDomainOptions = { | ||||
|         domainName: domain, | ||||
|         sslRedirect: true, | ||||
|         acmeMaintenance: true | ||||
| @@ -341,7 +341,7 @@ export class CertificateManager { | ||||
|       } | ||||
|        | ||||
|       // Register the domain for certificate issuance with new domain options format | ||||
|       const domainOptions: DomainOptions = { | ||||
|       const domainOptions: IDomainOptions = { | ||||
|         domainName: domain, | ||||
|         sslRedirect: true, | ||||
|         acmeMaintenance: true | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import { type NetworkProxyOptions, type ConnectionEntry, type Logger, createLogger } from './models/types.js'; | ||||
| import { type INetworkProxyOptions, type IConnectionEntry, type ILogger, createLogger } from './models/types.js'; | ||||
|  | ||||
| /** | ||||
|  * Manages a pool of backend connections for efficient reuse | ||||
|  */ | ||||
| export class ConnectionPool { | ||||
|   private connectionPool: Map<string, Array<ConnectionEntry>> = new Map(); | ||||
|   private connectionPool: Map<string, Array<IConnectionEntry>> = new Map(); | ||||
|   private roundRobinPositions: Map<string, number> = new Map(); | ||||
|   private logger: Logger; | ||||
|   private logger: ILogger; | ||||
|  | ||||
|   constructor(private options: NetworkProxyOptions) { | ||||
|   constructor(private options: INetworkProxyOptions) { | ||||
|     this.logger = createLogger(options.logLevel || 'info'); | ||||
|   } | ||||
|    | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| import * as plugins from '../../../plugins.js'; | ||||
| import type { AcmeOptions } from '../../../certificate/models/certificate-types.js'; | ||||
| import type { IAcmeOptions } from '../../../certificate/models/certificate-types.js'; | ||||
|  | ||||
| /** | ||||
|  * Configuration options for NetworkProxy | ||||
|  */ | ||||
| export interface NetworkProxyOptions { | ||||
| export interface INetworkProxyOptions { | ||||
|   port: number; | ||||
|   maxConnections?: number; | ||||
|   keepAliveTimeout?: number; | ||||
| @@ -16,22 +16,22 @@ export interface NetworkProxyOptions { | ||||
|     allowHeaders?: string; | ||||
|     maxAge?: number; | ||||
|   }; | ||||
|    | ||||
|  | ||||
|   // Settings for SmartProxy integration | ||||
|   connectionPoolSize?: number; // Maximum connections to maintain in the pool to each backend | ||||
|   portProxyIntegration?: boolean; // Flag to indicate this proxy is used by SmartProxy | ||||
|   useExternalPort80Handler?: boolean; // Flag to indicate using external Port80Handler | ||||
|   // Protocol to use when proxying to backends: HTTP/1.x or HTTP/2 | ||||
|   backendProtocol?: 'http1' | 'http2'; | ||||
|    | ||||
|  | ||||
|   // ACME certificate management options | ||||
|   acme?: AcmeOptions; | ||||
|   acme?: IAcmeOptions; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Interface for a certificate entry in the cache | ||||
|  */ | ||||
| export interface CertificateEntry { | ||||
| export interface ICertificateEntry { | ||||
|   key: string; | ||||
|   cert: string; | ||||
|   expires?: Date; | ||||
| @@ -40,7 +40,7 @@ export interface CertificateEntry { | ||||
| /** | ||||
|  * Interface for reverse proxy configuration | ||||
|  */ | ||||
| export interface ReverseProxyConfig { | ||||
| export interface IReverseProxyConfig { | ||||
|   destinationIps: string[]; | ||||
|   destinationPorts: number[]; | ||||
|   hostName: string; | ||||
| @@ -62,7 +62,7 @@ export interface ReverseProxyConfig { | ||||
| /** | ||||
|  * Interface for connection tracking in the pool | ||||
|  */ | ||||
| export interface ConnectionEntry { | ||||
| export interface IConnectionEntry { | ||||
|   socket: plugins.net.Socket; | ||||
|   lastUsed: number; | ||||
|   isIdle: boolean; | ||||
| @@ -71,7 +71,7 @@ export interface ConnectionEntry { | ||||
| /** | ||||
|  * WebSocket with heartbeat interface | ||||
|  */ | ||||
| export interface WebSocketWithHeartbeat extends plugins.wsDefault { | ||||
| export interface IWebSocketWithHeartbeat extends plugins.wsDefault { | ||||
|   lastPong: number; | ||||
|   isAlive: boolean; | ||||
| } | ||||
| @@ -79,7 +79,7 @@ export interface WebSocketWithHeartbeat extends plugins.wsDefault { | ||||
| /** | ||||
|  * Logger interface for consistent logging across components | ||||
|  */ | ||||
| export interface Logger { | ||||
| export interface ILogger { | ||||
|   debug(message: string, data?: any): void; | ||||
|   info(message: string, data?: any): void; | ||||
|   warn(message: string, data?: any): void; | ||||
| @@ -89,14 +89,14 @@ export interface Logger { | ||||
| /** | ||||
|  * Creates a logger based on the specified log level | ||||
|  */ | ||||
| export function createLogger(logLevel: string = 'info'): Logger { | ||||
| export function createLogger(logLevel: string = 'info'): ILogger { | ||||
|   const logLevels = { | ||||
|     error: 0, | ||||
|     warn: 1, | ||||
|     info: 2, | ||||
|     debug: 3 | ||||
|   }; | ||||
|    | ||||
|  | ||||
|   return { | ||||
|     debug: (message: string, data?: any) => { | ||||
|       if (logLevels[logLevel] >= logLevels.debug) { | ||||
| @@ -119,12 +119,4 @@ export function createLogger(logLevel: string = 'info'): Logger { | ||||
|       } | ||||
|     } | ||||
|   }; | ||||
| } | ||||
|  | ||||
| // Backward compatibility interfaces | ||||
| export interface INetworkProxyOptions extends NetworkProxyOptions {} | ||||
| export interface ICertificateEntry extends CertificateEntry {} | ||||
| export interface IReverseProxyConfig extends ReverseProxyConfig {} | ||||
| export interface IConnectionEntry extends ConnectionEntry {} | ||||
| export interface IWebSocketWithHeartbeat extends WebSocketWithHeartbeat {} | ||||
| export interface ILogger extends Logger {} | ||||
| } | ||||
| @@ -3,9 +3,9 @@ import { | ||||
|   createLogger | ||||
| } from './models/types.js'; | ||||
| import type { | ||||
|   NetworkProxyOptions, | ||||
|   Logger, | ||||
|   ReverseProxyConfig | ||||
|   INetworkProxyOptions, | ||||
|   ILogger, | ||||
|   IReverseProxyConfig | ||||
| } from './models/types.js'; | ||||
| import { CertificateManager } from './certificate-manager.js'; | ||||
| import { ConnectionPool } from './connection-pool.js'; | ||||
| @@ -24,8 +24,8 @@ export class NetworkProxy implements IMetricsTracker { | ||||
|     return {}; | ||||
|   } | ||||
|   // Configuration | ||||
|   public options: NetworkProxyOptions; | ||||
|   public proxyConfigs: ReverseProxyConfig[] = []; | ||||
|   public options: INetworkProxyOptions; | ||||
|   public proxyConfigs: IReverseProxyConfig[] = []; | ||||
|    | ||||
|   // Server instances (HTTP/2 with HTTP/1 fallback) | ||||
|   public httpsServer: any; | ||||
| @@ -54,12 +54,12 @@ export class NetworkProxy implements IMetricsTracker { | ||||
|   private connectionPoolCleanupInterval: NodeJS.Timeout; | ||||
|    | ||||
|   // Logger | ||||
|   private logger: Logger; | ||||
|   private logger: ILogger; | ||||
|  | ||||
|   /** | ||||
|    * Creates a new NetworkProxy instance | ||||
|    */ | ||||
|   constructor(optionsArg: NetworkProxyOptions) { | ||||
|   constructor(optionsArg: INetworkProxyOptions) { | ||||
|     // Set default options | ||||
|     this.options = { | ||||
|       port: optionsArg.port, | ||||
| @@ -328,7 +328,7 @@ export class NetworkProxy implements IMetricsTracker { | ||||
|    * Updates proxy configurations | ||||
|    */ | ||||
|   public async updateProxyConfigs( | ||||
|     proxyConfigsArg: ReverseProxyConfig[] | ||||
|     proxyConfigsArg: IReverseProxyConfig[] | ||||
|   ): Promise<void> { | ||||
|     this.logger.info(`Updating proxy configurations (${proxyConfigsArg.length} configs)`); | ||||
|      | ||||
| @@ -385,8 +385,8 @@ export class NetworkProxy implements IMetricsTracker { | ||||
|       allowedIPs?: string[]; | ||||
|     }>, | ||||
|     sslKeyPair?: { key: string; cert: string } | ||||
|   ): ReverseProxyConfig[] { | ||||
|     const proxyConfigs: ReverseProxyConfig[] = []; | ||||
|   ): IReverseProxyConfig[] { | ||||
|     const proxyConfigs: IReverseProxyConfig[] = []; | ||||
|      | ||||
|     // Use default certificates if not provided | ||||
|     const defaultCerts = this.certificateManager.getDefaultCertificates(); | ||||
| @@ -478,7 +478,7 @@ export class NetworkProxy implements IMetricsTracker { | ||||
|   /** | ||||
|    * Gets all proxy configurations currently in use | ||||
|    */ | ||||
|   public getProxyConfigs(): ReverseProxyConfig[] { | ||||
|   public getProxyConfigs(): IReverseProxyConfig[] { | ||||
|     return [...this.proxyConfigs]; | ||||
|   } | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import { type NetworkProxyOptions, type Logger, createLogger, type ReverseProxyConfig } from './models/types.js'; | ||||
| import { type INetworkProxyOptions, type ILogger, createLogger, type IReverseProxyConfig } from './models/types.js'; | ||||
| import { ConnectionPool } from './connection-pool.js'; | ||||
| import { ProxyRouter } from '../../http/router/index.js'; | ||||
|  | ||||
| @@ -19,13 +19,13 @@ export type MetricsTracker = IMetricsTracker; | ||||
|  */ | ||||
| export class RequestHandler { | ||||
|   private defaultHeaders: { [key: string]: string } = {}; | ||||
|   private logger: Logger; | ||||
|   private logger: ILogger; | ||||
|   private metricsTracker: IMetricsTracker | null = null; | ||||
|   // HTTP/2 client sessions for backend proxying | ||||
|   private h2Sessions: Map<string, plugins.http2.ClientHttp2Session> = new Map(); | ||||
|  | ||||
|   constructor( | ||||
|     private options: NetworkProxyOptions, | ||||
|     private options: INetworkProxyOptions, | ||||
|     private connectionPool: ConnectionPool, | ||||
|     private router: ProxyRouter | ||||
|   ) { | ||||
| @@ -137,7 +137,7 @@ export class RequestHandler { | ||||
|     this.applyDefaultHeaders(res); | ||||
|      | ||||
|     // Determine routing configuration | ||||
|     let proxyConfig: ReverseProxyConfig | undefined; | ||||
|     let proxyConfig: IReverseProxyConfig | undefined; | ||||
|     try { | ||||
|       proxyConfig = this.router.routeReq(req); | ||||
|     } catch (err) { | ||||
| @@ -235,7 +235,7 @@ export class RequestHandler { | ||||
|       // Remove host header to avoid issues with virtual hosts on target server | ||||
|       // The host header should match the target server's expected hostname | ||||
|       if (options.headers && options.headers.host) { | ||||
|         if ((proxyConfig as ReverseProxyConfig).rewriteHostHeader) { | ||||
|         if ((proxyConfig as IReverseProxyConfig).rewriteHostHeader) { | ||||
|           options.headers.host = `${destination.host}:${destination.port}`; | ||||
|         } | ||||
|       } | ||||
| @@ -426,7 +426,7 @@ export class RequestHandler { | ||||
|           outboundHeaders[key] = value; | ||||
|         } | ||||
|       } | ||||
|       if (outboundHeaders.host && (proxyConfig as any).rewriteHostHeader) { | ||||
|       if (outboundHeaders.host && (proxyConfig as IReverseProxyConfig).rewriteHostHeader) { | ||||
|         outboundHeaders.host = `${destination.host}:${destination.port}`; | ||||
|       } | ||||
|       // Create HTTP/1 proxy request | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import { type NetworkProxyOptions, type WebSocketWithHeartbeat, type Logger, createLogger, type ReverseProxyConfig } from './models/types.js'; | ||||
| import { type INetworkProxyOptions, type IWebSocketWithHeartbeat, type ILogger, createLogger, type IReverseProxyConfig } from './models/types.js'; | ||||
| import { ConnectionPool } from './connection-pool.js'; | ||||
| import { ProxyRouter } from '../../http/router/index.js'; | ||||
|  | ||||
| @@ -9,10 +9,10 @@ import { ProxyRouter } from '../../http/router/index.js'; | ||||
| export class WebSocketHandler { | ||||
|   private heartbeatInterval: NodeJS.Timeout | null = null; | ||||
|   private wsServer: plugins.ws.WebSocketServer | null = null; | ||||
|   private logger: Logger; | ||||
|   private logger: ILogger; | ||||
|  | ||||
|   constructor( | ||||
|     private options: NetworkProxyOptions, | ||||
|     private options: INetworkProxyOptions, | ||||
|     private connectionPool: ConnectionPool, | ||||
|     private router: ProxyRouter | ||||
|   ) { | ||||
| @@ -30,7 +30,7 @@ export class WebSocketHandler { | ||||
|     }); | ||||
|  | ||||
|     // Handle WebSocket connections | ||||
|     this.wsServer.on('connection', (wsIncoming: WebSocketWithHeartbeat, req: plugins.http.IncomingMessage) => { | ||||
|     this.wsServer.on('connection', (wsIncoming: IWebSocketWithHeartbeat, req: plugins.http.IncomingMessage) => { | ||||
|       this.handleWebSocketConnection(wsIncoming, req); | ||||
|     }); | ||||
|      | ||||
| @@ -56,9 +56,9 @@ export class WebSocketHandler { | ||||
|       } | ||||
|        | ||||
|       this.logger.debug(`WebSocket heartbeat check for ${this.wsServer.clients.size} clients`); | ||||
|        | ||||
|  | ||||
|       this.wsServer.clients.forEach((ws: plugins.wsDefault) => { | ||||
|         const wsWithHeartbeat = ws as WebSocketWithHeartbeat; | ||||
|         const wsWithHeartbeat = ws as IWebSocketWithHeartbeat; | ||||
|          | ||||
|         if (wsWithHeartbeat.isAlive === false) { | ||||
|           this.logger.debug('Terminating inactive WebSocket connection'); | ||||
| @@ -79,7 +79,7 @@ export class WebSocketHandler { | ||||
|   /** | ||||
|    * Handle a new WebSocket connection | ||||
|    */ | ||||
|   private handleWebSocketConnection(wsIncoming: WebSocketWithHeartbeat, req: plugins.http.IncomingMessage): void { | ||||
|   private handleWebSocketConnection(wsIncoming: IWebSocketWithHeartbeat, req: plugins.http.IncomingMessage): void { | ||||
|     try { | ||||
|       // Initialize heartbeat tracking | ||||
|       wsIncoming.isAlive = true; | ||||
| @@ -127,7 +127,7 @@ export class WebSocketHandler { | ||||
|       } | ||||
|        | ||||
|       // Override host header if needed | ||||
|       if ((proxyConfig as ReverseProxyConfig).rewriteHostHeader) { | ||||
|       if ((proxyConfig as IReverseProxyConfig).rewriteHostHeader) { | ||||
|         headers['host'] = `${destination.host}:${destination.port}`; | ||||
|       } | ||||
|        | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import type { | ||||
|   ConnectionRecord, | ||||
|   DomainConfig, | ||||
|   SmartProxyOptions, | ||||
|   IConnectionRecord, | ||||
|   IDomainConfig, | ||||
|   ISmartProxyOptions, | ||||
| } from './models/interfaces.js'; | ||||
| import { ConnectionManager } from './connection-manager.js'; | ||||
| import { SecurityManager } from './security-manager.js'; | ||||
| @@ -12,14 +12,14 @@ import { NetworkProxyBridge } from './network-proxy-bridge.js'; | ||||
| import { TimeoutManager } from './timeout-manager.js'; | ||||
| import { PortRangeManager } from './port-range-manager.js'; | ||||
| import type { ForwardingHandler } from '../../forwarding/handlers/base-handler.js'; | ||||
| import type { ForwardingType } from '../../forwarding/config/forwarding-types.js'; | ||||
| import type { TForwardingType } from '../../forwarding/config/forwarding-types.js'; | ||||
|  | ||||
| /** | ||||
|  * Handles new connection processing and setup logic | ||||
|  */ | ||||
| export class ConnectionHandler { | ||||
|   constructor( | ||||
|     private settings: SmartProxyOptions, | ||||
|     private settings: ISmartProxyOptions, | ||||
|     private connectionManager: ConnectionManager, | ||||
|     private securityManager: SecurityManager, | ||||
|     private domainConfigManager: DomainConfigManager, | ||||
| @@ -102,7 +102,7 @@ export class ConnectionHandler { | ||||
|    */ | ||||
|   private handleNetworkProxyConnection( | ||||
|     socket: plugins.net.Socket, | ||||
|     record: ConnectionRecord | ||||
|     record: IConnectionRecord | ||||
|   ): void { | ||||
|     const connectionId = record.id; | ||||
|     let initialDataReceived = false; | ||||
| @@ -307,7 +307,7 @@ export class ConnectionHandler { | ||||
|   /** | ||||
|    * Handle a standard (non-NetworkProxy) connection | ||||
|    */ | ||||
|   private handleStandardConnection(socket: plugins.net.Socket, record: ConnectionRecord): void { | ||||
|   private handleStandardConnection(socket: plugins.net.Socket, record: IConnectionRecord): void { | ||||
|     const connectionId = record.id; | ||||
|     const localPort = record.localPort; | ||||
|  | ||||
| @@ -382,7 +382,7 @@ export class ConnectionHandler { | ||||
|     const setupConnection = ( | ||||
|       serverName: string, | ||||
|       initialChunk?: Buffer, | ||||
|       forcedDomain?: DomainConfig, | ||||
|       forcedDomain?: IDomainConfig, | ||||
|       overridePort?: number | ||||
|     ) => { | ||||
|       // Clear the initial timeout since we've received data | ||||
| @@ -500,7 +500,7 @@ export class ConnectionHandler { | ||||
|         const globalDomainConfig = { | ||||
|           domains: ['global'], | ||||
|           forwarding: { | ||||
|             type: 'http-only' as ForwardingType, | ||||
|             type: 'http-only' as TForwardingType, | ||||
|             target: { | ||||
|               host: this.settings.targetIP!, | ||||
|               port: this.settings.toPort | ||||
| @@ -730,8 +730,8 @@ export class ConnectionHandler { | ||||
|    */ | ||||
|   private setupDirectConnection( | ||||
|     socket: plugins.net.Socket, | ||||
|     record: ConnectionRecord, | ||||
|     domainConfig?: DomainConfig, | ||||
|     record: IConnectionRecord, | ||||
|     domainConfig?: IDomainConfig, | ||||
|     serverName?: string, | ||||
|     initialChunk?: Buffer, | ||||
|     overridePort?: number | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import type { ConnectionRecord, SmartProxyOptions } from './models/interfaces.js'; | ||||
| import type { IConnectionRecord, ISmartProxyOptions } from './models/interfaces.js'; | ||||
| import { SecurityManager } from './security-manager.js'; | ||||
| import { TimeoutManager } from './timeout-manager.js'; | ||||
|  | ||||
| @@ -7,14 +7,14 @@ import { TimeoutManager } from './timeout-manager.js'; | ||||
|  * Manages connection lifecycle, tracking, and cleanup | ||||
|  */ | ||||
| export class ConnectionManager { | ||||
|   private connectionRecords: Map<string, ConnectionRecord> = new Map(); | ||||
|   private connectionRecords: Map<string, IConnectionRecord> = new Map(); | ||||
|   private terminationStats: { | ||||
|     incoming: Record<string, number>; | ||||
|     outgoing: Record<string, number>; | ||||
|   } = { incoming: {}, outgoing: {} }; | ||||
|  | ||||
|   constructor( | ||||
|     private settings: SmartProxyOptions, | ||||
|     private settings: ISmartProxyOptions, | ||||
|     private securityManager: SecurityManager, | ||||
|     private timeoutManager: TimeoutManager | ||||
|   ) {} | ||||
| @@ -30,12 +30,12 @@ export class ConnectionManager { | ||||
|   /** | ||||
|    * Create and track a new connection | ||||
|    */ | ||||
|   public createConnection(socket: plugins.net.Socket): ConnectionRecord { | ||||
|   public createConnection(socket: plugins.net.Socket): IConnectionRecord { | ||||
|     const connectionId = this.generateConnectionId(); | ||||
|     const remoteIP = socket.remoteAddress || ''; | ||||
|     const localPort = socket.localPort || 0; | ||||
|  | ||||
|     const record: ConnectionRecord = { | ||||
|     const record: IConnectionRecord = { | ||||
|       id: connectionId, | ||||
|       incoming: socket, | ||||
|       outgoing: null, | ||||
| @@ -66,7 +66,7 @@ export class ConnectionManager { | ||||
|   /** | ||||
|    * Track an existing connection | ||||
|    */ | ||||
|   public trackConnection(connectionId: string, record: ConnectionRecord): void { | ||||
|   public trackConnection(connectionId: string, record: IConnectionRecord): void { | ||||
|     this.connectionRecords.set(connectionId, record); | ||||
|     this.securityManager.trackConnectionByIP(record.remoteIP, connectionId); | ||||
|   } | ||||
| @@ -74,14 +74,14 @@ export class ConnectionManager { | ||||
|   /** | ||||
|    * Get a connection by ID | ||||
|    */ | ||||
|   public getConnection(connectionId: string): ConnectionRecord | undefined { | ||||
|   public getConnection(connectionId: string): IConnectionRecord | undefined { | ||||
|     return this.connectionRecords.get(connectionId); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get all active connections | ||||
|    */ | ||||
|   public getConnections(): Map<string, ConnectionRecord> { | ||||
|   public getConnections(): Map<string, IConnectionRecord> { | ||||
|     return this.connectionRecords; | ||||
|   } | ||||
|    | ||||
| @@ -95,7 +95,7 @@ export class ConnectionManager { | ||||
|   /** | ||||
|    * Initiates cleanup once for a connection | ||||
|    */ | ||||
|   public initiateCleanupOnce(record: ConnectionRecord, reason: string = 'normal'): void { | ||||
|   public initiateCleanupOnce(record: IConnectionRecord, reason: string = 'normal'): void { | ||||
|     if (this.settings.enableDetailedLogging) { | ||||
|       console.log(`[${record.id}] Connection cleanup initiated for ${record.remoteIP} (${reason})`); | ||||
|     } | ||||
| @@ -110,11 +110,11 @@ export class ConnectionManager { | ||||
|  | ||||
|     this.cleanupConnection(record, reason); | ||||
|   } | ||||
|    | ||||
|  | ||||
|   /** | ||||
|    * Clean up a connection record | ||||
|    */ | ||||
|   public cleanupConnection(record: ConnectionRecord, reason: string = 'normal'): void { | ||||
|   public cleanupConnection(record: IConnectionRecord, reason: string = 'normal'): void { | ||||
|     if (!record.connectionClosed) { | ||||
|       record.connectionClosed = true; | ||||
|  | ||||
| @@ -178,7 +178,7 @@ export class ConnectionManager { | ||||
|   /** | ||||
|    * Helper method to clean up a socket | ||||
|    */ | ||||
|   private cleanupSocket(record: ConnectionRecord, side: 'incoming' | 'outgoing', socket: plugins.net.Socket): void { | ||||
|   private cleanupSocket(record: IConnectionRecord, side: 'incoming' | 'outgoing', socket: plugins.net.Socket): void { | ||||
|     try { | ||||
|       if (!socket.destroyed) { | ||||
|         // Try graceful shutdown first, then force destroy after a short timeout | ||||
| @@ -213,7 +213,7 @@ export class ConnectionManager { | ||||
|   /** | ||||
|    * Creates a generic error handler for incoming or outgoing sockets | ||||
|    */ | ||||
|   public handleError(side: 'incoming' | 'outgoing', record: ConnectionRecord) { | ||||
|   public handleError(side: 'incoming' | 'outgoing', record: IConnectionRecord) { | ||||
|     return (err: Error) => { | ||||
|       const code = (err as any).code; | ||||
|       let reason = 'error'; | ||||
| @@ -256,7 +256,7 @@ export class ConnectionManager { | ||||
|   /** | ||||
|    * Creates a generic close handler for incoming or outgoing sockets | ||||
|    */ | ||||
|   public handleClose(side: 'incoming' | 'outgoing', record: ConnectionRecord) { | ||||
|   public handleClose(side: 'incoming' | 'outgoing', record: IConnectionRecord) { | ||||
|     return () => { | ||||
|       if (this.settings.enableDetailedLogging) { | ||||
|         console.log(`[${record.id}] Connection closed on ${side} side from ${record.remoteIP}`); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import type { DomainConfig, SmartProxyOptions } from './models/interfaces.js'; | ||||
| import type { ForwardingType, ForwardConfig } from '../../forwarding/config/forwarding-types.js'; | ||||
| import type { IDomainConfig, ISmartProxyOptions } from './models/interfaces.js'; | ||||
| import type { TForwardingType, IForwardConfig } from '../../forwarding/config/forwarding-types.js'; | ||||
| import type { ForwardingHandler } from '../../forwarding/handlers/base-handler.js'; | ||||
| import { ForwardingHandlerFactory } from '../../forwarding/factory/forwarding-factory.js'; | ||||
|  | ||||
| @@ -9,17 +9,17 @@ import { ForwardingHandlerFactory } from '../../forwarding/factory/forwarding-fa | ||||
|  */ | ||||
| export class DomainConfigManager { | ||||
|   // Track round-robin indices for domain configs | ||||
|   private domainTargetIndices: Map<DomainConfig, number> = new Map(); | ||||
|   private domainTargetIndices: Map<IDomainConfig, number> = new Map(); | ||||
|  | ||||
|   // Cache forwarding handlers for each domain config | ||||
|   private forwardingHandlers: Map<DomainConfig, ForwardingHandler> = new Map(); | ||||
|   private forwardingHandlers: Map<IDomainConfig, ForwardingHandler> = new Map(); | ||||
|  | ||||
|   constructor(private settings: SmartProxyOptions) {} | ||||
|   constructor(private settings: ISmartProxyOptions) {} | ||||
|    | ||||
|   /** | ||||
|    * Updates the domain configurations | ||||
|    */ | ||||
|   public updateDomainConfigs(newDomainConfigs: DomainConfig[]): void { | ||||
|   public updateDomainConfigs(newDomainConfigs: IDomainConfig[]): void { | ||||
|     this.settings.domainConfigs = newDomainConfigs; | ||||
|  | ||||
|     // Reset target indices for removed configs | ||||
| @@ -31,7 +31,7 @@ export class DomainConfigManager { | ||||
|     } | ||||
|  | ||||
|     // Clear handlers for removed configs and create handlers for new configs | ||||
|     const handlersToRemove: DomainConfig[] = []; | ||||
|     const handlersToRemove: IDomainConfig[] = []; | ||||
|     for (const [config] of this.forwardingHandlers) { | ||||
|       if (!currentConfigSet.has(config)) { | ||||
|         handlersToRemove.push(config); | ||||
| @@ -55,29 +55,29 @@ export class DomainConfigManager { | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|    | ||||
|  | ||||
|   /** | ||||
|    * Get all domain configurations | ||||
|    */ | ||||
|   public getDomainConfigs(): DomainConfig[] { | ||||
|   public getDomainConfigs(): IDomainConfig[] { | ||||
|     return this.settings.domainConfigs; | ||||
|   } | ||||
|    | ||||
|  | ||||
|   /** | ||||
|    * Find domain config matching a server name | ||||
|    */ | ||||
|   public findDomainConfig(serverName: string): DomainConfig | undefined { | ||||
|   public findDomainConfig(serverName: string): IDomainConfig | undefined { | ||||
|     if (!serverName) return undefined; | ||||
|      | ||||
|  | ||||
|     return this.settings.domainConfigs.find((config) => | ||||
|       config.domains.some((d) => plugins.minimatch(serverName, d)) | ||||
|     ); | ||||
|   } | ||||
|    | ||||
|  | ||||
|   /** | ||||
|    * Find domain config for a specific port | ||||
|    */ | ||||
|   public findDomainConfigForPort(port: number): DomainConfig | undefined { | ||||
|   public findDomainConfigForPort(port: number): IDomainConfig | undefined { | ||||
|     return this.settings.domainConfigs.find( | ||||
|       (domain) => { | ||||
|         const portRanges = domain.forwarding?.advanced?.portRanges; | ||||
| @@ -98,7 +98,7 @@ export class DomainConfigManager { | ||||
|   /** | ||||
|    * Get target IP with round-robin support | ||||
|    */ | ||||
|   public getTargetIP(domainConfig: DomainConfig): string { | ||||
|   public getTargetIP(domainConfig: IDomainConfig): string { | ||||
|     const targetHosts = Array.isArray(domainConfig.forwarding.target.host) | ||||
|       ? domainConfig.forwarding.target.host | ||||
|       : [domainConfig.forwarding.target.host]; | ||||
| @@ -117,21 +117,21 @@ export class DomainConfigManager { | ||||
|    * Get target host with round-robin support (for tests) | ||||
|    * This is just an alias for getTargetIP for easier test compatibility | ||||
|    */ | ||||
|   public getTargetHost(domainConfig: DomainConfig): string { | ||||
|   public getTargetHost(domainConfig: IDomainConfig): string { | ||||
|     return this.getTargetIP(domainConfig); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Get target port from domain config | ||||
|    */ | ||||
|   public getTargetPort(domainConfig: DomainConfig, defaultPort: number): number { | ||||
|   public getTargetPort(domainConfig: IDomainConfig, defaultPort: number): number { | ||||
|     return domainConfig.forwarding.target.port || defaultPort; | ||||
|   } | ||||
|    | ||||
|  | ||||
|   /** | ||||
|    * Checks if a domain should use NetworkProxy | ||||
|    */ | ||||
|   public shouldUseNetworkProxy(domainConfig: DomainConfig): boolean { | ||||
|   public shouldUseNetworkProxy(domainConfig: IDomainConfig): boolean { | ||||
|     const forwardingType = this.getForwardingType(domainConfig); | ||||
|     return forwardingType === 'https-terminate-to-http' || | ||||
|            forwardingType === 'https-terminate-to-https'; | ||||
| @@ -140,7 +140,7 @@ export class DomainConfigManager { | ||||
|   /** | ||||
|    * Gets the NetworkProxy port for a domain | ||||
|    */ | ||||
|   public getNetworkProxyPort(domainConfig: DomainConfig): number | undefined { | ||||
|   public getNetworkProxyPort(domainConfig: IDomainConfig): number | undefined { | ||||
|     // First check if we should use NetworkProxy at all | ||||
|     if (!this.shouldUseNetworkProxy(domainConfig)) { | ||||
|       return undefined; | ||||
| @@ -148,14 +148,14 @@ export class DomainConfigManager { | ||||
|  | ||||
|     return domainConfig.forwarding.advanced?.networkProxyPort || this.settings.networkProxyPort; | ||||
|   } | ||||
|    | ||||
|  | ||||
|   /** | ||||
|    * Get effective allowed and blocked IPs for a domain | ||||
|    * | ||||
|    * This method combines domain-specific security rules from the forwarding configuration | ||||
|    * with global security defaults when necessary. | ||||
|    */ | ||||
|   public getEffectiveIPRules(domainConfig: DomainConfig): { | ||||
|   public getEffectiveIPRules(domainConfig: IDomainConfig): { | ||||
|     allowedIPs: string[], | ||||
|     blockedIPs: string[] | ||||
|   } { | ||||
| @@ -201,7 +201,7 @@ export class DomainConfigManager { | ||||
|   /** | ||||
|    * Get connection timeout for a domain | ||||
|    */ | ||||
|   public getConnectionTimeout(domainConfig?: DomainConfig): number { | ||||
|   public getConnectionTimeout(domainConfig?: IDomainConfig): number { | ||||
|     if (domainConfig?.forwarding.advanced?.timeout) { | ||||
|       return domainConfig.forwarding.advanced.timeout; | ||||
|     } | ||||
| @@ -212,7 +212,7 @@ export class DomainConfigManager { | ||||
|   /** | ||||
|    * Creates a forwarding handler for a domain configuration | ||||
|    */ | ||||
|   private createForwardingHandler(domainConfig: DomainConfig): ForwardingHandler { | ||||
|   private createForwardingHandler(domainConfig: IDomainConfig): ForwardingHandler { | ||||
|     // Create a new handler using the factory | ||||
|     const handler = ForwardingHandlerFactory.createHandler(domainConfig.forwarding); | ||||
|  | ||||
| @@ -228,7 +228,7 @@ export class DomainConfigManager { | ||||
|    * Gets a forwarding handler for a domain config | ||||
|    * If no handler exists, creates one | ||||
|    */ | ||||
|   public getForwardingHandler(domainConfig: DomainConfig): ForwardingHandler { | ||||
|   public getForwardingHandler(domainConfig: IDomainConfig): ForwardingHandler { | ||||
|     // If we already have a handler, return it | ||||
|     if (this.forwardingHandlers.has(domainConfig)) { | ||||
|       return this.forwardingHandlers.get(domainConfig)!; | ||||
| @@ -244,7 +244,7 @@ export class DomainConfigManager { | ||||
|   /** | ||||
|    * Gets the forwarding type for a domain config | ||||
|    */ | ||||
|   public getForwardingType(domainConfig?: DomainConfig): ForwardingType | undefined { | ||||
|   public getForwardingType(domainConfig?: IDomainConfig): TForwardingType | undefined { | ||||
|     if (!domainConfig?.forwarding) return undefined; | ||||
|     return domainConfig.forwarding.type; | ||||
|   } | ||||
| @@ -252,7 +252,7 @@ export class DomainConfigManager { | ||||
|   /** | ||||
|    * Checks if the forwarding type requires TLS termination | ||||
|    */ | ||||
|   public requiresTlsTermination(domainConfig?: DomainConfig): boolean { | ||||
|   public requiresTlsTermination(domainConfig?: IDomainConfig): boolean { | ||||
|     if (!domainConfig) return false; | ||||
|  | ||||
|     const forwardingType = this.getForwardingType(domainConfig); | ||||
| @@ -263,7 +263,7 @@ export class DomainConfigManager { | ||||
|   /** | ||||
|    * Checks if the forwarding type supports HTTP | ||||
|    */ | ||||
|   public supportsHttp(domainConfig?: DomainConfig): boolean { | ||||
|   public supportsHttp(domainConfig?: IDomainConfig): boolean { | ||||
|     if (!domainConfig) return false; | ||||
|  | ||||
|     const forwardingType = this.getForwardingType(domainConfig); | ||||
| @@ -285,7 +285,7 @@ export class DomainConfigManager { | ||||
|   /** | ||||
|    * Checks if HTTP requests should be redirected to HTTPS | ||||
|    */ | ||||
|   public shouldRedirectToHttps(domainConfig?: DomainConfig): boolean { | ||||
|   public shouldRedirectToHttps(domainConfig?: IDomainConfig): boolean { | ||||
|     if (!domainConfig?.forwarding) return false; | ||||
|  | ||||
|     // Only check for redirect if HTTP is enabled | ||||
|   | ||||
| @@ -1,28 +1,28 @@ | ||||
| import * as plugins from '../../../plugins.js'; | ||||
| import type { ForwardConfig } from '../../../forwarding/config/forwarding-types.js'; | ||||
| import type { IForwardConfig } from '../../../forwarding/config/forwarding-types.js'; | ||||
|  | ||||
| /** | ||||
|  * Provision object for static or HTTP-01 certificate | ||||
|  */ | ||||
| export type SmartProxyCertProvisionObject = plugins.tsclass.network.ICert | 'http01'; | ||||
| export type TSmartProxyCertProvisionObject = plugins.tsclass.network.ICert | 'http01'; | ||||
|  | ||||
| /** | ||||
|  * Domain configuration with forwarding configuration | ||||
|  */ | ||||
| export interface DomainConfig { | ||||
| export interface IDomainConfig { | ||||
|   domains: string[]; // Glob patterns for domain(s) | ||||
|   forwarding: ForwardConfig; // Unified forwarding configuration | ||||
|   forwarding: IForwardConfig; // Unified forwarding configuration | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Configuration options for the SmartProxy | ||||
|  */ | ||||
| import type { AcmeOptions } from '../../../certificate/models/certificate-types.js'; | ||||
| export interface SmartProxyOptions { | ||||
| import type { IAcmeOptions } from '../../../certificate/models/certificate-types.js'; | ||||
| export interface ISmartProxyOptions { | ||||
|   fromPort: number; | ||||
|   toPort: number; | ||||
|   targetIP?: string; // Global target host to proxy to, defaults to 'localhost' | ||||
|   domainConfigs: DomainConfig[]; | ||||
|   domainConfigs: IDomainConfig[]; | ||||
|   sniEnabled?: boolean; | ||||
|   defaultAllowedIPs?: string[]; | ||||
|   defaultBlockedIPs?: string[]; | ||||
| @@ -81,19 +81,19 @@ export interface SmartProxyOptions { | ||||
|   networkProxyPort?: number; // Port where NetworkProxy is listening (default: 8443) | ||||
|  | ||||
|   // ACME configuration options for SmartProxy | ||||
|   acme?: AcmeOptions; | ||||
|    | ||||
|   acme?: IAcmeOptions; | ||||
|  | ||||
|   /** | ||||
|    * Optional certificate provider callback. Return 'http01' to use HTTP-01 challenges, | ||||
|    * or a static certificate object for immediate provisioning. | ||||
|    */ | ||||
|   certProvisionFunction?: (domain: string) => Promise<SmartProxyCertProvisionObject>; | ||||
|   certProvisionFunction?: (domain: string) => Promise<TSmartProxyCertProvisionObject>; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Enhanced connection record | ||||
|  */ | ||||
| export interface ConnectionRecord { | ||||
| export interface IConnectionRecord { | ||||
|   id: string; // Unique connection identifier | ||||
|   incoming: plugins.net.Socket; | ||||
|   outgoing: plugins.net.Socket | null; | ||||
| @@ -116,7 +116,7 @@ export interface ConnectionRecord { | ||||
|   isTLS: boolean; // Whether this connection is a TLS connection | ||||
|   tlsHandshakeComplete: boolean; // Whether the TLS handshake is complete | ||||
|   hasReceivedInitialData: boolean; // Whether initial data has been received | ||||
|   domainConfig?: DomainConfig; // Associated domain config for this connection | ||||
|   domainConfig?: IDomainConfig; // Associated domain config for this connection | ||||
|  | ||||
|   // Keep-alive tracking | ||||
|   hasKeepAlive: boolean; // Whether keep-alive is enabled for this connection | ||||
| @@ -133,10 +133,4 @@ export interface ConnectionRecord { | ||||
|   // Browser connection tracking | ||||
|   isBrowserConnection?: boolean; // Whether this connection appears to be from a browser | ||||
|   domainSwitches?: number; // Number of times the domain has been switched on this connection | ||||
| } | ||||
|  | ||||
| // Backward compatibility types | ||||
| export type ISmartProxyCertProvisionObject = SmartProxyCertProvisionObject; | ||||
| export interface IDomainConfig extends DomainConfig {} | ||||
| export interface ISmartProxyOptions extends SmartProxyOptions {} | ||||
| export interface IConnectionRecord extends ConnectionRecord {} | ||||
| } | ||||
| @@ -3,8 +3,8 @@ import { NetworkProxy } from '../network-proxy/index.js'; | ||||
| import { Port80Handler } from '../../http/port80/port80-handler.js'; | ||||
| import { Port80HandlerEvents } from '../../core/models/common-types.js'; | ||||
| import { subscribeToPort80Handler } from '../../core/utils/event-utils.js'; | ||||
| import type { CertificateData } from '../../certificate/models/certificate-types.js'; | ||||
| import type { ConnectionRecord, SmartProxyOptions, DomainConfig } from './models/interfaces.js'; | ||||
| import type { ICertificateData } from '../../certificate/models/certificate-types.js'; | ||||
| import type { IConnectionRecord, ISmartProxyOptions, IDomainConfig } from './models/interfaces.js'; | ||||
|  | ||||
| /** | ||||
|  * Manages NetworkProxy integration for TLS termination | ||||
| @@ -13,7 +13,7 @@ export class NetworkProxyBridge { | ||||
|   private networkProxy: NetworkProxy | null = null; | ||||
|   private port80Handler: Port80Handler | null = null; | ||||
|  | ||||
|   constructor(private settings: SmartProxyOptions) {} | ||||
|   constructor(private settings: ISmartProxyOptions) {} | ||||
|    | ||||
|   /** | ||||
|    * Set the Port80Handler to use for certificate management | ||||
| @@ -66,23 +66,23 @@ export class NetworkProxyBridge { | ||||
|   /** | ||||
|    * Handle certificate issuance or renewal events | ||||
|    */ | ||||
|   private handleCertificateEvent(data: CertificateData): void { | ||||
|   private handleCertificateEvent(data: ICertificateData): void { | ||||
|     if (!this.networkProxy) return; | ||||
|      | ||||
|  | ||||
|     console.log(`Received certificate for ${data.domain} from Port80Handler, updating NetworkProxy`); | ||||
|      | ||||
|  | ||||
|     try { | ||||
|       // Find existing config for this domain | ||||
|       const existingConfigs = this.networkProxy.getProxyConfigs() | ||||
|         .filter(config => config.hostName === data.domain); | ||||
|        | ||||
|  | ||||
|       if (existingConfigs.length > 0) { | ||||
|         // Update existing configs with new certificate | ||||
|         for (const config of existingConfigs) { | ||||
|           config.privateKey = data.privateKey; | ||||
|           config.publicKey = data.certificate; | ||||
|         } | ||||
|          | ||||
|  | ||||
|         // Apply updated configs | ||||
|         this.networkProxy.updateProxyConfigs(existingConfigs) | ||||
|           .then(() => console.log(`Updated certificate for ${data.domain} in NetworkProxy`)) | ||||
| @@ -95,11 +95,11 @@ export class NetworkProxyBridge { | ||||
|       console.log(`Error handling certificate event: ${err}`); | ||||
|     } | ||||
|   } | ||||
|    | ||||
|  | ||||
|   /** | ||||
|    * Apply an external (static) certificate into NetworkProxy | ||||
|    */ | ||||
|   public applyExternalCertificate(data: CertificateData): void { | ||||
|   public applyExternalCertificate(data: ICertificateData): void { | ||||
|     if (!this.networkProxy) { | ||||
|       console.log(`NetworkProxy not initialized: cannot apply external certificate for ${data.domain}`); | ||||
|       return; | ||||
| @@ -183,7 +183,7 @@ export class NetworkProxyBridge { | ||||
|   public forwardToNetworkProxy( | ||||
|     connectionId: string, | ||||
|     socket: plugins.net.Socket, | ||||
|     record: ConnectionRecord, | ||||
|     record: IConnectionRecord, | ||||
|     initialData: Buffer, | ||||
|     customProxyPort?: number, | ||||
|     onError?: (reason: string) => void | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| import type { SmartProxyOptions } from './models/interfaces.js'; | ||||
| import type { ISmartProxyOptions } from './models/interfaces.js'; | ||||
|  | ||||
| /** | ||||
|  * Manages port ranges and port-based configuration | ||||
|  */ | ||||
| export class PortRangeManager { | ||||
|   constructor(private settings: SmartProxyOptions) {} | ||||
|   constructor(private settings: ISmartProxyOptions) {} | ||||
|    | ||||
|   /** | ||||
|    * Get all ports that should be listened on | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import type { SmartProxyOptions } from './models/interfaces.js'; | ||||
| import type { ISmartProxyOptions } from './models/interfaces.js'; | ||||
|  | ||||
| /** | ||||
|  * Handles security aspects like IP tracking, rate limiting, and authorization | ||||
| @@ -8,7 +8,7 @@ export class SecurityManager { | ||||
|   private connectionsByIP: Map<string, Set<string>> = new Map(); | ||||
|   private connectionRateByIP: Map<string, number[]> = new Map(); | ||||
|  | ||||
|   constructor(private settings: SmartProxyOptions) {} | ||||
|   constructor(private settings: ISmartProxyOptions) {} | ||||
|    | ||||
|   /** | ||||
|    * Get connections count by IP | ||||
|   | ||||
| @@ -13,15 +13,15 @@ import { ConnectionHandler } from './connection-handler.js'; | ||||
| // External dependencies from migrated modules | ||||
| import { Port80Handler } from '../../http/port80/port80-handler.js'; | ||||
| import { CertProvisioner } from '../../certificate/providers/cert-provisioner.js'; | ||||
| import type { CertificateData } from '../../certificate/models/certificate-types.js'; | ||||
| import type { ICertificateData } from '../../certificate/models/certificate-types.js'; | ||||
| import { buildPort80Handler } from '../../certificate/acme/acme-factory.js'; | ||||
| import type { ForwardingType } from '../../forwarding/config/forwarding-types.js'; | ||||
| import type { TForwardingType } from '../../forwarding/config/forwarding-types.js'; | ||||
| import { createPort80HandlerOptions } from '../../common/port80-adapter.js'; | ||||
|  | ||||
| // Import types from models | ||||
| import type { SmartProxyOptions, DomainConfig } from './models/interfaces.js'; | ||||
| import type { ISmartProxyOptions, IDomainConfig } from './models/interfaces.js'; | ||||
| // Provide backward compatibility types | ||||
| export type { SmartProxyOptions as IPortProxySettings, DomainConfig as IDomainConfig }; | ||||
| export type { ISmartProxyOptions as IPortProxySettings, IDomainConfig }; | ||||
|  | ||||
| /** | ||||
|  * SmartProxy - Main class that coordinates all components | ||||
| @@ -46,7 +46,7 @@ export class SmartProxy extends plugins.EventEmitter { | ||||
|   // CertProvisioner for unified certificate workflows | ||||
|   private certProvisioner?: CertProvisioner; | ||||
|    | ||||
|   constructor(settingsArg: SmartProxyOptions) { | ||||
|   constructor(settingsArg: ISmartProxyOptions) { | ||||
|     super(); | ||||
|     // Set reasonable defaults for all settings | ||||
|     this.settings = { | ||||
| @@ -63,12 +63,12 @@ export class SmartProxy extends plugins.EventEmitter { | ||||
|       keepAliveInitialDelay: settingsArg.keepAliveInitialDelay || 10000, | ||||
|       maxPendingDataSize: settingsArg.maxPendingDataSize || 10 * 1024 * 1024, | ||||
|       disableInactivityCheck: settingsArg.disableInactivityCheck || false, | ||||
|       enableKeepAliveProbes:  | ||||
|       enableKeepAliveProbes: | ||||
|         settingsArg.enableKeepAliveProbes !== undefined ? settingsArg.enableKeepAliveProbes : true, | ||||
|       enableDetailedLogging: settingsArg.enableDetailedLogging || false, | ||||
|       enableTlsDebugLogging: settingsArg.enableTlsDebugLogging || false, | ||||
|       enableRandomizedTimeouts: settingsArg.enableRandomizedTimeouts || false, | ||||
|       allowSessionTicket:  | ||||
|       allowSessionTicket: | ||||
|         settingsArg.allowSessionTicket !== undefined ? settingsArg.allowSessionTicket : true, | ||||
|       maxConnectionsPerIP: settingsArg.maxConnectionsPerIP || 100, | ||||
|       connectionRateLimitPerMinute: settingsArg.connectionRateLimitPerMinute || 300, | ||||
| @@ -126,7 +126,7 @@ export class SmartProxy extends plugins.EventEmitter { | ||||
|   /** | ||||
|    * The settings for the port proxy | ||||
|    */ | ||||
|   public settings: SmartProxyOptions; | ||||
|   public settings: ISmartProxyOptions; | ||||
|    | ||||
|   /** | ||||
|    * Initialize the Port80Handler for ACME certificate management | ||||
| @@ -413,7 +413,7 @@ export class SmartProxy extends plugins.EventEmitter { | ||||
|   /** | ||||
|    * Updates the domain configurations for the proxy | ||||
|    */ | ||||
|   public async updateDomainConfigs(newDomainConfigs: DomainConfig[]): Promise<void> { | ||||
|   public async updateDomainConfigs(newDomainConfigs: IDomainConfig[]): Promise<void> { | ||||
|     console.log(`Updating domain configurations (${newDomainConfigs.length} configs)`); | ||||
|  | ||||
|     // Update domain configs in DomainConfigManager | ||||
| @@ -475,7 +475,7 @@ export class SmartProxy extends plugins.EventEmitter { | ||||
|           } else { | ||||
|             // Static certificate (e.g., DNS-01 provisioned) supports wildcards | ||||
|             const certObj = provision as plugins.tsclass.network.ICert; | ||||
|             const certData: CertificateData = { | ||||
|             const certData: ICertificateData = { | ||||
|               domain: certObj.domainName, | ||||
|               certificate: certObj.publicKey, | ||||
|               privateKey: certObj.privateKey, | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| import type { ConnectionRecord, SmartProxyOptions } from './models/interfaces.js'; | ||||
| import type { IConnectionRecord, ISmartProxyOptions } from './models/interfaces.js'; | ||||
|  | ||||
| /** | ||||
|  * Manages timeouts and inactivity tracking for connections | ||||
|  */ | ||||
| export class TimeoutManager { | ||||
|   constructor(private settings: SmartProxyOptions) {} | ||||
|   constructor(private settings: ISmartProxyOptions) {} | ||||
|    | ||||
|   /** | ||||
|    * Ensure timeout values don't exceed Node.js max safe integer | ||||
| @@ -28,7 +28,7 @@ export class TimeoutManager { | ||||
|   /** | ||||
|    * Update connection activity timestamp | ||||
|    */ | ||||
|   public updateActivity(record: ConnectionRecord): void { | ||||
|   public updateActivity(record: IConnectionRecord): void { | ||||
|     record.lastActivity = Date.now(); | ||||
|  | ||||
|     // Clear any inactivity warning | ||||
| @@ -36,11 +36,11 @@ export class TimeoutManager { | ||||
|       record.inactivityWarningIssued = false; | ||||
|     } | ||||
|   } | ||||
|    | ||||
|  | ||||
|   /** | ||||
|    * Calculate effective inactivity timeout based on connection type | ||||
|    */ | ||||
|   public getEffectiveInactivityTimeout(record: ConnectionRecord): number { | ||||
|   public getEffectiveInactivityTimeout(record: IConnectionRecord): number { | ||||
|     let effectiveTimeout = this.settings.inactivityTimeout || 14400000; // 4 hours default | ||||
|      | ||||
|     // For immortal keep-alive connections, use an extremely long timeout | ||||
| @@ -60,7 +60,7 @@ export class TimeoutManager { | ||||
|   /** | ||||
|    * Calculate effective max lifetime based on connection type | ||||
|    */ | ||||
|   public getEffectiveMaxLifetime(record: ConnectionRecord): number { | ||||
|   public getEffectiveMaxLifetime(record: IConnectionRecord): number { | ||||
|     // Use domain-specific timeout from forwarding.advanced if available | ||||
|     const baseTimeout = record.domainConfig?.forwarding?.advanced?.timeout || | ||||
|                         this.settings.maxConnectionLifetime || | ||||
| @@ -91,8 +91,8 @@ export class TimeoutManager { | ||||
|    * @returns The cleanup timer | ||||
|    */ | ||||
|   public setupConnectionTimeout( | ||||
|     record: ConnectionRecord, | ||||
|     onTimeout: (record: ConnectionRecord, reason: string) => void | ||||
|     record: IConnectionRecord, | ||||
|     onTimeout: (record: IConnectionRecord, reason: string) => void | ||||
|   ): NodeJS.Timeout { | ||||
|     // Clear any existing timer | ||||
|     if (record.cleanupTimer) { | ||||
| @@ -120,7 +120,7 @@ export class TimeoutManager { | ||||
|    * Check for inactivity on a connection | ||||
|    * @returns Object with check results | ||||
|    */ | ||||
|   public checkInactivity(record: ConnectionRecord): { | ||||
|   public checkInactivity(record: IConnectionRecord): { | ||||
|     isInactive: boolean; | ||||
|     shouldWarn: boolean; | ||||
|     inactivityTime: number; | ||||
| @@ -169,7 +169,7 @@ export class TimeoutManager { | ||||
|   /** | ||||
|    * Apply socket timeout settings | ||||
|    */ | ||||
|   public applySocketTimeouts(record: ConnectionRecord): void { | ||||
|   public applySocketTimeouts(record: IConnectionRecord): void { | ||||
|     // Skip for immortal keep-alive connections | ||||
|     if (record.hasKeepAlive && this.settings.keepAliveTreatment === 'immortal') { | ||||
|       // Disable timeouts completely for immortal connections | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import * as plugins from '../../plugins.js'; | ||||
| import type { SmartProxyOptions } from './models/interfaces.js'; | ||||
| import type { ISmartProxyOptions } from './models/interfaces.js'; | ||||
| import { SniHandler } from '../../tls/sni/sni-handler.js'; | ||||
|  | ||||
| /** | ||||
| @@ -16,7 +16,7 @@ interface IConnectionInfo { | ||||
|  * Manages TLS-related operations including SNI extraction and validation | ||||
|  */ | ||||
| export class TlsManager { | ||||
|   constructor(private settings: SmartProxyOptions) {} | ||||
|   constructor(private settings: ISmartProxyOptions) {} | ||||
|    | ||||
|   /** | ||||
|    * Check if a data chunk appears to be a TLS handshake | ||||
|   | ||||
		Reference in New Issue
	
	Block a user