@push.rocks/smartproxy 16.0.3 → 17.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/common/port80-adapter.js +29 -3
  3. package/dist_ts/forwarding/config/forwarding-types.d.ts +3 -29
  4. package/dist_ts/forwarding/config/forwarding-types.js +3 -36
  5. package/dist_ts/forwarding/config/index.d.ts +3 -2
  6. package/dist_ts/forwarding/config/index.js +4 -3
  7. package/dist_ts/forwarding/factory/forwarding-factory.js +9 -3
  8. package/dist_ts/forwarding/handlers/base-handler.d.ts +4 -0
  9. package/dist_ts/forwarding/handlers/base-handler.js +25 -3
  10. package/dist_ts/forwarding/index.d.ts +3 -8
  11. package/dist_ts/forwarding/index.js +4 -13
  12. package/dist_ts/proxies/network-proxy/network-proxy.js +4 -2
  13. package/dist_ts/proxies/network-proxy/request-handler.js +3 -3
  14. package/dist_ts/proxies/network-proxy/websocket-handler.js +2 -2
  15. package/dist_ts/proxies/smart-proxy/models/index.d.ts +0 -1
  16. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +0 -9
  17. package/dist_ts/proxies/smart-proxy/models/interfaces.js +1 -12
  18. package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +1 -44
  19. package/dist_ts/proxies/smart-proxy/models/route-types.js +2 -1
  20. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +0 -3
  21. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +8 -13
  22. package/dist_ts/proxies/smart-proxy/route-manager.js +2 -3
  23. package/dist_ts/proxies/smart-proxy/smart-proxy.js +2 -3
  24. package/dist_ts/proxies/smart-proxy/utils/index.d.ts +0 -2
  25. package/dist_ts/proxies/smart-proxy/utils/index.js +3 -6
  26. package/dist_ts/proxies/smart-proxy/utils/route-patterns.d.ts +48 -0
  27. package/dist_ts/proxies/smart-proxy/utils/route-patterns.js +106 -2
  28. package/package.json +1 -1
  29. package/readme.plan.md +175 -77
  30. package/ts/00_commitinfo_data.ts +1 -1
  31. package/ts/common/port80-adapter.ts +26 -2
  32. package/ts/forwarding/config/forwarding-types.ts +12 -70
  33. package/ts/forwarding/config/index.ts +19 -2
  34. package/ts/forwarding/factory/forwarding-factory.ts +7 -2
  35. package/ts/forwarding/handlers/base-handler.ts +22 -2
  36. package/ts/forwarding/index.ts +17 -17
  37. package/ts/proxies/network-proxy/network-proxy.ts +4 -1
  38. package/ts/proxies/network-proxy/request-handler.ts +2 -2
  39. package/ts/proxies/network-proxy/websocket-handler.ts +1 -1
  40. package/ts/proxies/smart-proxy/models/index.ts +0 -3
  41. package/ts/proxies/smart-proxy/models/interfaces.ts +1 -17
  42. package/ts/proxies/smart-proxy/models/route-types.ts +2 -60
  43. package/ts/proxies/smart-proxy/route-connection-handler.ts +4 -14
  44. package/ts/proxies/smart-proxy/route-manager.ts +3 -8
  45. package/ts/proxies/smart-proxy/smart-proxy.ts +2 -4
  46. package/ts/proxies/smart-proxy/utils/index.ts +2 -5
  47. package/ts/proxies/smart-proxy/utils/route-patterns.ts +146 -2
  48. package/ts/proxies/smart-proxy/utils/route-migration-utils.ts +0 -165
@@ -55,17 +55,37 @@ export abstract class ForwardingHandler extends plugins.EventEmitter implements
55
55
  const randomIndex = Math.floor(Math.random() * target.host.length);
56
56
  return {
57
57
  host: target.host[randomIndex],
58
- port: target.port
58
+ port: this.resolvePort(target.port)
59
59
  };
60
60
  }
61
61
 
62
62
  // Single host
63
63
  return {
64
64
  host: target.host,
65
- port: target.port
65
+ port: this.resolvePort(target.port)
66
66
  };
67
67
  }
68
68
 
