fix(typescript): Refactor types and interfaces to use consistent I prefix and update related tests

This commit is contained in:
Philipp Kunz 2025-05-09 22:46:53 +00:00
parent d924190680
commit f8647516b5
45 changed files with 403 additions and 392 deletions

View File

@ -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

View File

@ -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',

View File

@ -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: {

View File

@ -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 }

View File

@ -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 }
};

View File

@ -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

View File

@ -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.'
}

View File

@ -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,

View File

@ -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();

View File

@ -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 {

View File

@ -85,3 +85,4 @@ export interface IAcmeOptions {
skipConfiguredCerts?: boolean; // Skip domains with existing certificates
domainForwards?: IDomainForwardConfig[]; // Domain-specific forwarding configs
}

View File

@ -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

View File

@ -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';
/**
@ -24,7 +24,7 @@ export class FileStorage {
* @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);

View File

@ -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');

View File

@ -6,7 +6,7 @@ import type {
} from './types.js';
import type {
ForwardConfig as IForwardConfig
IForwardConfig
} from '../forwarding/config/forwarding-types.js';
/**

View File

@ -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];
@ -26,6 +26,3 @@ export function createDomainConfig(
forwarding
};
}
// Backwards compatibility
export interface IDomainConfig extends DomainConfig {}

View File

@ -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];
}
}

View File

@ -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,7 +40,7 @@ export interface HttpsOptions {
/**
* ACME certificate handling options
*/
export interface AcmeForwardingOptions {
export interface IAcmeForwardingOptions {
enabled?: boolean; // Enable ACME certificate provisioning
maintenance?: boolean; // Auto-renew certificates
production?: boolean; // Use production ACME servers
@ -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 {}

View File

@ -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,7 +14,7 @@ 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':
@ -40,9 +40,9 @@ export class ForwardingHandlerFactory {
* @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');

View File

@ -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();
}

View File

@ -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,7 +11,7 @@ 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
@ -20,6 +20,15 @@ export class HttpForwardingHandler extends ForwardingHandler {
}
}
/**
* 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
* HTTP handler doesn't do much with raw sockets as it mainly processes

View File

@ -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,7 +11,7 @@ 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
@ -20,6 +20,15 @@ export class HttpsPassthroughHandler extends ForwardingHandler {
}
}
/**
* 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
* @param clientSocket The incoming socket from the client

View File

@ -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

View File

@ -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

View File

@ -1,8 +1,8 @@
import * as plugins from '../../plugins.js';
import type {
ForwardConfig,
DomainOptions,
AcmeOptions
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;
@ -103,4 +103,3 @@ export interface RouterConfig {
// Backward compatibility interfaces
export { HttpError as Port80HandlerError };
export { CertificateError as CertError };
export type IDomainCertificate = DomainCertificate;

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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');
@ -221,7 +221,7 @@ export class CertificateManager {
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

View File

@ -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');
}

View File

@ -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;
@ -25,13 +25,13 @@ export interface NetworkProxyOptions {
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,7 +89,7 @@ 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,
@ -120,11 +120,3 @@ 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 {}

View File

@ -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];
}
}

View File

@ -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

View File

@ -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);
});
@ -58,7 +58,7 @@ 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}`;
}

View File

@ -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

View File

@ -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})`);
}
@ -114,7 +114,7 @@ export class ConnectionManager {
/**
* 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}`);

View File

@ -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);
@ -59,14 +59,14 @@ 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) =>
@ -77,7 +77,7 @@ export class DomainConfigManager {
/**
* 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;
@ -155,7 +155,7 @@ export class DomainConfigManager {
* 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

View File

@ -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
@ -134,9 +134,3 @@ export interface ConnectionRecord {
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 {}

View File

@ -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,7 +66,7 @@ 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`);
@ -99,7 +99,7 @@ export class NetworkProxyBridge {
/**
* 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

View File

@ -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

View File

@ -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

View File

@ -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 = {
@ -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,

View File

@ -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
@ -40,7 +40,7 @@ export class TimeoutManager {
/**
* 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

View File

@ -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