@push.rocks/smartproxy 15.0.2 → 16.0.2

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 (80) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/certificate/index.d.ts +10 -4
  3. package/dist_ts/certificate/index.js +5 -7
  4. package/dist_ts/certificate/models/certificate-types.d.ts +35 -15
  5. package/dist_ts/certificate/providers/cert-provisioner.d.ts +41 -15
  6. package/dist_ts/certificate/providers/cert-provisioner.js +201 -41
  7. package/dist_ts/forwarding/config/forwarding-types.d.ts +40 -76
  8. package/dist_ts/forwarding/config/forwarding-types.js +19 -18
  9. package/dist_ts/forwarding/config/index.d.ts +4 -2
  10. package/dist_ts/forwarding/config/index.js +5 -3
  11. package/dist_ts/forwarding/handlers/base-handler.js +3 -1
  12. package/dist_ts/forwarding/index.d.ts +5 -6
  13. package/dist_ts/forwarding/index.js +3 -3
  14. package/dist_ts/http/models/http-types.js +1 -1
  15. package/dist_ts/http/port80/acme-interfaces.d.ts +30 -0
  16. package/dist_ts/http/port80/acme-interfaces.js +46 -1
  17. package/dist_ts/http/port80/port80-handler.d.ts +17 -2
  18. package/dist_ts/http/port80/port80-handler.js +49 -11
  19. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +2 -61
  20. package/dist_ts/proxies/smart-proxy/models/interfaces.js +5 -4
  21. package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +118 -4
  22. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +70 -4
  23. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +193 -43
  24. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +2 -5
  25. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +25 -146
  26. package/dist_ts/proxies/smart-proxy/route-helpers/index.d.ts +7 -0
  27. package/dist_ts/proxies/smart-proxy/route-helpers/index.js +9 -0
  28. package/dist_ts/proxies/smart-proxy/route-helpers.d.ts +54 -1
  29. package/dist_ts/proxies/smart-proxy/route-helpers.js +102 -1
  30. package/dist_ts/proxies/smart-proxy/route-manager.d.ts +3 -9
  31. package/dist_ts/proxies/smart-proxy/route-manager.js +3 -115
  32. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +72 -10
  33. package/dist_ts/proxies/smart-proxy/smart-proxy.js +135 -268
  34. package/dist_ts/proxies/smart-proxy/timeout-manager.js +3 -3
  35. package/dist_ts/proxies/smart-proxy/utils/index.d.ts +12 -0
  36. package/dist_ts/proxies/smart-proxy/utils/index.js +19 -0
  37. package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +174 -0
  38. package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +332 -0
  39. package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.d.ts +51 -0
  40. package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.js +124 -0
  41. package/dist_ts/proxies/smart-proxy/utils/route-patterns.d.ts +131 -0
  42. package/dist_ts/proxies/smart-proxy/utils/route-patterns.js +217 -0
  43. package/dist_ts/proxies/smart-proxy/utils/route-utils.d.ts +79 -0
  44. package/dist_ts/proxies/smart-proxy/utils/route-utils.js +266 -0
  45. package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +73 -0
  46. package/dist_ts/proxies/smart-proxy/utils/route-validators.js +242 -0
  47. package/package.json +1 -1
  48. package/readme.md +139 -111
  49. package/readme.plan.md +164 -312
  50. package/ts/00_commitinfo_data.ts +1 -1
  51. package/ts/certificate/index.ts +17 -9
  52. package/ts/certificate/models/certificate-types.ts +37 -16
  53. package/ts/certificate/providers/cert-provisioner.ts +247 -54
  54. package/ts/forwarding/config/forwarding-types.ts +79 -107
  55. package/ts/forwarding/config/index.ts +4 -2
  56. package/ts/forwarding/handlers/base-handler.ts +4 -2
  57. package/ts/forwarding/index.ts +3 -2
  58. package/ts/http/models/http-types.ts +0 -1
  59. package/ts/http/port80/acme-interfaces.ts +84 -0
  60. package/ts/http/port80/port80-handler.ts +61 -15
  61. package/ts/proxies/smart-proxy/models/interfaces.ts +7 -64
  62. package/ts/proxies/smart-proxy/models/route-types.ts +152 -22
  63. package/ts/proxies/smart-proxy/network-proxy-bridge.ts +226 -55
  64. package/ts/proxies/smart-proxy/route-connection-handler.ts +36 -205
  65. package/ts/proxies/smart-proxy/route-helpers/index.ts +9 -0
  66. package/ts/proxies/smart-proxy/route-helpers.ts +165 -11
  67. package/ts/proxies/smart-proxy/route-manager.ts +3 -130
  68. package/ts/proxies/smart-proxy/smart-proxy.ts +157 -329
  69. package/ts/proxies/smart-proxy/timeout-manager.ts +2 -2
  70. package/ts/proxies/smart-proxy/utils/index.ts +40 -0
  71. package/ts/proxies/smart-proxy/utils/route-helpers.ts +455 -0
  72. package/ts/proxies/smart-proxy/utils/route-migration-utils.ts +165 -0
  73. package/ts/proxies/smart-proxy/utils/route-patterns.ts +309 -0
  74. package/ts/proxies/smart-proxy/utils/route-utils.ts +330 -0
  75. package/ts/proxies/smart-proxy/utils/route-validators.ts +269 -0
  76. package/ts/forwarding/config/domain-config.ts +0 -28
  77. package/ts/forwarding/config/domain-manager.ts +0 -283
  78. package/ts/proxies/smart-proxy/connection-handler.ts +0 -1240
  79. package/ts/proxies/smart-proxy/port-range-manager.ts +0 -211
  80. /package/ts/proxies/smart-proxy/{domain-config-manager.ts → domain-config-manager.ts.bak} +0 -0