69
+ /**
70
+ * Resolves a port value, handling 'preserve' and function ports
71
+ */
72
+ protected resolvePort(port: number | 'preserve' | ((ctx: any) => number)): number {
73
+ if (typeof port === 'function') {
74
+ try {
75
+ // Create a minimal context for the function
76
+ const ctx = { port: 80 }; // Default port for minimal context
77
+ return port(ctx);
78
+ } catch (err) {
79
+ console.error('Error resolving port function:', err);
80
+ return 80; // Default fallback port
81
+ }
82
+ } else if (port === 'preserve') {
83
+ return 80; // Default port for 'preserve' in base handler
84
+ } else {
85
+ return port;
86
+ }
87
+ }
88
+
69
89
  /**
70
90
  * Redirect an HTTP request to HTTPS
71
91
  * @param req The HTTP request
@@ -3,9 +3,6 @@
3
3
  * Provides a flexible and type-safe way to configure and manage various forwarding strategies
4
4
  */
5
5
 
6
- // Export types and configuration
7
- export * from './config/forwarding-types.js';
8
-
9
6
  // Export handlers
10
7
  export { ForwardingHandler } from './handlers/base-handler.js';
11
8
  export * from './handlers/http-handler.js';
@@ -16,20 +13,23 @@ export * from './handlers/https-terminate-to-https-handler.js';
16
13
  // Export factory
17
14
  export * from './factory/forwarding-factory.js';
18
15
 
