@push.rocks/smartproxy 19.3.13 → 19.4.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.
@@ -93,6 +93,12 @@ export class SmartCertManager {
93
93
  */
94
94
  public setUpdateRoutesCallback(callback: (routes: IRouteConfig[]) => Promise<void>): void {
95
95
  this.updateRoutesCallback = callback;
96
+ try {
97
+ logger.log('debug', 'Route update callback set successfully', { component: 'certificate-manager' });
98
+ } catch (error) {
99
+ // Silently handle logging errors
100
+ console.log('[DEBUG] Route update callback set successfully');
101
+ }
96
102
  }
97
103
 
98
104
  /**
@@ -395,17 +401,31 @@ export class SmartCertManager {
395
401
 
396
402
  /**
397
403
  * Add challenge route to SmartProxy
404
+ *
405
+ * This method adds a special route for ACME HTTP-01 challenges, which typically uses port 80.
406
+ * Since we may already be listening on port 80 for regular routes, we need to be
407
+ * careful about how we add this route to avoid binding conflicts.
398
408
  */
399
409
  private async addChallengeRoute(): Promise<void> {
400
- // Check with state manager first
410
+ // Check with state manager first - avoid duplication
401
411
  if (this.acmeStateManager && this.acmeStateManager.isChallengeRouteActive()) {
402
- logger.log('info', 'Challenge route already active in global state, skipping', { component: 'certificate-manager' });
412
+ try {
413
+ logger.log('info', 'Challenge route already active in global state, skipping', { component: 'certificate-manager' });
414
+ } catch (error) {
415
+ // Silently handle logging errors
416
+ console.log('[INFO] Challenge route already active in global state, skipping');
417
+ }
403
418
  this.challengeRouteActive = true;
404
419
  return;
405
420
  }
406
421
 
407
422
  if (this.challengeRouteActive) {
408
- logger.log('info', 'Challenge route already active locally, skipping', { component: 'certificate-manager' });
423
+ try {
424
+ logger.log('info', 'Challenge route already active locally, skipping', { component: 'certificate-manager' });
425
+ } catch (error) {
426
+ // Silently handle logging errors
427
+ console.log('[INFO] Challenge route already active locally, skipping');
428
+ }
409
429
  return;
410
430
  }
411
431
 
@@ -421,6 +441,7 @@ export class SmartCertManager {
421
441
  const challengePort = this.globalAcmeDefaults?.port || 80;
422
442
 
423
443
  // Check if any existing routes are already using this port
444
+ // This helps us determine if we need to create a new binding or can reuse existing one
424
445
  const portInUseByRoutes = this.routes.some(route => {
425
446
  const routePorts = Array.isArray(route.match.ports) ? route.match.ports : [route.match.ports];
426
447
  return routePorts.some(p => {
@@ -434,19 +455,37 @@ export class SmartCertManager {
434
455
  return false;
435
456
  });
436
457
  });
437
-
438
- if (portInUseByRoutes) {
439
- logger.log('info', `Port ${challengePort} is already used by another route, merging ACME challenge route`, {
440
- port: challengePort,
441
- component: 'certificate-manager'
442
- });
443
- }
444
-
445
- // Add the challenge route
446
- const challengeRoute = this.challengeRoute;
447
-
458
+
448
459
  try {
460
+ // Log whether port is already in use by other routes
461
+ if (portInUseByRoutes) {
462
+ try {
463
+ logger.log('info', `Port ${challengePort} is already used by another route, merging ACME challenge route`, {
464
+ port: challengePort,
465
+ component: 'certificate-manager'
466
+ });
467
+ } catch (error) {
468
+ // Silently handle logging errors
469
+ console.log(`[INFO] Port ${challengePort} is already used by another route, merging ACME challenge route`);
470
+ }
471
+ } else {
472
+ try {
473
+ logger.log('info', `Adding new ACME challenge route on port ${challengePort}`, {
474
+ port: challengePort,
475
+ component: 'certificate-manager'
476
+ });
477
+ } catch (error) {
478
+ // Silently handle logging errors
479
+ console.log(`[INFO] Adding new ACME challenge route on port ${challengePort}`);
480
+ }
481
+ }
482
+
483
+ // Add the challenge route to the existing routes
484
+ const challengeRoute = this.challengeRoute;
449
485
  const updatedRoutes = [...this.routes, challengeRoute];
486
+
487
+ // With the re-ordering of start(), port binding should already be done
488
+ // This updateRoutes call should just add the route without binding again
450
489
  await this.updateRoutesCallback(updatedRoutes);
451
490
  this.challengeRouteActive = true;
452
491
 
@@ -455,29 +494,63 @@ export class SmartCertManager {
455
494
  this.acmeStateManager.addChallengeRoute(challengeRoute);
456
495
  }
457
496
 
458
- logger.log('info', 'ACME challenge route successfully added', { component: 'certificate-manager' });
497
+ try {
498
+ logger.log('info', 'ACME challenge route successfully added', { component: 'certificate-manager' });
499
+ } catch (error) {
500
+ // Silently handle logging errors
501
+ console.log('[INFO] ACME challenge route successfully added');
502
+ }
459
503
  } catch (error) {
460
- // Handle specific EADDRINUSE errors differently based on whether it's an internal conflict
504
+ // Enhanced error handling based on error type
461
505
  if ((error as any).code === 'EADDRINUSE') {
462
- logger.log('error', `Failed to add challenge route on port ${challengePort}: ${error.message}`, {
463
- error: error.message,
464
- port: challengePort,
465
- component: 'certificate-manager'
466
- });
506
+ try {
507
+ logger.log('warn', `Challenge port ${challengePort} is unavailable - it's already in use by another process. Consider configuring a different ACME port.`, {
508
+ port: challengePort,
509
+ error: (error as Error).message,
510
+ component: 'certificate-manager'
511
+ });
512
+ } catch (logError) {
513
+ // Silently handle logging errors
514
+ console.log(`[WARN] Challenge port ${challengePort} is unavailable - it's already in use by another process. Consider configuring a different ACME port.`);
515
+ }
516
+
517
+ // Provide a more informative and actionable error message
518
+ throw new Error(
519
+ `ACME HTTP-01 challenge port ${challengePort} is already in use by another process. ` +
520
+ `Please configure a different port using the acme.port setting (e.g., 8080).`
521
+ );
522
+ } else if (error.message && error.message.includes('EADDRINUSE')) {
523
+ // Some Node.js versions embed the error code in the message rather than the code property
524
+ try {
525
+ logger.log('warn', `Port ${challengePort} conflict detected: ${error.message}`, {
526
+ port: challengePort,
527
+ component: 'certificate-manager'
528
+ });
529
+ } catch (logError) {
530
+ // Silently handle logging errors
531
+ console.log(`[WARN] Port ${challengePort} conflict detected: ${error.message}`);
532
+ }
467
533
 
468
- // Provide a more informative error message
534
+ // More detailed error message with suggestions
469
535
  throw new Error(
470
- `Port ${challengePort} is already in use. ` +
471
- `If it's in use by an external process, configure a different port in the ACME settings. ` +
472
- `If it's in use by SmartProxy, there may be a route configuration issue.`
536
+ `ACME HTTP challenge port ${challengePort} conflict detected. ` +
537
+ `To resolve this issue, try one of these approaches:\n` +
538
+ `1. Configure a different port in ACME settings (acme.port)\n` +
539
+ `2. Add a regular route that uses port ${challengePort} before initializing the certificate manager\n` +
540
+ `3. Stop any other services that might be using port ${challengePort}`
473
541
  );
474
542
  }
475
543
 
476
- // Log and rethrow other errors
477
- logger.log('error', `Failed to add challenge route: ${error.message}`, {
478
- error: error.message,
479
- component: 'certificate-manager'
480
- });
544
+ // Log and rethrow other types of errors
545
+ try {
546
+ logger.log('error', `Failed to add challenge route: ${(error as Error).message}`, {
547
+ error: (error as Error).message,
548
+ component: 'certificate-manager'
549
+ });
550
+ } catch (logError) {
551
+ // Silently handle logging errors
552
+ console.log(`[ERROR] Failed to add challenge route: ${(error as Error).message}`);
553
+ }
481
554
  throw error;
482
555
  }
483
556
  }
@@ -487,7 +560,12 @@ export class SmartCertManager {
487
560
  */
488
561
  private async removeChallengeRoute(): Promise<void> {
489
562
  if (!this.challengeRouteActive) {
490
- logger.log('info', 'Challenge route not active, skipping removal', { component: 'certificate-manager' });
563
+ try {
564
+ logger.log('info', 'Challenge route not active, skipping removal', { component: 'certificate-manager' });
565
+ } catch (error) {
566
+ // Silently handle logging errors
567
+ console.log('[INFO] Challenge route not active, skipping removal');
568
+ }
491
569
  return;
492
570
  }
493
571
 
@@ -505,9 +583,19 @@ export class SmartCertManager {
505
583
  this.acmeStateManager.removeChallengeRoute('acme-challenge');
506
584
  }
507
585
 
508
- logger.log('info', 'ACME challenge route successfully removed', { component: 'certificate-manager' });
586
+ try {
587
+ logger.log('info', 'ACME challenge route successfully removed', { component: 'certificate-manager' });
588
+ } catch (error) {
589
+ // Silently handle logging errors
590
+ console.log('[INFO] ACME challenge route successfully removed');
591
+ }
509
592
  } catch (error) {
510
- logger.log('error', `Failed to remove challenge route: ${error.message}`, { error: error.message, component: 'certificate-manager' });
593
+ try {
594
+ logger.log('error', `Failed to remove challenge route: ${error.message}`, { error: error.message, component: 'certificate-manager' });
595
+ } catch (logError) {
596
+ // Silently handle logging errors
597
+ console.log(`[ERROR] Failed to remove challenge route: ${error.message}`);
598
+ }
511
599
  // Reset the flag even on error to avoid getting stuck
512
600
  this.challengeRouteActive = false;
513
601
  throw error;
@@ -46,10 +46,14 @@ export class PortManager {
46
46
  if (this.servers.has(port)) {
47
47
  // Port is already bound, just increment the reference count
48
48
  this.incrementPortRefCount(port);
49
- logger.log('debug', `PortManager: Port ${port} is already bound by SmartProxy, reusing binding`, {
50
- port,
51
- component: 'port-manager'
52
- });
49
+ try {
50
+ logger.log('debug', `PortManager: Port ${port} is already bound by SmartProxy, reusing binding`, {
51
+ port,
52
+ component: 'port-manager'
53
+ });
54
+ } catch (e) {
55
+ console.log(`[DEBUG] PortManager: Port ${port} is already bound by SmartProxy, reusing binding`);
56
+ }
53
57
  return;
54
58
  }
55
59
 
@@ -68,24 +72,34 @@ export class PortManager {
68
72
  // Delegate to route connection handler
69
73
  this.routeConnectionHandler.handleConnection(socket);
70
74
  }).on('error', (err: Error) => {
71
- logger.log('error', `Server Error on port ${port}: ${err.message}`, {
72
- port,
73
- error: err.message,
74
- component: 'port-manager'
75
- });
75
+ try {
76
+ logger.log('error', `Server Error on port ${port}: ${err.message}`, {
77
+ port,
78
+ error: err.message,
79
+ component: 'port-manager'
80
+ });
81
+ } catch (e) {
82
+ console.error(`[ERROR] Server Error on port ${port}: ${err.message}`);
83
+ }
76
84
  });
77
85
 
78
86
  // Start listening on the port
79
87
  return new Promise<void>((resolve, reject) => {
80
88
  server.listen(port, () => {
81
89
  const isHttpProxyPort = this.settings.useHttpProxy?.includes(port);
82
- logger.log('info', `SmartProxy -> OK: Now listening on port ${port}${
83
- isHttpProxyPort ? ' (HttpProxy forwarding enabled)' : ''
84
- }`, {
85
- port,
86
- isHttpProxyPort: !!isHttpProxyPort,
87
- component: 'port-manager'
88
- });
90
+ try {
91
+ logger.log('info', `SmartProxy -> OK: Now listening on port ${port}${
92
+ isHttpProxyPort ? ' (HttpProxy forwarding enabled)' : ''
93
+ }`, {
94
+ port,
95
+ isHttpProxyPort: !!isHttpProxyPort,
96
+ component: 'port-manager'
97
+ });
98
+ } catch (e) {
99
+ console.log(`[INFO] SmartProxy -> OK: Now listening on port ${port}${
100
+ isHttpProxyPort ? ' (HttpProxy forwarding enabled)' : ''
101
+ }`);
102
+ }
89
103
 
90
104
  // Store the server reference
91
105
  this.servers.set(port, server);
@@ -313,21 +313,6 @@ export class SmartProxy extends plugins.EventEmitter {
313
313
  return;
314
314
  }
315
315
 
316
- // Initialize certificate manager before starting servers
317
- await this.initializeCertificateManager();
318
-
319
- // Initialize and start HttpProxy if needed
320
- if (this.settings.useHttpProxy && this.settings.useHttpProxy.length > 0) {
321
- await this.httpProxyBridge.initialize();
322
-
323
- // Connect HttpProxy with certificate manager
324
- if (this.certManager) {
325
- this.certManager.setHttpProxy(this.httpProxyBridge.getHttpProxy());
326
- }
327
-
328
- await this.httpProxyBridge.start();
329
- }
330
-
331
316
  // Validate the route configuration
332
317
  const configWarnings = this.routeManager.validateConfiguration();
333
318
 
@@ -362,9 +347,25 @@ export class SmartProxy extends plugins.EventEmitter {
362
347
  }
363
348
  }
364
349
 
365
- // Start port listeners using the PortManager
350
+ // Initialize and start HttpProxy if needed - before port binding
351
+ if (this.settings.useHttpProxy && this.settings.useHttpProxy.length > 0) {
352
+ await this.httpProxyBridge.initialize();
353
+ await this.httpProxyBridge.start();
354
+ }
355
+
356
+ // Start port listeners using the PortManager BEFORE initializing certificate manager
357
+ // This ensures all required ports are bound and ready when adding ACME challenge routes
366
358
  await this.portManager.addPorts(listeningPorts);
367
359
 
360
+ // Initialize certificate manager AFTER port binding is complete
361
+ // This ensures the ACME challenge port is already bound and ready when needed
362
+ await this.initializeCertificateManager();
363
+
364
+ // Connect certificate manager with HttpProxy if both are available
365
+ if (this.certManager && this.httpProxyBridge.getHttpProxy()) {
366
+ this.certManager.setHttpProxy(this.httpProxyBridge.getHttpProxy());
367
+ }
368
+
368
369
  // Now that ports are listening, provision any required certificates
369
370
  if (this.certManager) {
370
371
  logger.log('info', 'Starting certificate provisioning now that ports are ready', { component: 'certificate-manager' });
@@ -521,7 +522,12 @@ export class SmartProxy extends plugins.EventEmitter {
521
522
  const challengeRouteExists = this.settings.routes.some(r => r.name === 'acme-challenge');
522
523
 
523
524
  if (!challengeRouteExists) {
524
- logger.log('info', 'Challenge route successfully removed from routes');
525
+ try {
526
+ logger.log('info', 'Challenge route successfully removed from routes');
527
+ } catch (error) {
528
+ // Silently handle logging errors
529
+ console.log('[INFO] Challenge route successfully removed from routes');
530
+ }
525
531
  return;
526
532
  }
527
533
 
@@ -530,7 +536,12 @@ export class SmartProxy extends plugins.EventEmitter {
530
536
  }
531
537
 
532
538
  const error = `Failed to verify challenge route removal after ${maxRetries} attempts`;
533
- logger.log('error', error);
539
+ try {
540
+ logger.log('error', error);
541
+ } catch (logError) {
542
+ // Silently handle logging errors
543
+ console.log(`[ERROR] ${error}`);
544
+ }
534
545
  throw new Error(error);
535
546
  }
536
547
 
@@ -559,31 +570,74 @@ export class SmartProxy extends plugins.EventEmitter {
559
570
  */
560
571
  public async updateRoutes(newRoutes: IRouteConfig[]): Promise<void> {
561
572
  return this.routeUpdateLock.runExclusive(async () => {
562
- logger.log('info', `Updating routes (${newRoutes.length} routes)`, { routeCount: newRoutes.length, component: 'route-manager' });
573
+ try {
574
+ logger.log('info', `Updating routes (${newRoutes.length} routes)`, {
575
+ routeCount: newRoutes.length,
576
+ component: 'route-manager'
577
+ });
578
+ } catch (error) {
579
+ // Silently handle logging errors
580
+ console.log(`[INFO] Updating routes (${newRoutes.length} routes)`);
581
+ }
563
582
 
564
583
  // Track port usage before and after updates
565
584
  const oldPortUsage = this.updatePortUsageMap(this.settings.routes);
566
585
  const newPortUsage = this.updatePortUsageMap(newRoutes);
567
586
 
587
+ // Get the lists of currently listening ports and new ports needed
588
+ const currentPorts = new Set(this.portManager.getListeningPorts());
589
+ const newPortsSet = new Set(newPortUsage.keys());
590
+
591
+ // Log the port usage for debugging
592
+ try {
593
+ logger.log('debug', `Current listening ports: ${Array.from(currentPorts).join(', ')}`, {
594
+ ports: Array.from(currentPorts),
595
+ component: 'smart-proxy'
596
+ });
597
+
598
+ logger.log('debug', `Ports needed for new routes: ${Array.from(newPortsSet).join(', ')}`, {
599
+ ports: Array.from(newPortsSet),
600
+ component: 'smart-proxy'
601
+ });
602
+ } catch (error) {
603
+ // Silently handle logging errors
604
+ console.log(`[DEBUG] Current listening ports: ${Array.from(currentPorts).join(', ')}`);
605
+ console.log(`[DEBUG] Ports needed for new routes: ${Array.from(newPortsSet).join(', ')}`);
606
+ }
607
+
568
608
  // Find orphaned ports - ports that no longer have any routes
569
609
  const orphanedPorts = this.findOrphanedPorts(oldPortUsage, newPortUsage);
570
610
 
571
- // Find new ports that need binding
572
- const currentPorts = new Set(this.portManager.getListeningPorts());
573
- const newPortsSet = new Set(newPortUsage.keys());
611
+ // Find new ports that need binding (only ports that we aren't already listening on)
574
612
  const newBindingPorts = Array.from(newPortsSet).filter(p => !currentPorts.has(p));
613
+
614
+ // Check for ACME challenge port to give it special handling
615
+ const acmePort = this.settings.acme?.port || 80;
616
+ const acmePortNeeded = newPortsSet.has(acmePort);
617
+ const acmePortListed = newBindingPorts.includes(acmePort);
618
+
619
+ if (acmePortNeeded && acmePortListed) {
620
+ try {
621
+ logger.log('info', `Adding ACME challenge port ${acmePort} to routes`, {
622
+ port: acmePort,
623
+ component: 'smart-proxy'
624
+ });
625
+ } catch (error) {
626
+ // Silently handle logging errors
627
+ console.log(`[INFO] Adding ACME challenge port ${acmePort} to routes`);
628
+ }
629
+ }
575
630
 
576
- // Get existing routes that use NFTables
631
+ // Get existing routes that use NFTables and update them
577
632
  const oldNfTablesRoutes = this.settings.routes.filter(
578
633
  r => r.action.forwardingEngine === 'nftables'
579
634
  );
580
635
 
581
- // Get new routes that use NFTables
582
636
  const newNfTablesRoutes = newRoutes.filter(
583
637
  r => r.action.forwardingEngine === 'nftables'
584
638
  );
585
639
 
586
- // Find routes to remove, update, or add
640
+ // Update existing NFTables routes
587
641
  for (const oldRoute of oldNfTablesRoutes) {
588
642
  const newRoute = newNfTablesRoutes.find(r => r.name === oldRoute.name);
589
643
 
@@ -596,7 +650,7 @@ export class SmartProxy extends plugins.EventEmitter {
596
650
  }
597
651
  }
598
652
 
599
- // Find new routes to add
653
+ // Add new NFTables routes
600
654
  for (const newRoute of newNfTablesRoutes) {
601
655
  const oldRoute = oldNfTablesRoutes.find(r => r.name === newRoute.name);
602
656
 
@@ -609,22 +663,63 @@ export class SmartProxy extends plugins.EventEmitter {
609
663
  // Update routes in RouteManager
610
664
  this.routeManager.updateRoutes(newRoutes);
611
665
 
612
- // Release orphaned ports first
666
+ // Release orphaned ports first to free resources
613
667
  if (orphanedPorts.length > 0) {
614
- logger.log('info', `Releasing ${orphanedPorts.length} orphaned ports: ${orphanedPorts.join(', ')}`, {
615
- ports: orphanedPorts,
616
- component: 'smart-proxy'
617
- });
668
+ try {
669
+ logger.log('info', `Releasing ${orphanedPorts.length} orphaned ports: ${orphanedPorts.join(', ')}`, {
670
+ ports: orphanedPorts,
671
+ component: 'smart-proxy'
672
+ });
673
+ } catch (error) {
674
+ // Silently handle logging errors
675
+ console.log(`[INFO] Releasing ${orphanedPorts.length} orphaned ports: ${orphanedPorts.join(', ')}`);
676
+ }
618
677
  await this.portManager.removePorts(orphanedPorts);
619
678
  }
620
679
 
621
- // Add new ports
680
+ // Add new ports if needed
622
681
  if (newBindingPorts.length > 0) {
623
- logger.log('info', `Binding to ${newBindingPorts.length} new ports: ${newBindingPorts.join(', ')}`, {
624
- ports: newBindingPorts,
625
- component: 'smart-proxy'
626
- });
627
- await this.portManager.addPorts(newBindingPorts);
682
+ try {
683
+ logger.log('info', `Binding to ${newBindingPorts.length} new ports: ${newBindingPorts.join(', ')}`, {
684
+ ports: newBindingPorts,
685
+ component: 'smart-proxy'
686
+ });
687
+ } catch (error) {
688
+ // Silently handle logging errors
689
+ console.log(`[INFO] Binding to ${newBindingPorts.length} new ports: ${newBindingPorts.join(', ')}`);
690
+ }
691
+
692
+ // Handle port binding with improved error recovery
693
+ try {
694
+ await this.portManager.addPorts(newBindingPorts);
695
+ } catch (error) {
696
+ // Special handling for port binding errors
697
+ // This provides better diagnostics for ACME challenge port conflicts
698
+ if ((error as any).code === 'EADDRINUSE') {
699
+ const port = (error as any).port || newBindingPorts[0];
700
+ const isAcmePort = port === acmePort;
701
+
702
+ if (isAcmePort) {
703
+ try {
704
+ logger.log('warn', `Could not bind to ACME challenge port ${port}. It may be in use by another application.`, {
705
+ port,
706
+ component: 'smart-proxy'
707
+ });
708
+ } catch (logError) {
709
+ console.log(`[WARN] Could not bind to ACME challenge port ${port}. It may be in use by another application.`);
710
+ }
711
+
712
+ // Re-throw with more helpful message
713
+ throw new Error(
714
+ `ACME challenge port ${port} is already in use by another application. ` +
715
+ `Configure a different port in settings.acme.port (e.g., 8080) or free up port ${port}.`
716
+ );
717
+ }
718
+ }
719
+
720
+ // Re-throw the original error for other cases
721
+ throw error;
722
+ }
628
723
  }
629
724
 
630
725
  // Update settings with the new routes
@@ -646,6 +741,22 @@ export class SmartProxy extends plugins.EventEmitter {
646
741
  // Store global state before stopping
647
742
  this.globalChallengeRouteActive = existingState.challengeRouteActive;
648
743
 
744
+ // Only stop the cert manager if absolutely necessary
745
+ // First check if there's an ACME route on the same port already
746
+ const acmePort = existingAcmeOptions?.port || 80;
747
+ const acmePortInUse = newPortUsage.has(acmePort) && newPortUsage.get(acmePort)!.size > 0;
748
+
749
+ try {
750
+ logger.log('debug', `ACME port ${acmePort} ${acmePortInUse ? 'is' : 'is not'} already in use by other routes`, {
751
+ port: acmePort,
752
+ inUse: acmePortInUse,
753
+ component: 'smart-proxy'
754
+ });
755
+ } catch (error) {
756
+ // Silently handle logging errors
757
+ console.log(`[DEBUG] ACME port ${acmePort} ${acmePortInUse ? 'is' : 'is not'} already in use by other routes`);
758
+ }
759
+
649
760
  await this.certManager.stop();
650
761
 
651
762
  // Verify the challenge route has been properly removed
@@ -721,11 +832,16 @@ export class SmartProxy extends plugins.EventEmitter {
721
832
 
722
833
  // Log port usage for debugging
723
834
  for (const [port, routes] of portUsage.entries()) {
724
- logger.log('debug', `Port ${port} is used by ${routes.size} routes: ${Array.from(routes).join(', ')}`, {
725
- port,
726
- routeCount: routes.size,
727
- component: 'smart-proxy'
728
- });
835
+ try {
836
+ logger.log('debug', `Port ${port} is used by ${routes.size} routes: ${Array.from(routes).join(', ')}`, {
837
+ port,
838
+ routeCount: routes.size,
839
+ component: 'smart-proxy'
840
+ });
841
+ } catch (error) {
842
+ // Silently handle logging errors
843
+ console.log(`[DEBUG] Port ${port} is used by ${routes.size} routes: ${Array.from(routes).join(', ')}`);
844
+ }
729
845
  }
730
846
 
731
847
  return portUsage;
@@ -740,10 +856,15 @@ export class SmartProxy extends plugins.EventEmitter {
740
856
  for (const [port, routes] of oldUsage.entries()) {
741
857
  if (!newUsage.has(port) || newUsage.get(port)!.size === 0) {
742
858
  orphanedPorts.push(port);
743
- logger.log('info', `Port ${port} no longer has any associated routes, will be released`, {
744
- port,
745
- component: 'smart-proxy'
746
- });
859
+ try {
860
+ logger.log('info', `Port ${port} no longer has any associated routes, will be released`, {
861
+ port,
862
+ component: 'smart-proxy'
863
+ });
864
+ } catch (error) {
865
+ // Silently handle logging errors
866
+ console.log(`[INFO] Port ${port} no longer has any associated routes, will be released`);
867
+ }
747
868
  }
748
869
  }
749
870