@@ -5,7 +5,7 @@ import type { TForwardingType } from '../../../forwarding/config/forwarding-type
5
5
  /**
6
6
  * Supported action types for route configurations
7
7
  */
8
- export type TRouteActionType = 'forward' | 'redirect' | 'block';
8
+ export type TRouteActionType = 'forward' | 'redirect' | 'block' | 'static';
9
9
 
10
10
  /**
11
11
  * TLS handling modes for route configurations
@@ -23,14 +23,15 @@ export type TPortRange = number | number[] | Array<{ from: number; to: number }>
23
23
  export interface IRouteMatch {
24
24
  // Listen on these ports (required)
25
25
  ports: TPortRange;
26
-
26
+
27
27
  // Optional domain patterns to match (default: all domains)
28
28
  domains?: string | string[];
29
-
29
+
30
30
  // Advanced matching criteria
31
31
  path?: string; // Match specific paths
32
32
  clientIp?: string[]; // Match specific client IPs
33
33
  tlsVersion?: string[]; // Match specific TLS versions
34
+ headers?: Record<string, string | RegExp>; // Match specific HTTP headers
34
35
  }
35
36
 
36
37
  /**
@@ -61,6 +62,25 @@ export interface IRouteRedirect {
61
62
  status: 301 | 302 | 307 | 308;
62
63
  }
63
64
 
65
+ /**
66
+ * Authentication options
67
+ */
68
+ export interface IRouteAuthentication {
69
+ type: 'basic' | 'digest' | 'oauth' | 'jwt';
70
+ credentials?: {
71
+ username: string;
72
+ password: string;
73
+ }[];
74
+ realm?: string;
75
+ jwtSecret?: string;
76
+ jwtIssuer?: string;
77
+ oauthProvider?: string;
78
+ oauthClientId?: string;
79
+ oauthClientSecret?: string;
80
+ oauthRedirectUri?: string;
81
+ [key: string]: any; // Allow additional auth-specific options
82
+ }
83
+
64
84
  /**
65
85
  * Security options for route actions
66
86
  */
