BREAKING CHANGE(smartproxy): Remove legacy migration utilities and deprecated forwarding helpers; consolidate route utilities, streamline interface definitions, and normalize IPv6-mapped IPv4 addresses
This commit is contained in:
		| @@ -3,6 +3,6 @@ | ||||
|  */ | ||||
| export const commitinfo = { | ||||
|   name: '@push.rocks/smartproxy', | ||||
|   version: '16.0.4', | ||||
|   version: '17.0.0', | ||||
|   description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.' | ||||
| } | ||||
|   | ||||
| @@ -21,9 +21,21 @@ export function convertToLegacyForwardConfig( | ||||
|     ? forwardConfig.target.host[0]  // Use the first host in the array | ||||
|     : forwardConfig.target.host; | ||||
|  | ||||
|   // Extract port number, handling different port formats | ||||
|   let port: number; | ||||
|   if (typeof forwardConfig.target.port === 'function') { | ||||
|     // Use a default port for function-based ports in adapter context | ||||
|     port = 80; | ||||
|   } else if (forwardConfig.target.port === 'preserve') { | ||||
|     // For 'preserve', use the default port 80 in this adapter context | ||||
|     port = 80; | ||||
|   } else { | ||||
|     port = forwardConfig.target.port; | ||||
|   } | ||||
|  | ||||
|   return { | ||||
|     ip: host, | ||||
|     port: forwardConfig.target.port | ||||
|     port: port | ||||
|   }; | ||||
| } | ||||
|  | ||||
| @@ -75,11 +87,23 @@ export function createPort80HandlerOptions( | ||||
|       forwardConfig.type === 'https-terminate-to-https')); | ||||
|    | ||||
|   if (supportsHttp) { | ||||
|     // Determine port value handling different formats | ||||
|     let port: number; | ||||
|     if (typeof forwardConfig.target.port === 'function') { | ||||
|       // Use a default port for function-based ports | ||||
|       port = 80; | ||||
|     } else if (forwardConfig.target.port === 'preserve') { | ||||
|       // For 'preserve', use 80 in this adapter context | ||||
|       port = 80; | ||||
|     } else { | ||||
|       port = forwardConfig.target.port; | ||||
|     } | ||||
|  | ||||
|     options.forward = { | ||||
|       ip: Array.isArray(forwardConfig.target.host)  | ||||
|         ? forwardConfig.target.host[0] | ||||
|         : forwardConfig.target.host, | ||||
|       port: forwardConfig.target.port | ||||
|       port: port | ||||
|     }; | ||||
|   } | ||||
|    | ||||
|   | ||||
| @@ -1,10 +1,8 @@ | ||||
| import type * as plugins from '../../plugins.js'; | ||||
|  | ||||
| /** | ||||
|  * @deprecated The legacy forwarding types are being replaced by the route-based configuration system. | ||||
|  * See /ts/proxies/smart-proxy/models/route-types.ts for the new route-based configuration. | ||||
|  * | ||||
|  * The primary forwarding types supported by SmartProxy | ||||
|  * Used for configuration compatibility | ||||
|  */ | ||||
| export type TForwardingType = | ||||
|   | 'http-only'                // HTTP forwarding only (no HTTPS) | ||||
| @@ -35,7 +33,7 @@ export interface IForwardingHandler extends plugins.EventEmitter { | ||||
|   handleHttpRequest(req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse): void; | ||||
| } | ||||
|  | ||||
| // Import and re-export the route-based helpers for seamless transition | ||||
| // Route-based helpers are now available directly from route-patterns.ts | ||||
| import { | ||||
|   createHttpRoute, | ||||
|   createHttpsTerminateRoute, | ||||
| @@ -43,7 +41,7 @@ import { | ||||
|   createHttpToHttpsRedirect, | ||||
|   createCompleteHttpsServer, | ||||
|   createLoadBalancerRoute | ||||
| } from '../../proxies/smart-proxy/utils/route-helpers.js'; | ||||
| } from '../../proxies/smart-proxy/utils/route-patterns.js'; | ||||
|  | ||||
| export { | ||||
|   createHttpRoute, | ||||
| @@ -54,23 +52,20 @@ export { | ||||
|   createLoadBalancerRoute | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @deprecated These helper functions are maintained for backward compatibility. | ||||
|  * Please use the route-based helpers instead: | ||||
|  * - createHttpRoute | ||||
|  * - createHttpsTerminateRoute | ||||
|  * - createHttpsPassthroughRoute | ||||
|  * - createHttpToHttpsRedirect | ||||
|  */ | ||||
| // Note: Legacy helper functions have been removed | ||||
| // Please use the route-based helpers instead: | ||||
| // - createHttpRoute | ||||
| // - createHttpsTerminateRoute | ||||
| // - createHttpsPassthroughRoute | ||||
| // - createHttpToHttpsRedirect | ||||
| import type { IRouteConfig } from '../../proxies/smart-proxy/models/route-types.js'; | ||||
| import { domainConfigToRouteConfig } from '../../proxies/smart-proxy/utils/route-migration-utils.js'; | ||||
|  | ||||
| // For backward compatibility | ||||
| // For backward compatibility, kept only the basic configuration interface | ||||
| export interface IForwardConfig { | ||||
|   type: TForwardingType; | ||||
|   target: { | ||||
|     host: string | string[]; | ||||
|     port: number; | ||||
|     port: number | 'preserve' | ((ctx: any) => number); | ||||
|   }; | ||||
|   http?: any; | ||||
|   https?: any; | ||||
| @@ -78,57 +73,4 @@ export interface IForwardConfig { | ||||
|   security?: any; | ||||
|   advanced?: any; | ||||
|   [key: string]: any; | ||||
| } | ||||
|  | ||||
| export interface IDeprecatedForwardConfig { | ||||
|   type: TForwardingType; | ||||
|   target: { | ||||
|     host: string | string[]; | ||||
|     port: number; | ||||
|   }; | ||||
|   [key: string]: any; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @deprecated Use createHttpRoute instead | ||||
|  */ | ||||
| export const httpOnly = ( | ||||
|   partialConfig: Partial<IDeprecatedForwardConfig> & Pick<IDeprecatedForwardConfig, 'target'> | ||||
| ): IDeprecatedForwardConfig => ({ | ||||
|   type: 'http-only', | ||||
|   target: partialConfig.target, | ||||
|   ...(partialConfig) | ||||
| }); | ||||
|  | ||||
| /** | ||||
|  * @deprecated Use createHttpsTerminateRoute instead | ||||
|  */ | ||||
| export const tlsTerminateToHttp = ( | ||||
|   partialConfig: Partial<IDeprecatedForwardConfig> & Pick<IDeprecatedForwardConfig, 'target'> | ||||
| ): IDeprecatedForwardConfig => ({ | ||||
|   type: 'https-terminate-to-http', | ||||
|   target: partialConfig.target, | ||||
|   ...(partialConfig) | ||||
| }); | ||||
|  | ||||
| /** | ||||
|  * @deprecated Use createHttpsTerminateRoute with reencrypt option instead | ||||
|  */ | ||||
| export const tlsTerminateToHttps = ( | ||||
|   partialConfig: Partial<IDeprecatedForwardConfig> & Pick<IDeprecatedForwardConfig, 'target'> | ||||
| ): IDeprecatedForwardConfig => ({ | ||||
|   type: 'https-terminate-to-https', | ||||
|   target: partialConfig.target, | ||||
|   ...(partialConfig) | ||||
| }); | ||||
|  | ||||
| /** | ||||
|  * @deprecated Use createHttpsPassthroughRoute instead | ||||
|  */ | ||||
| export const httpsPassthrough = ( | ||||
|   partialConfig: Partial<IDeprecatedForwardConfig> & Pick<IDeprecatedForwardConfig, 'target'> | ||||
| ): IDeprecatedForwardConfig => ({ | ||||
|   type: 'https-passthrough', | ||||
|   target: partialConfig.target, | ||||
|   ...(partialConfig) | ||||
| }); | ||||
| } | ||||
| @@ -5,5 +5,22 @@ | ||||
|  * See /ts/proxies/smart-proxy/models/route-types.ts for the new route-based configuration. | ||||
|  */ | ||||
|  | ||||
| export * from './forwarding-types.js'; | ||||
| export * from '../../proxies/smart-proxy/utils/route-helpers.js'; | ||||
| export type {  | ||||
|   TForwardingType, | ||||
|   IForwardConfig, | ||||
|   IForwardingHandler | ||||
| } from './forwarding-types.js'; | ||||
|  | ||||
| export {  | ||||
|   ForwardingHandlerEvents | ||||
| } from './forwarding-types.js'; | ||||
|  | ||||
| // Import route helpers from route-patterns instead of deleted route-helpers | ||||
| export { | ||||
|   createHttpRoute, | ||||
|   createHttpsTerminateRoute, | ||||
|   createHttpsPassthroughRoute, | ||||
|   createHttpToHttpsRedirect, | ||||
|   createCompleteHttpsServer, | ||||
|   createLoadBalancerRoute | ||||
| } from '../../proxies/smart-proxy/utils/route-patterns.js'; | ||||
| @@ -122,8 +122,13 @@ export class ForwardingHandlerFactory { | ||||
|       throw new Error('Target must include a host or array of hosts'); | ||||
|     } | ||||
|      | ||||
|     if (!config.target.port || config.target.port <= 0 || config.target.port > 65535) { | ||||
|       throw new Error('Target must include a valid port (1-65535)'); | ||||
|     // Validate port if it's a number | ||||
|     if (typeof config.target.port === 'number') { | ||||
|       if (config.target.port <= 0 || config.target.port > 65535) { | ||||
|         throw new Error('Target must include a valid port (1-65535)'); | ||||
|       } | ||||
|     } else if (config.target.port !== 'preserve' && typeof config.target.port !== 'function') { | ||||
|       throw new Error('Target port must be a number, "preserve", or a function'); | ||||
|     } | ||||
|      | ||||
|     // Type-specific validation | ||||
|   | ||||
| @@ -55,17 +55,37 @@ export abstract class ForwardingHandler extends plugins.EventEmitter implements | ||||
|       const randomIndex = Math.floor(Math.random() * target.host.length); | ||||
|       return { | ||||
|         host: target.host[randomIndex], | ||||
|         port: target.port | ||||
|         port: this.resolvePort(target.port) | ||||
|       }; | ||||
|     } | ||||
|      | ||||
|     // Single host | ||||
|     return { | ||||
|       host: target.host, | ||||
|       port: target.port | ||||
|       port: this.resolvePort(target.port) | ||||
|     }; | ||||
|   } | ||||
|    | ||||
|   /** | ||||
|    * Resolves a port value, handling 'preserve' and function ports | ||||
|    */ | ||||
|   protected resolvePort(port: number | 'preserve' | ((ctx: any) => number)): number { | ||||
|     if (typeof port === 'function') { | ||||
|       try { | ||||
|         // Create a minimal context for the function | ||||
|         const ctx = { port: 80 }; // Default port for minimal context | ||||
|         return port(ctx); | ||||
|       } catch (err) { | ||||
|         console.error('Error resolving port function:', err); | ||||
|         return 80; // Default fallback port | ||||
|       } | ||||
|     } else if (port === 'preserve') { | ||||
|       return 80; // Default port for 'preserve' in base handler | ||||
|     } else { | ||||
|       return port; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Redirect an HTTP request to HTTPS | ||||
|    * @param req The HTTP request | ||||
|   | ||||
| @@ -3,9 +3,6 @@ | ||||
|  * Provides a flexible and type-safe way to configure and manage various forwarding strategies | ||||
|  */ | ||||
|  | ||||
| // Export types and configuration | ||||
| export * from './config/forwarding-types.js'; | ||||
|  | ||||
| // Export handlers | ||||
| export { ForwardingHandler } from './handlers/base-handler.js'; | ||||
| export * from './handlers/http-handler.js'; | ||||
| @@ -16,20 +13,23 @@ export * from './handlers/https-terminate-to-https-handler.js'; | ||||
| // Export factory | ||||
| export * from './factory/forwarding-factory.js'; | ||||
|  | ||||
| // Helper functions as a convenience object | ||||
| import { | ||||
|   httpOnly, | ||||
|   tlsTerminateToHttp, | ||||
|   tlsTerminateToHttps, | ||||
|   httpsPassthrough | ||||
| // Export types - these include TForwardingType and IForwardConfig | ||||
| export type {  | ||||
|   TForwardingType, | ||||
|   IForwardConfig, | ||||
|   IForwardingHandler | ||||
| } from './config/forwarding-types.js'; | ||||
|  | ||||
| // Export route-based helpers from smart-proxy | ||||
| export * from '../proxies/smart-proxy/utils/route-helpers.js'; | ||||
| export {  | ||||
|   ForwardingHandlerEvents | ||||
| } from './config/forwarding-types.js'; | ||||
|  | ||||
| export const helpers = { | ||||
|   httpOnly, | ||||
|   tlsTerminateToHttp, | ||||
|   tlsTerminateToHttps, | ||||
|   httpsPassthrough | ||||
| }; | ||||
| // Export route helpers directly from route-patterns | ||||
| export { | ||||
|   createHttpRoute, | ||||
|   createHttpsTerminateRoute, | ||||
|   createHttpsPassthroughRoute, | ||||
|   createHttpToHttpsRedirect, | ||||
|   createCompleteHttpsServer, | ||||
|   createLoadBalancerRoute | ||||
| } from '../proxies/smart-proxy/utils/route-patterns.js'; | ||||
| @@ -3,6 +3,3 @@ | ||||
|  */ | ||||
| export * from './interfaces.js'; | ||||
| export * from './route-types.js'; | ||||
|  | ||||
| // Re-export IRoutedSmartProxyOptions explicitly to avoid ambiguity | ||||
| export type { ISmartProxyOptions as IRoutedSmartProxyOptions } from './interfaces.js'; | ||||
|   | ||||
| @@ -8,23 +8,7 @@ import type { TForwardingType } from '../../../forwarding/config/forwarding-type | ||||
|  */ | ||||
| export type TSmartProxyCertProvisionObject = plugins.tsclass.network.ICert | 'http01'; | ||||
|  | ||||
| /** | ||||
|  * Alias for backward compatibility with code that uses IRoutedSmartProxyOptions | ||||
|  */ | ||||
| export type IRoutedSmartProxyOptions = ISmartProxyOptions; | ||||
|  | ||||
| /** | ||||
|  * Helper functions for type checking configuration types | ||||
|  */ | ||||
| export function isLegacyOptions(options: any): boolean { | ||||
|   // Legacy options are no longer supported | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| export function isRoutedOptions(options: any): boolean { | ||||
|   // All configurations are now route-based | ||||
|   return true; | ||||
| } | ||||
| // Legacy options and type checking functions have been removed | ||||
|  | ||||
| /** | ||||
|  * SmartProxy configuration options | ||||
|   | ||||
| @@ -321,61 +321,4 @@ export interface IRouteConfig { | ||||
|   enabled?: boolean;         // Whether the route is active (default: true) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Unified SmartProxy options with routes-based configuration | ||||
|  */ | ||||
| export interface IRoutedSmartProxyOptions { | ||||
|   // The unified configuration array (required) | ||||
|   routes: IRouteConfig[]; | ||||
|  | ||||
|   // Global/default settings | ||||
|   defaults?: { | ||||
|     target?: { | ||||
|       host: string; | ||||
|       port: number; | ||||
|     }; | ||||
|     security?: IRouteSecurity; | ||||
|     tls?: IRouteTls; | ||||
|     // ...other defaults | ||||
|   }; | ||||
|  | ||||
|   // Other global settings remain (acme, etc.) | ||||
|   acme?: IAcmeOptions; | ||||
|  | ||||
|   // Connection timeouts and other global settings | ||||
|   initialDataTimeout?: number; | ||||
|   socketTimeout?: number; | ||||
|   inactivityCheckInterval?: number; | ||||
|   maxConnectionLifetime?: number; | ||||
|   inactivityTimeout?: number; | ||||
|   gracefulShutdownTimeout?: number; | ||||
|  | ||||
|   // Socket optimization settings | ||||
|   noDelay?: boolean; | ||||
|   keepAlive?: boolean; | ||||
|   keepAliveInitialDelay?: number; | ||||
|   maxPendingDataSize?: number; | ||||
|  | ||||
|   // Enhanced features | ||||
|   disableInactivityCheck?: boolean; | ||||
|   enableKeepAliveProbes?: boolean; | ||||
|   enableDetailedLogging?: boolean; | ||||
|   enableTlsDebugLogging?: boolean; | ||||
|   enableRandomizedTimeouts?: boolean; | ||||
|   allowSessionTicket?: boolean; | ||||
|  | ||||
|   // Rate limiting and security | ||||
|   maxConnectionsPerIP?: number; | ||||
|   connectionRateLimitPerMinute?: number; | ||||
|  | ||||
|   // Enhanced keep-alive settings | ||||
|   keepAliveTreatment?: 'standard' | 'extended' | 'immortal'; | ||||
|   keepAliveInactivityMultiplier?: number; | ||||
|   extendedKeepAliveLifetime?: number; | ||||
|  | ||||
|   /** | ||||
|    * Optional certificate provider callback. Return 'http01' to use HTTP-01 challenges, | ||||
|    * or a static certificate object for immediate provisioning. | ||||
|    */ | ||||
|   certProvisionFunction?: (domain: string) => Promise<any>; | ||||
| } | ||||
| // Configuration moved to models/interfaces.ts as ISmartProxyOptions | ||||
| @@ -3,9 +3,7 @@ import type { | ||||
|   IConnectionRecord, | ||||
|   ISmartProxyOptions | ||||
| } from './models/interfaces.js'; | ||||
| import { | ||||
|   isRoutedOptions | ||||
| } from './models/interfaces.js'; | ||||
| // Route checking functions have been removed | ||||
| import type { | ||||
|   IRouteConfig, | ||||
|   IRouteAction, | ||||
| @@ -316,7 +314,6 @@ export class RouteConnectionHandler { | ||||
|         return this.setupDirectConnection( | ||||
|           socket, | ||||
|           record, | ||||
|           undefined, | ||||
|           serverName, | ||||
|           initialChunk, | ||||
|           undefined, | ||||
| @@ -457,7 +454,6 @@ export class RouteConnectionHandler { | ||||
|           return this.setupDirectConnection( | ||||
|             socket, | ||||
|             record, | ||||
|             undefined, | ||||
|             record.lockedDomain, | ||||
|             initialChunk, | ||||
|             undefined, | ||||
| @@ -538,7 +534,6 @@ export class RouteConnectionHandler { | ||||
|       return this.setupDirectConnection( | ||||
|         socket, | ||||
|         record, | ||||
|         undefined, | ||||
|         record.lockedDomain, | ||||
|         initialChunk, | ||||
|         undefined, | ||||
| @@ -656,17 +651,12 @@ export class RouteConnectionHandler { | ||||
|     this.connectionManager.initiateCleanupOnce(record, 'route_blocked'); | ||||
|   } | ||||
|    | ||||
|   /** | ||||
|    * Legacy connection handling has been removed in favor of pure route-based approach | ||||
|    */ | ||||
|    | ||||
|   /** | ||||
|    * Sets up a direct connection to the target | ||||
|    */ | ||||
|   private setupDirectConnection( | ||||
|     socket: plugins.net.Socket, | ||||
|     record: IConnectionRecord, | ||||
|     _unused?: any, // kept for backward compatibility | ||||
|     serverName?: string, | ||||
|     initialChunk?: Buffer, | ||||
|     overridePort?: number, | ||||
|   | ||||
| @@ -6,12 +6,7 @@ import type { | ||||
|   TPortRange | ||||
| } from './models/route-types.js'; | ||||
| import type { | ||||
|   ISmartProxyOptions, | ||||
|   IRoutedSmartProxyOptions | ||||
| } from './models/interfaces.js'; | ||||
| import { | ||||
|   isRoutedOptions, | ||||
|   isLegacyOptions | ||||
|   ISmartProxyOptions | ||||
| } from './models/interfaces.js'; | ||||
|  | ||||
| /** | ||||
| @@ -29,12 +24,12 @@ export interface IRouteMatchResult { | ||||
| export class RouteManager extends plugins.EventEmitter { | ||||
|   private routes: IRouteConfig[] = []; | ||||
|   private portMap: Map<number, IRouteConfig[]> = new Map(); | ||||
|   private options: IRoutedSmartProxyOptions; | ||||
|   private options: ISmartProxyOptions; | ||||
|    | ||||
|   constructor(options: ISmartProxyOptions) { | ||||
|     super(); | ||||
|      | ||||
|     // We no longer support legacy options, always use provided options | ||||
|     // Store options | ||||
|     this.options = options; | ||||
|      | ||||
|     // Initialize routes from either source | ||||
|   | ||||
| @@ -19,10 +19,8 @@ import { createPort80HandlerOptions } from '../../common/port80-adapter.js'; | ||||
|  | ||||
| // Import types and utilities | ||||
| import type { | ||||
|   ISmartProxyOptions, | ||||
|   IRoutedSmartProxyOptions | ||||
|   ISmartProxyOptions | ||||
| } from './models/interfaces.js'; | ||||
| import { isRoutedOptions, isLegacyOptions } from './models/interfaces.js'; | ||||
| import type { IRouteConfig } from './models/route-types.js'; | ||||
|  | ||||
| /** | ||||
| @@ -650,7 +648,7 @@ export class SmartProxy extends plugins.EventEmitter { | ||||
|     const domains: string[] = []; | ||||
|      | ||||
|     // Get domains from routes | ||||
|     const routes = isRoutedOptions(this.settings) ? this.settings.routes : []; | ||||
|     const routes = this.settings.routes || []; | ||||
|      | ||||
|     for (const route of routes) { | ||||
|       if (!route.match.domains) continue; | ||||
|   | ||||
| @@ -5,8 +5,7 @@ | ||||
|  * including helpers, validators, utilities, and patterns for working with routes. | ||||
|  */ | ||||
|  | ||||
| // Export route helpers for creating routes | ||||
| export * from './route-helpers.js'; | ||||
| // Route helpers have been consolidated in route-patterns.js | ||||
|  | ||||
| // Export route validators for validating route configurations | ||||
| export * from './route-validators.js'; | ||||
| @@ -35,6 +34,4 @@ export { | ||||
|   addJwtAuth | ||||
| }; | ||||
|  | ||||
| // Export migration utilities for transitioning from domain-based to route-based configs | ||||
| // Note: These will be removed in a future version once migration is complete | ||||
| export * from './route-migration-utils.js'; | ||||
| // Migration utilities have been removed as they are no longer needed | ||||
| @@ -1,165 +0,0 @@ | ||||
| /** | ||||
|  * Route Migration Utilities | ||||
|  *  | ||||
|  * This file provides utility functions for migrating from legacy domain-based | ||||
|  * configuration to the new route-based configuration system. These functions | ||||
|  * are temporary and will be removed after the migration is complete. | ||||
|  */ | ||||
|  | ||||
| import type { TForwardingType } from '../../../forwarding/config/forwarding-types.js'; | ||||
| import type { IRouteConfig, IRouteMatch, IRouteAction, IRouteTarget } from '../models/route-types.js'; | ||||
|  | ||||
| /** | ||||
|  * Legacy domain config interface (for migration only) | ||||
|  * @deprecated This interface will be removed in a future version | ||||
|  */ | ||||
| export interface ILegacyDomainConfig { | ||||
|   domains: string[]; | ||||
|   forwarding: { | ||||
|     type: TForwardingType; | ||||
|     target: { | ||||
|       host: string | string[]; | ||||
|       port: number; | ||||
|     }; | ||||
|     [key: string]: any; | ||||
|   }; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Convert a legacy domain config to a route-based config | ||||
|  * @param domainConfig Legacy domain configuration | ||||
|  * @param additionalOptions Additional options to add to the route | ||||
|  * @returns Route configuration | ||||
|  * @deprecated This function will be removed in a future version | ||||
|  */ | ||||
| export function domainConfigToRouteConfig( | ||||
|   domainConfig: ILegacyDomainConfig, | ||||
|   additionalOptions: Partial<IRouteConfig> = {} | ||||
| ): IRouteConfig { | ||||
|   // Default port based on forwarding type | ||||
|   let defaultPort = 80; | ||||
|   let tlsMode: 'passthrough' | 'terminate' | 'terminate-and-reencrypt' | undefined; | ||||
|  | ||||
|   switch (domainConfig.forwarding.type) { | ||||
|     case 'http-only': | ||||
|       defaultPort = 80; | ||||
|       break; | ||||
|     case 'https-passthrough': | ||||
|       defaultPort = 443; | ||||
|       tlsMode = 'passthrough'; | ||||
|       break; | ||||
|     case 'https-terminate-to-http': | ||||
|       defaultPort = 443; | ||||
|       tlsMode = 'terminate'; | ||||
|       break; | ||||
|     case 'https-terminate-to-https': | ||||
|       defaultPort = 443; | ||||
|       tlsMode = 'terminate-and-reencrypt'; | ||||
|       break; | ||||
|   } | ||||
|  | ||||
|   // Create route match criteria | ||||
|   const match: IRouteMatch = { | ||||
|     ports: additionalOptions.match?.ports || defaultPort, | ||||
|     domains: domainConfig.domains | ||||
|   }; | ||||
|  | ||||
|   // Create route target | ||||
|   const target: IRouteTarget = { | ||||
|     host: domainConfig.forwarding.target.host, | ||||
|     port: domainConfig.forwarding.target.port | ||||
|   }; | ||||
|  | ||||
|   // Create route action | ||||
|   const action: IRouteAction = { | ||||
|     type: 'forward', | ||||
|     target | ||||
|   }; | ||||
|  | ||||
|   // Add TLS configuration if needed | ||||
|   if (tlsMode) { | ||||
|     action.tls = { | ||||
|       mode: tlsMode, | ||||
|       certificate: 'auto' | ||||
|     }; | ||||
|  | ||||
|     // If the legacy config has custom certificates, use them | ||||
|     if (domainConfig.forwarding.https?.customCert) { | ||||
|       action.tls.certificate = { | ||||
|         key: domainConfig.forwarding.https.customCert.key, | ||||
|         cert: domainConfig.forwarding.https.customCert.cert | ||||
|       }; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Add security options if present | ||||
|   if (domainConfig.forwarding.security) { | ||||
|     action.security = domainConfig.forwarding.security; | ||||
|   } | ||||
|  | ||||
|   // Create the route config | ||||
|   const routeConfig: IRouteConfig = { | ||||
|     match, | ||||
|     action, | ||||
|     // Include a name based on domains if not provided | ||||
|     name: additionalOptions.name || `Legacy route for ${domainConfig.domains.join(', ')}`, | ||||
|     // Include a note that this was converted from a legacy config | ||||
|     description: additionalOptions.description || 'Converted from legacy domain configuration' | ||||
|   }; | ||||
|  | ||||
|   // Add optional properties if provided | ||||
|   if (additionalOptions.priority !== undefined) { | ||||
|     routeConfig.priority = additionalOptions.priority; | ||||
|   } | ||||
|    | ||||
|   if (additionalOptions.tags) { | ||||
|     routeConfig.tags = additionalOptions.tags; | ||||
|   } | ||||
|  | ||||
|   return routeConfig; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Convert an array of legacy domain configs to route configurations | ||||
|  * @param domainConfigs Array of legacy domain configurations | ||||
|  * @returns Array of route configurations | ||||
|  * @deprecated This function will be removed in a future version | ||||
|  */ | ||||
| export function domainConfigsToRouteConfigs( | ||||
|   domainConfigs: ILegacyDomainConfig[] | ||||
| ): IRouteConfig[] { | ||||
|   return domainConfigs.map(config => domainConfigToRouteConfig(config)); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Extract domains from a route configuration | ||||
|  * @param route Route configuration | ||||
|  * @returns Array of domains | ||||
|  */ | ||||
| export function extractDomainsFromRoute(route: IRouteConfig): string[] { | ||||
|   if (!route.match.domains) { | ||||
|     return []; | ||||
|   } | ||||
|    | ||||
|   return Array.isArray(route.match.domains) | ||||
|     ? route.match.domains | ||||
|     : [route.match.domains]; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Extract domains from an array of route configurations | ||||
|  * @param routes Array of route configurations | ||||
|  * @returns Array of unique domains | ||||
|  */ | ||||
| export function extractDomainsFromRoutes(routes: IRouteConfig[]): string[] { | ||||
|   const domains = new Set<string>(); | ||||
|    | ||||
|   for (const route of routes) { | ||||
|     const routeDomains = extractDomainsFromRoute(route); | ||||
|     for (const domain of routeDomains) { | ||||
|       domains.add(domain); | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   return Array.from(domains); | ||||
| } | ||||
| @@ -5,10 +5,154 @@ | ||||
|  * These patterns can be used as templates for creating route configurations. | ||||
|  */ | ||||
|  | ||||
| import type { IRouteConfig } from '../models/route-types.js'; | ||||
| import { createHttpRoute, createHttpsTerminateRoute, createHttpsPassthroughRoute, createCompleteHttpsServer } from './route-helpers.js'; | ||||
| import type { IRouteConfig, IRouteMatch, IRouteAction, IRouteTarget } from '../models/route-types.js'; | ||||
| import { mergeRouteConfigs } from './route-utils.js'; | ||||
|  | ||||
| /** | ||||
|  * Create a basic HTTP route configuration | ||||
|  */ | ||||
| export function createHttpRoute( | ||||
|   domains: string | string[], | ||||
|   target: { host: string | string[]; port: number | 'preserve' | ((ctx: any) => number) }, | ||||
|   options: Partial<IRouteConfig> = {} | ||||
| ): IRouteConfig { | ||||
|   const route: IRouteConfig = { | ||||
|     match: { | ||||
|       domains, | ||||
|       ports: 80 | ||||
|     }, | ||||
|     action: { | ||||
|       type: 'forward', | ||||
|       target: { | ||||
|         host: target.host, | ||||
|         port: target.port | ||||
|       } | ||||
|     }, | ||||
|     name: options.name || `HTTP: ${Array.isArray(domains) ? domains.join(', ') : domains}` | ||||
|   }; | ||||
|  | ||||
|   return mergeRouteConfigs(route, options); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Create an HTTPS route with TLS termination | ||||
|  */ | ||||
| export function createHttpsTerminateRoute( | ||||
|   domains: string | string[], | ||||
|   target: { host: string | string[]; port: number | 'preserve' | ((ctx: any) => number) }, | ||||
|   options: Partial<IRouteConfig> & { | ||||
|     certificate?: 'auto' | { key: string; cert: string }; | ||||
|     reencrypt?: boolean; | ||||
|   } = {} | ||||
| ): IRouteConfig { | ||||
|   const route: IRouteConfig = { | ||||
|     match: { | ||||
|       domains, | ||||
|       ports: 443 | ||||
|     }, | ||||
|     action: { | ||||
|       type: 'forward', | ||||
|       target: { | ||||
|         host: target.host, | ||||
|         port: target.port | ||||
|       }, | ||||
|       tls: { | ||||
|         mode: options.reencrypt ? 'terminate-and-reencrypt' : 'terminate', | ||||
|         certificate: options.certificate || 'auto' | ||||
|       } | ||||
|     }, | ||||
|     name: options.name || `HTTPS (terminate): ${Array.isArray(domains) ? domains.join(', ') : domains}` | ||||
|   }; | ||||
|  | ||||
|   return mergeRouteConfigs(route, options); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Create an HTTPS route with TLS passthrough | ||||
|  */ | ||||
| export function createHttpsPassthroughRoute( | ||||
|   domains: string | string[], | ||||
|   target: { host: string | string[]; port: number | 'preserve' | ((ctx: any) => number) }, | ||||
|   options: Partial<IRouteConfig> = {} | ||||
| ): IRouteConfig { | ||||
|   const route: IRouteConfig = { | ||||
|     match: { | ||||
|       domains, | ||||
|       ports: 443 | ||||
|     }, | ||||
|     action: { | ||||
|       type: 'forward', | ||||
|       target: { | ||||
|         host: target.host, | ||||
|         port: target.port | ||||
|       }, | ||||
|       tls: { | ||||
|         mode: 'passthrough' | ||||
|       } | ||||
|     }, | ||||
|     name: options.name || `HTTPS (passthrough): ${Array.isArray(domains) ? domains.join(', ') : domains}` | ||||
|   }; | ||||
|  | ||||
|   return mergeRouteConfigs(route, options); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Create an HTTP to HTTPS redirect route | ||||
|  */ | ||||
| export function createHttpToHttpsRedirect( | ||||
|   domains: string | string[], | ||||
|   options: Partial<IRouteConfig> & { | ||||
|     redirectCode?: 301 | 302 | 307 | 308; | ||||
|     preservePath?: boolean; | ||||
|   } = {} | ||||
| ): IRouteConfig { | ||||
|   const route: IRouteConfig = { | ||||
|     match: { | ||||
|       domains, | ||||
|       ports: 80 | ||||
|     }, | ||||
|     action: { | ||||
|       type: 'redirect', | ||||
|       redirect: { | ||||
|         to: options.preservePath ? 'https://{domain}{path}' : 'https://{domain}', | ||||
|         status: options.redirectCode || 301 | ||||
|       } | ||||
|     }, | ||||
|     name: options.name || `HTTP to HTTPS redirect: ${Array.isArray(domains) ? domains.join(', ') : domains}` | ||||
|   }; | ||||
|  | ||||
|   return mergeRouteConfigs(route, options); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Create a complete HTTPS server with redirect from HTTP | ||||
|  */ | ||||
| export function createCompleteHttpsServer( | ||||
|   domains: string | string[], | ||||
|   target: { host: string | string[]; port: number | 'preserve' | ((ctx: any) => number) }, | ||||
|   options: Partial<IRouteConfig> & { | ||||
|     certificate?: 'auto' | { key: string; cert: string }; | ||||
|     tlsMode?: 'terminate' | 'passthrough' | 'terminate-and-reencrypt'; | ||||
|     redirectCode?: 301 | 302 | 307 | 308; | ||||
|   } = {} | ||||
| ): IRouteConfig[] { | ||||
|   // Create the TLS route based on the selected mode | ||||
|   const tlsRoute = options.tlsMode === 'passthrough'  | ||||
|     ? createHttpsPassthroughRoute(domains, target, options) | ||||
|     : createHttpsTerminateRoute(domains, target, { | ||||
|         ...options, | ||||
|         reencrypt: options.tlsMode === 'terminate-and-reencrypt' | ||||
|       }); | ||||
|    | ||||
|   // Create the HTTP to HTTPS redirect route | ||||
|   const redirectRoute = createHttpToHttpsRedirect(domains, { | ||||
|     redirectCode: options.redirectCode, | ||||
|     preservePath: true | ||||
|   }); | ||||
|    | ||||
|   return [tlsRoute, redirectRoute]; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Create an API Gateway route pattern | ||||
|  * @param domains Domain(s) to match | ||||
|   | ||||
		Reference in New Issue
	
	Block a user