19
- // Helper functions as a convenience object
20
- import {
21
- httpOnly,
22
- tlsTerminateToHttp,
23
- tlsTerminateToHttps,
24
- httpsPassthrough
16
+ // Export types - these include TForwardingType and IForwardConfig
17
+ export type {
18
+ TForwardingType,
19
+ IForwardConfig,
20
+ IForwardingHandler
25
21
  } from './config/forwarding-types.js';
26
22
 
27
- // Export route-based helpers from smart-proxy
28
- export * from '../proxies/smart-proxy/utils/route-helpers.js';
23
+ export {
24
+ ForwardingHandlerEvents
25
+ } from './config/forwarding-types.js';
29
26
 
30
- export const helpers = {
31
- httpOnly,
32
- tlsTerminateToHttp,
33
- tlsTerminateToHttps,
34
- httpsPassthrough
35
- };
27
+ // Export route helpers directly from route-patterns
28
+ export {
29
+ createHttpRoute,
30
+ createHttpsTerminateRoute,
31
+ createHttpsPassthroughRoute,
32
+ createHttpToHttpsRedirect,
33
+ createCompleteHttpsServer,
34
+ createLoadBalancerRoute
35
+ } from '../proxies/smart-proxy/utils/route-patterns.js';
@@ -447,6 +447,8 @@ export class NetworkProxy implements IMetricsTracker {
447
447
 
448
448
  // Create legacy proxy configs for the router
449
449
  // This is only needed for backward compatibility with ProxyRouter
450
+
451
+ const defaultPort = 443; // Default port for HTTPS when using 'preserve'
450
452
  // and will be removed in the future
451
453
  const legacyConfigs: IReverseProxyConfig[] = [];
452
454
 
@@ -472,7 +474,8 @@ export class NetworkProxy implements IMetricsTracker {
472
474
  ? route.action.target.host
473
475
  : [route.action.target.host];
474
476
 
475
- const targetPort = route.action.target.port;
477
+ // Handle 'preserve' port value
478
+ const targetPort = route.action.target.port === 'preserve' ? defaultPort : route.action.target.port;
476
479
 
477
480
  // Get certificate information
478
481
  const certData = certificateUpdates.get(domain);
@@ -540,7 +540,7 @@ export class RequestHandler {
540
540
  this.logger.debug(`Resolved function-based port to: ${resolvedPort}`);
541
541
  }
542
542
  } else {
543
- targetPort = matchingRoute.action.target.port;
543
+ targetPort = matchingRoute.action.target.port === 'preserve' ? routeContext.port : matchingRoute.action.target.port as number;
544
544
  }
545
545
 
546
546
  // Select a single host if an array was provided
@@ -760,7 +760,7 @@ export class RequestHandler {
760
760
  this.logger.debug(`Resolved HTTP/2 function-based port to: ${resolvedPort}`);
761
761
  }
762
762
  } else {
763
- targetPort = matchingRoute.action.target.port;
763
+ targetPort = matchingRoute.action.target.port === 'preserve' ? routeContext.port : matchingRoute.action.target.port as number;
764
764
  }
765
765
 
766
766
  // Select a single host if an array was provided
@@ -204,7 +204,7 @@ export class WebSocketHandler {
204
204
  targetPort = route.action.target.port(toBaseContext(routeContext));
205
205
  this.logger.debug(`Resolved function-based port for WebSocket: ${targetPort}`);
206
206
  } else {
207
- targetPort = route.action.target.port;
207
+ targetPort = route.action.target.port === 'preserve' ? routeContext.port : route.action.target.port as number;
208
208
  }
209
209
 
210
210
  // Select a single host if an array was provided
@@ -3,6 +3,3 @@
3
3
  */
4
4
  export * from './interfaces.js';
5
5
  export * from './route-types.js';
6
-
7
- // Re-export IRoutedSmartProxyOptions explicitly to avoid ambiguity
8
- export type { ISmartProxyOptions as IRoutedSmartProxyOptions } from './interfaces.js';
@@ -8,23 +8,7 @@ import type { TForwardingType } from '../../../forwarding/config/forwarding-type
8
8
  */
9
9
  export type TSmartProxyCertProvisionObject = plugins.tsclass.network.ICert | 'http01';
10
10
 
11
- /**
12
- * Alias for backward compatibility with code that uses IRoutedSmartProxyOptions
13
- */
14
- export type IRoutedSmartProxyOptions = ISmartProxyOptions;
15
-
16
- /**
17
- * Helper functions for type checking configuration types
18
- */
19
- export function isLegacyOptions(options: any): boolean {
20
- // Legacy options are no longer supported
21
- return false;
22
- }
23
-
24
- export function isRoutedOptions(options: any): boolean {
25
- // All configurations are now route-based
26
- return true;
27
- }
11
+ // Legacy options and type checking functions have been removed
28
12
 
29
13
  /**
30
14
  * SmartProxy configuration options
@@ -69,8 +69,7 @@ export interface IRouteContext {
69
69
  */
70
70
  export interface IRouteTarget {
71
71
  host: string | string[] | ((context: IRouteContext) => string | string[]); // Host or hosts with optional function for dynamic resolution
72
- port: number | ((context: IRouteContext) => number); // Port with optional function for dynamic mapping
73
- preservePort?: boolean; // Use incoming port as target port (ignored if port is a function)
72
+ port: number | 'preserve' | ((context: IRouteContext) => number); // Port with optional function for dynamic mapping (use 'preserve' to keep the incoming port)
74
73
  }
75
74
 
76
75
  /**
@@ -322,61 +321,4 @@ export interface IRouteConfig {
322
321
  enabled?: boolean; // Whether the route is active (default: true)
323
322
  }
324
323
 
325
- /**
326
- * Unified SmartProxy options with routes-based configuration
327
- */
328
- export interface IRoutedSmartProxyOptions {
329
- // The unified configuration array (required)
330
- routes: IRouteConfig[];
331
-
332
- // Global/default settings
333
- defaults?: {
334
- target?: {
335
- host: string;
336
- port: number;
337
- };
338
- security?: IRouteSecurity;
339
- tls?: IRouteTls;
340
- // ...other defaults
341
- };
342
-
343
- // Other global settings remain (acme, etc.)
344
- acme?: IAcmeOptions;
345
-
346
- // Connection timeouts and other global settings
347
- initialDataTimeout?: number;
348
- socketTimeout?: number;
349
- inactivityCheckInterval?: number;
350
- maxConnectionLifetime?: number;
351
- inactivityTimeout?: number;
352
- gracefulShutdownTimeout?: number;
353
-
354
- // Socket optimization settings
355
- noDelay?: boolean;
356
- keepAlive?: boolean;
357
- keepAliveInitialDelay?: number;
358
- maxPendingDataSize?: number;
359
-
360
- // Enhanced features
361
- disableInactivityCheck?: boolean;
362
- enableKeepAliveProbes?: boolean;
363
- enableDetailedLogging?: boolean;
364
- enableTlsDebugLogging?: boolean;
365
- enableRandomizedTimeouts?: boolean;
366
- allowSessionTicket?: boolean;
367
-
368
- // Rate limiting and security
369
- maxConnectionsPerIP?: number;
370
- connectionRateLimitPerMinute?: number;
371
-
372
- // Enhanced keep-alive settings
373
- keepAliveTreatment?: 'standard' | 'extended' | 'immortal';
374
- keepAliveInactivityMultiplier?: number;
375
- extendedKeepAliveLifetime?: number;
376
-
377
- /**
378
- * Optional certificate provider callback. Return 'http01' to use HTTP-01 challenges,
379
- * or a static certificate object for immediate provisioning.
380
- */
381
- certProvisionFunction?: (domain: string) => Promise<any>;
382
- }
324
+ // Configuration moved to models/interfaces.ts as ISmartProxyOptions
@@ -3,9 +3,7 @@ import type {
3
3
  IConnectionRecord,
4
4
  ISmartProxyOptions
5
5
  } from './models/interfaces.js';
6
- import {
7
- isRoutedOptions
8
- } from './models/interfaces.js';
6
+ // Route checking functions have been removed
9
7
  import type {
10
8
  IRouteConfig,
11
9
  IRouteAction,
@@ -316,7 +314,6 @@ export class RouteConnectionHandler {
316
314
  return this.setupDirectConnection(
317
315
  socket,
318
316
  record,
319
- undefined,
320
317
  serverName,
321
318
  initialChunk,
322
319
  undefined,
@@ -434,8 +431,8 @@ export class RouteConnectionHandler {
434
431
  this.connectionManager.cleanupConnection(record, 'port_mapping_error');
435
432
  return;
436
433
  }
437
- } else if (action.target.preservePort) {
438
- // Use incoming port if preservePort is true
434
+ } else if (action.target.port === 'preserve') {
435
+ // Use incoming port if port is 'preserve'
439
436
  targetPort = record.localPort;
440
437
  } else {
441
438
  // Use static port from configuration
@@ -457,7 +454,6 @@ export class RouteConnectionHandler {
457
454
  return this.setupDirectConnection(
458
455
  socket,
459
456
  record,
460
- undefined,
461
457
  record.lockedDomain,
462
458
  initialChunk,
463
459
  undefined,
@@ -525,7 +521,7 @@ export class RouteConnectionHandler {
525
521
  let targetPort: number;
526
522
  if (typeof action.target.port === 'function') {
527
523
  targetPort = action.target.port(routeContext);
528
- } else if (action.target.preservePort) {
524
+ } else if (action.target.port === 'preserve') {
529
525
  targetPort = record.localPort;
530
526
  } else {
531
527
  targetPort = action.target.port;
@@ -538,7 +534,6 @@ export class RouteConnectionHandler {
538
534
  return this.setupDirectConnection(
539
535
  socket,
540
536
  record,
541
- undefined,
542
537
  record.lockedDomain,
543
538
  initialChunk,
544
539
  undefined,
@@ -656,17 +651,12 @@ export class RouteConnectionHandler {
656
651
  this.connectionManager.initiateCleanupOnce(record, 'route_blocked');
657
652
  }
658
653
 
659
- /**
660
- * Legacy connection handling has been removed in favor of pure route-based approach
661
- */
662
-
663
654
  /**
664
655
  * Sets up a direct connection to the target
665
656
  */
666
657
  private setupDirectConnection(
667
658
  socket: plugins.net.Socket,
668
659
  record: IConnectionRecord,
669
- _unused?: any, // kept for backward compatibility
670
660
  serverName?: string,
671
661
  initialChunk?: Buffer,
672
662
  overridePort?: number,
@@ -6,12 +6,7 @@ import type {
6
6
  TPortRange
7
7
  } from './models/route-types.js';
8
8
  import type {
9
- ISmartProxyOptions,
10
- IRoutedSmartProxyOptions
11
- } from './models/interfaces.js';
12
- import {
13
- isRoutedOptions,
14
- isLegacyOptions
9
+ ISmartProxyOptions
15
10
  } from './models/interfaces.js';
16
11
 
17
12
  /**
@@ -29,12 +24,12 @@ export interface IRouteMatchResult {
29
24
  export class RouteManager extends plugins.EventEmitter {
30
25
  private routes: IRouteConfig[] = [];
31
26
  private portMap: Map<number, IRouteConfig[]> = new Map();
32
- private options: IRoutedSmartProxyOptions;
27
+ private options: ISmartProxyOptions;
33
28
 
34
29
  constructor(options: ISmartProxyOptions) {
35
30
  super();
36
31
 
37
- // We no longer support legacy options, always use provided options
32
+ // Store options
38
33
  this.options = options;
39
34
 
40
35
  // Initialize routes from either source
@@ -19,10 +19,8 @@ import { createPort80HandlerOptions } from '../../common/port80-adapter.js';
19
19
 
20
20
  // Import types and utilities
21
21
  import type {
22
- ISmartProxyOptions,
23
- IRoutedSmartProxyOptions
22
+ ISmartProxyOptions
24
23
  } from './models/interfaces.js';
25
- import { isRoutedOptions, isLegacyOptions } from './models/interfaces.js';
26
24
  import type { IRouteConfig } from './models/route-types.js';
27
25
 
28
26
  /**
@@ -650,7 +648,7 @@ export class SmartProxy extends plugins.EventEmitter {
650
648
  const domains: string[] = [];
651
649
 
652
650
  // Get domains from routes
653
- const routes = isRoutedOptions(this.settings) ? this.settings.routes : [];
651
+ const routes = this.settings.routes || [];
654
652
 
655
653
  for (const route of routes) {
656
654
  if (!route.match.domains) continue;
@@ -5,8 +5,7 @@
5
5
  * including helpers, validators, utilities, and patterns for working with routes.
6
6
  */
7
7
 
8
- // Export route helpers for creating routes
9
- export * from './route-helpers.js';
8
+ // Route helpers have been consolidated in route-patterns.js
10
9
 
11
10
  // Export route validators for validating route configurations
12
11
  export * from './route-validators.js';
@@ -35,6 +34,4 @@ export {
35
34
  addJwtAuth
36
35
  };
37
36
 
38
- // Export migration utilities for transitioning from domain-based to route-based configs
39
- // Note: These will be removed in a future version once migration is complete
40
- export * from './route-migration-utils.js';
37
+ // Migration utilities have been removed as they are no longer needed
@@ -5,10 +5,154 @@
5
5
  * These patterns can be used as templates for creating route configurations.
6
6
  */
7
7
 
8
- import type { IRouteConfig } from '../models/route-types.js';
9
- import { createHttpRoute, createHttpsTerminateRoute, createHttpsPassthroughRoute, createCompleteHttpsServer } from './route-helpers.js';
8
+ import type { IRouteConfig, IRouteMatch, IRouteAction, IRouteTarget } from '../models/route-types.js';
10
9
  import { mergeRouteConfigs } from './route-utils.js';
11
10
 
11
+ /**
12
+ * Create a basic HTTP route configuration
13
+ */
14
+ export function createHttpRoute(
15
+ domains: string | string[],
16
+ target: { host: string | string[]; port: number | 'preserve' | ((ctx: any) => number) },
17
+ options: Partial<IRouteConfig> = {}
18
+ ): IRouteConfig {
19
+ const route: IRouteConfig = {
20
+ match: {
21
+ domains,
22
+ ports: 80
23
+ },
24
+ action: {
25
+ type: 'forward',
26
+ target: {
27
+ host: target.host,
28
+ port: target.port
29
+ }
30
+ },
31
+ name: options.name || `HTTP: ${Array.isArray(domains) ? domains.join(', ') : domains}`
32
+ };
33
+
34
+ return mergeRouteConfigs(route, options);
35
+ }
36
+
37
+ /**
38
+ * Create an HTTPS route with TLS termination
39
+ */
40
+ export function createHttpsTerminateRoute(
41
+ domains: string | string[],
42
+ target: { host: string | string[]; port: number | 'preserve' | ((ctx: any) => number) },
43
+ options: Partial<IRouteConfig> & {
44
+ certificate?: 'auto' | { key: string; cert: string };
45
+ reencrypt?: boolean;
46
+ } = {}
47
+ ): IRouteConfig {
48
+ const route: IRouteConfig = {
49
+ match: {
50
+ domains,
51
+ ports: 443
52
+ },
53
+ action: {
54
+ type: 'forward',
55
+ target: {
56
+ host: target.host,
57
+ port: target.port
58
+ },
59
+ tls: {
60
+ mode: options.reencrypt ? 'terminate-and-reencrypt' : 'terminate',
61
+ certificate: options.certificate || 'auto'
62
+ }
63
+ },
64
+ name: options.name || `HTTPS (terminate): ${Array.isArray(domains) ? domains.join(', ') : domains}`
65
+ };
66
+
67
+ return mergeRouteConfigs(route, options);
68
+ }
69
+
70
+ /**
71
+ * Create an HTTPS route with TLS passthrough
72
+ */
73
+ export function createHttpsPassthroughRoute(
74
+ domains: string | string[],
75
+ target: { host: string | string[]; port: number | 'preserve' | ((ctx: any) => number) },
76
+ options: Partial<IRouteConfig> = {}
77
+ ): IRouteConfig {
78
+ const route: IRouteConfig = {
79
+ match: {
80
+ domains,
81
+ ports: 443
82
+ },
83
+ action: {
84
+ type: 'forward',
85
+ target: {
86
+ host: target.host,
87
+ port: target.port
88
+ },
89
+ tls: {
90
+ mode: 'passthrough'
91
+ }
92
+ },
93
+ name: options.name || `HTTPS (passthrough): ${Array.isArray(domains) ? domains.join(', ') : domains}`
94
+ };
95
+
96
+ return mergeRouteConfigs(route, options);
97
+ }
98
+
99
+ /**
100
+ * Create an HTTP to HTTPS redirect route
101
+ */
102
+ export function createHttpToHttpsRedirect(
103
+ domains: string | string[],
104
+ options: Partial<IRouteConfig> & {
105
+ redirectCode?: 301 | 302 | 307 | 308;
106
+ preservePath?: boolean;
107
+ } = {}
108
+ ): IRouteConfig {
109
+ const route: IRouteConfig = {
110
+ match: {
111
+ domains,
112
+ ports: 80
113
+ },
114
+ action: {
115
+ type: 'redirect',
116
+ redirect: {
117
+ to: options.preservePath ? 'https://{domain}{path}' : 'https://{domain}',
118
+ status: options.redirectCode || 301
119
+ }
120
+ },
121
+ name: options.name || `HTTP to HTTPS redirect: ${Array.isArray(domains) ? domains.join(', ') : domains}`
122
+ };
123
+
124
+ return mergeRouteConfigs(route, options);
125
+ }
126
+
127
+ /**
128
+ * Create a complete HTTPS server with redirect from HTTP
129
+ */
130
+ export function createCompleteHttpsServer(
131
+ domains: string | string[],
132
+ target: { host: string | string[]; port: number | 'preserve' | ((ctx: any) => number) },
133
+ options: Partial<IRouteConfig> & {
134
+ certificate?: 'auto' | { key: string; cert: string };
135
+ tlsMode?: 'terminate' | 'passthrough' | 'terminate-and-reencrypt';
136
+ redirectCode?: 301 | 302 | 307 | 308;
137
+ } = {}
138
+ ): IRouteConfig[] {
139
+ // Create the TLS route based on the selected mode
140
+ const tlsRoute = options.tlsMode === 'passthrough'
141
+ ? createHttpsPassthroughRoute(domains, target, options)
142
+ : createHttpsTerminateRoute(domains, target, {
143
+ ...options,
144
+ reencrypt: options.tlsMode === 'terminate-and-reencrypt'
145
+ });
146
+
147
+ // Create the HTTP to HTTPS redirect route
148
+ const redirectRoute = createHttpToHttpsRedirect(domains, {
149
+ redirectCode: options.redirectCode,
150
+ preservePath: true
151
+ });
152
+
153
+ return [tlsRoute, redirectRoute];
154
+ }
155
+
12
156
  /**
13
157
  * Create an API Gateway route pattern
14
158
  * @param domains Domain(s) to match