@@ -68,10 +88,31 @@ export interface IRouteSecurity {
68
88
  allowedIps?: string[];
69
89
  blockedIps?: string[];
70
90
  maxConnections?: number;
71
- authentication?: {
72
- type: 'basic' | 'digest' | 'oauth';
73
- // Auth-specific options would go here
74
- };
91
+ authentication?: IRouteAuthentication;
92
+ }
93
+
94
+ /**
95
+ * Static file server configuration
96
+ */
97
+ export interface IRouteStaticFiles {
98
+ root: string;
99
+ index?: string[];
100
+ headers?: Record<string, string>;
101
+ directory?: string;
102
+ indexFiles?: string[];
103
+ cacheControl?: string;
104
+ expires?: number;
105
+ followSymlinks?: boolean;
106
+ disableDirectoryListing?: boolean;
107
+ }
108
+
109
+ /**
110
+ * Test route response configuration
111
+ */
112
+ export interface IRouteTestResponse {
113
+ status: number;
114
+ headers: Record<string, string>;
115
+ body: string;
75
116
  }
76
117
 
77
118
  /**
@@ -81,47 +122,136 @@ export interface IRouteAdvanced {
81
122
  timeout?: number;
82
123
  headers?: Record<string, string>;
83
124
  keepAlive?: boolean;
125
+ staticFiles?: IRouteStaticFiles;
126
+ testResponse?: IRouteTestResponse;
84
127
  // Additional advanced options would go here
85
128
  }
86
129
 
130
+ /**
131
+ * WebSocket configuration
132
+ */
133
+ export interface IRouteWebSocket {
134
+ enabled: boolean;
135
+ pingInterval?: number;
136
+ pingTimeout?: number;
137
+ maxPayloadSize?: number;
138
+ }
139
+
140
+ /**
141
+ * Load balancing configuration
142
+ */
143
+ export interface IRouteLoadBalancing {
144
+ algorithm: 'round-robin' | 'least-connections' | 'ip-hash';
145
+ healthCheck?: {
146
+ path: string;
147
+ interval: number;
148
+ timeout: number;
149
+ unhealthyThreshold: number;
150
+ healthyThreshold: number;
151
+ };
152
+ }
153
+
87
154
  /**
88
155
  * Action configuration for route handling
89
156
  */
90
157
  export interface IRouteAction {
91
158
  // Basic routing
92
159
  type: TRouteActionType;
93
-
160
+
94
161
  // Target for forwarding
95
162
  target?: IRouteTarget;
96
-
163
+
97
164
  // TLS handling
98
165
  tls?: IRouteTls;
99
-
166
+
100
167
  // For redirects
101
168
  redirect?: IRouteRedirect;
102
-
169
+
170
+ // For static files
171
+ static?: IRouteStaticFiles;
172
+
173
+ // WebSocket support
174
+ websocket?: IRouteWebSocket;
175
+
176
+ // Load balancing options
177
+ loadBalancing?: IRouteLoadBalancing;
178
+
103
179
  // Security options
104
180
  security?: IRouteSecurity;
105
-
181
+
106
182
  // Advanced options
107
183
  advanced?: IRouteAdvanced;
108
184
  }
109
185
 
186
+ /**
187
+ * Rate limiting configuration
188
+ */
189
+ export interface IRouteRateLimit {
190
+ enabled: boolean;
191
+ maxRequests: number;
192
+ window: number; // Time window in seconds
193
+ keyBy?: 'ip' | 'path' | 'header';
194
+ headerName?: string;
195
+ errorMessage?: string;
196
+ }
197
+
198
+ /**
199
+ * Security features for routes
200
+ */
201
+ export interface IRouteSecurity {
202
+ rateLimit?: IRouteRateLimit;
203
+ basicAuth?: {
204
+ enabled: boolean;
205
+ users: Array<{ username: string; password: string }>;
206
+ realm?: string;
207
+ excludePaths?: string[];
208
+ };
209
+ jwtAuth?: {
210
+ enabled: boolean;
211
+ secret: string;
212
+ algorithm?: string;
213
+ issuer?: string;
214
+ audience?: string;
215
+ expiresIn?: number;
216
+ excludePaths?: string[];
217
+ };
218
+ ipAllowList?: string[];
219
+ ipBlockList?: string[];
220
+ }
221
+
222
+ /**
223
+ * Headers configuration
224
+ */
225
+ export interface IRouteHeaders {
226
+ request?: Record<string, string>;
227
+ response?: Record<string, string>;
228
+ }
229
+
110
230
  /**
111
231
  * The core unified configuration interface
112
232
  */
113
233
  export interface IRouteConfig {
234
+ // Unique identifier
235
+ id?: string;
236
+
114
237
  // What to match
115
238
  match: IRouteMatch;
116
-
239
+
117
240
  // What to do with matched traffic
118
241
  action: IRouteAction;
119
-
242
+
243
+ // Custom headers
244
+ headers?: IRouteHeaders;
245
+
246
+ // Security features
247
+ security?: IRouteSecurity;
248
+
120
249
  // Optional metadata
121
250
  name?: string; // Human-readable name for this route
122
251
  description?: string; // Description of the route's purpose
123
252
  priority?: number; // Controls matching order (higher = matched first)
124
253
  tags?: string[]; // Arbitrary tags for categorization
254
+ enabled?: boolean; // Whether the route is active (default: true)
125
255
  }
126
256
 
127
257
  /**
@@ -130,7 +260,7 @@ export interface IRouteConfig {
130
260
  export interface IRoutedSmartProxyOptions {
131
261
  // The unified configuration array (required)
132
262
  routes: IRouteConfig[];
133
-
263
+
134
264
  // Global/default settings
135
265
  defaults?: {
136
266
  target?: {
@@ -141,10 +271,10 @@ export interface IRoutedSmartProxyOptions {
141
271
  tls?: IRouteTls;
142
272
  // ...other defaults
143
273
  };
144
-
274
+
145
275
  // Other global settings remain (acme, etc.)
146
276
  acme?: IAcmeOptions;
147
-
277
+
148
278
  // Connection timeouts and other global settings
149
279
  initialDataTimeout?: number;
150
280
  socketTimeout?: number;
@@ -152,13 +282,13 @@ export interface IRoutedSmartProxyOptions {
152
282
  maxConnectionLifetime?: number;
153
283
  inactivityTimeout?: number;
154
284
  gracefulShutdownTimeout?: number;
155
-
285
+
156
286
  // Socket optimization settings
157
287
  noDelay?: boolean;
158
288
  keepAlive?: boolean;
159
289
  keepAliveInitialDelay?: number;
160
290
  maxPendingDataSize?: number;
161
-
291
+
162
292
  // Enhanced features
163
293
  disableInactivityCheck?: boolean;
164
294
  enableKeepAliveProbes?: boolean;
@@ -166,16 +296,16 @@ export interface IRoutedSmartProxyOptions {
166
296
  enableTlsDebugLogging?: boolean;
167
297
  enableRandomizedTimeouts?: boolean;
168
298
  allowSessionTicket?: boolean;
169
-
299
+
170
300
  // Rate limiting and security
171
301
  maxConnectionsPerIP?: number;
172
302
  connectionRateLimitPerMinute?: number;
173
-
303
+
174
304
  // Enhanced keep-alive settings
175
305
  keepAliveTreatment?: 'standard' | 'extended' | 'immortal';
176
306
  keepAliveInactivityMultiplier?: number;
177
307
  extendedKeepAliveLifetime?: number;
178
-
308
+
179
309
  /**
180
310
  * Optional certificate provider callback. Return 'http01' to use HTTP-01 challenges,
181
311
  * or a static certificate object for immediate provisioning.
@@ -4,10 +4,19 @@ import { Port80Handler } from '../../http/port80/port80-handler.js';
4
4
  import { Port80HandlerEvents } from '../../core/models/common-types.js';
5
5
  import { subscribeToPort80Handler } from '../../core/utils/event-utils.js';
6
6
  import type { ICertificateData } from '../../certificate/models/certificate-types.js';
7
- import type { IConnectionRecord, ISmartProxyOptions, IDomainConfig } from './models/interfaces.js';
7
+ import type { IConnectionRecord, ISmartProxyOptions } from './models/interfaces.js';
8
+ import type { IRouteConfig } from './models/route-types.js';
8
9
 
9
10
  /**
10
11
  * Manages NetworkProxy integration for TLS termination
12
+ *
13
+ * NetworkProxyBridge connects SmartProxy with NetworkProxy to handle TLS termination.
14
+ * It directly maps route configurations to NetworkProxy configuration format and manages
15
+ * certificate provisioning through Port80Handler when ACME is enabled.
16
+ *
17
+ * It is used by SmartProxy for routes that have:
18
+ * - TLS mode of 'terminate' or 'terminate-and-reencrypt'
19
+ * - Certificate set to 'auto' or custom certificate
11
20
  */
12
21
  export class NetworkProxyBridge {
13
22
  private networkProxy: NetworkProxy | null = null;
@@ -58,8 +67,8 @@ export class NetworkProxyBridge {
58
67
  this.networkProxy.setExternalPort80Handler(this.port80Handler);
59
68
  }
60
69
 
61
- // Convert and apply domain configurations to NetworkProxy
62
- await this.syncDomainConfigsToNetworkProxy();
70
+ // Apply route configurations to NetworkProxy
71
+ await this.syncRoutesToNetworkProxy(this.settings.routes || []);
63
72
  }
64
73
  }
65
74
 
@@ -147,35 +156,90 @@ export class NetworkProxyBridge {
147
156
  }
148
157
 
149
158
  /**
150
- * Register domains with Port80Handler
159
+ * Register domains from routes with Port80Handler for certificate management
160
+ *
161
+ * Extracts domains from routes that require TLS termination and registers them
162
+ * with the Port80Handler for certificate issuance and renewal.
163
+ *
164
+ * @param routes The route configurations to extract domains from
151
165
  */
152
- public registerDomainsWithPort80Handler(domains: string[]): void {
166
+ public registerDomainsWithPort80Handler(routes: IRouteConfig[]): void {
153
167
  if (!this.port80Handler) {
154
168
  console.log('Cannot register domains - Port80Handler not initialized');
155
169
  return;
156
170
  }
157
-
158
- for (const domain of domains) {
159
- // Skip wildcards
160
- if (domain.includes('*')) {
161
- console.log(`Skipping wildcard domain for ACME: ${domain}`);
162
- continue;
171
+
172
+ // Extract domains from routes that require TLS termination
173
+ const domainsToRegister = new Set<string>();
174
+
175
+ for (const route of routes) {
176
+ // Skip routes without domains or TLS configuration
177
+ if (!route.match.domains || !route.action.tls) continue;
178
+
179
+ // Only register domains for routes that terminate TLS
180
+ if (route.action.tls.mode !== 'terminate' && route.action.tls.mode !== 'terminate-and-reencrypt') continue;
181
+
182
+ // Extract domains from route
183
+ const domains = Array.isArray(route.match.domains)
184
+ ? route.match.domains
185
+ : [route.match.domains];
186
+
187
+ // Add each domain to the set (avoiding duplicates)
188
+ for (const domain of domains) {
189
+ // Skip wildcards
190
+ if (domain.includes('*')) {
191
+ console.log(`Skipping wildcard domain for ACME: ${domain}`);
192
+ continue;
193
+ }
194
+
195
+ domainsToRegister.add(domain);
163
196
  }
164
-
165
- // Register the domain
197
+ }
198
+
199
+ // Register each unique domain with Port80Handler
200
+ for (const domain of domainsToRegister) {
166
201
  try {
167
202
  this.port80Handler.addDomain({
168
203
  domainName: domain,
169
204
  sslRedirect: true,
170
- acmeMaintenance: true
205
+ acmeMaintenance: true,
206
+ // Include route reference if we can find it
207
+ routeReference: this.findRouteReferenceForDomain(domain, routes)
171
208
  });
172
-
209
+
173
210
  console.log(`Registered domain with Port80Handler: ${domain}`);
174
211
  } catch (err) {
175
212
  console.log(`Error registering domain ${domain} with Port80Handler: ${err}`);
176
213
  }
177
214
  }
178
215
  }
216
+
217
+ /**
218
+ * Finds the route reference for a given domain
219
+ *
220
+ * @param domain The domain to find a route reference for
221
+ * @param routes The routes to search
222
+ * @returns The route reference if found, undefined otherwise
223
+ */
224
+ private findRouteReferenceForDomain(domain: string, routes: IRouteConfig[]): { routeId?: string; routeName?: string } | undefined {
225
+ // Find the first route that matches this domain
226
+ for (const route of routes) {
227
+ if (!route.match.domains) continue;
228
+
229
+ const domains = Array.isArray(route.match.domains)
230
+ ? route.match.domains
231
+ : [route.match.domains];
232
+
233
+ if (domains.includes(domain)) {
234
+ return {
235
+ routeId: undefined, // No explicit IDs in our current routes
236
+ routeName: route.name
237
+ };
238
+ }
239
+ }
240
+
241
+ return undefined;
242
+ }
179
243
 
180
244
  /**
181
245
  * Forwards a TLS connection to a NetworkProxy for handling
@@ -249,9 +313,19 @@ export class NetworkProxyBridge {
249
313
  }
250
314
 
251
315
  /**
252
- * Synchronizes domain configurations to NetworkProxy
316
+ * Synchronizes routes to NetworkProxy
317
+ *
318
+ * This method directly maps route configurations to NetworkProxy format and updates
319
+ * the NetworkProxy with these configurations. It handles:
320
+ *
321
+ * - Extracting domain, target, and certificate information from routes
322
+ * - Converting TLS mode settings to NetworkProxy configuration
323
+ * - Applying security and advanced settings
324
+ * - Registering domains for ACME certificate provisioning when needed
325
+ *
326
+ * @param routes The route configurations to sync to NetworkProxy
253
327
  */
254
- public async syncDomainConfigsToNetworkProxy(): Promise<void> {
328
+ public async syncRoutesToNetworkProxy(routes: IRouteConfig[]): Promise<void> {
255
329
  if (!this.networkProxy) {
256
330
  console.log('Cannot sync configurations - NetworkProxy not initialized');
257
331
  return;
@@ -262,9 +336,9 @@ export class NetworkProxyBridge {
262
336
  // Import fs directly since it's not in plugins
263
337
  const fs = await import('fs');
264
338
 
265
- let certPair;
339
+ let defaultCertPair;
266
340
  try {
267
- certPair = {
341
+ defaultCertPair = {
268
342
  key: fs.readFileSync('assets/certs/key.pem', 'utf8'),
269
343
  cert: fs.readFileSync('assets/certs/cert.pem', 'utf8'),
270
344
  };
@@ -276,49 +350,130 @@ export class NetworkProxyBridge {
276
350
 
277
351
  // Use empty placeholders - NetworkProxy will use its internal defaults
278
352
  // or ACME will generate proper ones if enabled
279
- certPair = {
353
+ defaultCertPair = {
280
354
  key: '',
281
355
  cert: '',
282
356
  };
283
357
  }
284
358
 
285
- // Convert domain configs to NetworkProxy configs
286
- const proxyConfigs = this.networkProxy.convertSmartProxyConfigs(
287
- this.settings.domainConfigs,
288
- certPair
289
- );
290
-
291
- // Log ACME-eligible domains
292
- const acmeEnabled = !!this.settings.acme?.enabled;
293
- if (acmeEnabled) {
294
- const acmeEligibleDomains = proxyConfigs
295
- .filter((config) => !config.hostName.includes('*')) // Exclude wildcards
296
- .map((config) => config.hostName);
297
-
298
- if (acmeEligibleDomains.length > 0) {
299
- console.log(`Domains eligible for ACME certificates: ${acmeEligibleDomains.join(', ')}`);
300
-
301
- // Register these domains with Port80Handler if available
302
- if (this.port80Handler) {
303
- this.registerDomainsWithPort80Handler(acmeEligibleDomains);
304
- }
305
- } else {
306
- console.log('No domains eligible for ACME certificates found in configuration');
307
- }
308
- }
359
+ // Map routes directly to NetworkProxy configs
360
+ const proxyConfigs = this.mapRoutesToNetworkProxyConfigs(routes, defaultCertPair);
309
361
 
310
- // Update NetworkProxy with the converted configs
362
+ // Update the proxy configs
311
363
  await this.networkProxy.updateProxyConfigs(proxyConfigs);
312
- console.log(`Successfully synchronized ${proxyConfigs.length} domain configurations to NetworkProxy`);
364
+ console.log(`Synced ${proxyConfigs.length} configurations to NetworkProxy`);
365
+
366
+ // Register domains with Port80Handler for certificate issuance
367
+ if (this.port80Handler) {
368
+ this.registerDomainsWithPort80Handler(routes);
369
+ }
313
370
  } catch (err) {
314
- console.log(`Failed to sync configurations: ${err}`);
371
+ console.log(`Error syncing routes to NetworkProxy: ${err}`);
315
372
  }
316
373
  }
374
+
375
+ /**
376
+ * Map routes directly to NetworkProxy configuration format
377
+ *
378
+ * This method directly maps route configurations to NetworkProxy's format
379
+ * without any intermediate domain-based representation. It processes each route
380
+ * and creates appropriate NetworkProxy configs for domains that require TLS termination.
381
+ *
382
+ * @param routes Array of route configurations to map
383
+ * @param defaultCertPair Default certificate to use if no custom certificate is specified
384
+ * @returns Array of NetworkProxy configurations
385
+ */
386
+ public mapRoutesToNetworkProxyConfigs(
387
+ routes: IRouteConfig[],
388
+ defaultCertPair: { key: string; cert: string }
389
+ ): plugins.tsclass.network.IReverseProxyConfig[] {
390
+ const configs: plugins.tsclass.network.IReverseProxyConfig[] = [];
391
+
392
+ for (const route of routes) {
393
+ // Skip routes without domains
394
+ if (!route.match.domains) continue;
395
+
396
+ // Skip non-forward routes
397
+ if (route.action.type !== 'forward') continue;
398
+
399
+ // Skip routes without TLS configuration
400
+ if (!route.action.tls || !route.action.target) continue;
401
+
402
+ // Skip routes that don't require TLS termination
403
+ if (route.action.tls.mode !== 'terminate' && route.action.tls.mode !== 'terminate-and-reencrypt') continue;
404
+
405
+ // Get domains from route
406
+ const domains = Array.isArray(route.match.domains)
407
+ ? route.match.domains
408
+ : [route.match.domains];
409
+
410
+ // Create a config for each domain
411
+ for (const domain of domains) {
412
+ // Get certificate
413
+ let certKey = defaultCertPair.key;
414
+ let certCert = defaultCertPair.cert;
415
+
416
+ // Use custom certificate if specified
417
+ if (route.action.tls.certificate !== 'auto' && typeof route.action.tls.certificate === 'object') {
418
+ certKey = route.action.tls.certificate.key;
419
+ certCert = route.action.tls.certificate.cert;
420
+ }
421
+
422
+ // Determine target hosts and ports
423
+ const targetHosts = Array.isArray(route.action.target.host)
424
+ ? route.action.target.host
425
+ : [route.action.target.host];
426
+
427
+ const targetPort = route.action.target.port;
428
+
429
+ // Create the NetworkProxy config
430
+ const config: plugins.tsclass.network.IReverseProxyConfig = {
431
+ hostName: domain,
432
+ privateKey: certKey,
433
+ publicKey: certCert,
434
+ destinationIps: targetHosts,
435
+ destinationPorts: [targetPort]
436
+ // Note: We can't include additional metadata as it's not supported in the interface
437
+ };
438
+
439
+ configs.push(config);
440
+ }
441
+ }
442
+
443
+ return configs;
444
+ }
445
+
446
+ /**
447
+ * @deprecated This method is kept for backward compatibility.
448
+ * Use mapRoutesToNetworkProxyConfigs() instead.
449
+ */
450
+ public convertRoutesToNetworkProxyConfigs(
451
+ routes: IRouteConfig[],
452
+ defaultCertPair: { key: string; cert: string }
453
+ ): plugins.tsclass.network.IReverseProxyConfig[] {
454
+ return this.mapRoutesToNetworkProxyConfigs(routes, defaultCertPair);
455
+ }
456
+
457
+ /**
458
+ * @deprecated This method is deprecated and will be removed in a future version.
459
+ * Use syncRoutesToNetworkProxy() instead.
460
+ *
461
+ * This legacy method exists only for backward compatibility and
462
+ * simply forwards to syncRoutesToNetworkProxy().
463
+ */
464
+ public async syncDomainConfigsToNetworkProxy(): Promise<void> {
465
+ console.log('DEPRECATED: Method syncDomainConfigsToNetworkProxy will be removed in a future version.');
466
+ console.log('Please use syncRoutesToNetworkProxy() instead for direct route-based configuration.');
467
+ await this.syncRoutesToNetworkProxy(this.settings.routes || []);
468
+ }
317
469
 
318
470
  /**
319
471
  * Request a certificate for a specific domain
472
+ *
473
+ * @param domain The domain to request a certificate for
474
+ * @param routeName Optional route name to associate with this certificate
320
475
  */
321
- public async requestCertificate(domain: string): Promise<boolean> {
476
+ public async requestCertificate(domain: string, routeName?: string): Promise<boolean> {
322
477
  // Delegate to Port80Handler if available
323
478
  if (this.port80Handler) {
324
479
  try {
@@ -328,14 +483,30 @@ export class NetworkProxyBridge {
328
483
  console.log(`Certificate already exists for ${domain}`);
329
484
  return true;
330
485
  }
331
-
332
- // Register the domain for certificate issuance
333
- this.port80Handler.addDomain({
486
+
487
+ // Build the domain options
488
+ const domainOptions: any = {
334
489
  domainName: domain,
335
490
  sslRedirect: true,
336
- acmeMaintenance: true
337
- });
338
-
491
+ acmeMaintenance: true,
492
+ };
493
+
494
+ // Add route reference if available
495
+ if (routeName) {
496
+ domainOptions.routeReference = {
497
+ routeName
498
+ };
499
+ } else {
500
+ // Try to find a route reference from the current routes
501
+ const routeReference = this.findRouteReferenceForDomain(domain, this.settings.routes || []);
502
+ if (routeReference) {
503
+ domainOptions.routeReference = routeReference;
504
+ }
505
+ }
506
+
507
+ // Register the domain for certificate issuance
508
+ this.port80Handler.addDomain(domainOptions);
509
+
339
510
  console.log(`Domain ${domain} registered for certificate issuance`);
340
511
  return true;
341
512
  } catch (err) {
@@ -343,7 +514,7 @@ export class NetworkProxyBridge {
343
514
  return false;
344
515
  }
345
516
  }
346
-
517
+
347
518
  // Fall back to NetworkProxy if Port80Handler is not available
348
519
  if (!this.networkProxy) {
349
520
  console.log('Cannot request certificate - NetworkProxy not initialized');