dynamic-self-register-proxy 1.0.4 → 1.0.5

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 (2) hide show
  1. package/package.json +1 -1
  2. package/proxy.js +134 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dynamic-self-register-proxy",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Dynamic reverse proxy with self-registration API - applications can register themselves and receive an automatically assigned port",
5
5
  "main": "proxy-client.js",
6
6
  "bin": {
package/proxy.js CHANGED
@@ -9,7 +9,7 @@ app.use(express.json());
9
9
  // ============================================
10
10
  // CONFIGURATION
11
11
  // ============================================
12
- const PROXY_PORT = process.env.PROXY_PORT || 3005;
12
+ const PROXY_PORT = process.env.PROXY_PORT || 3000;
13
13
  const INTERNAL_PORT_START = 4000;
14
14
  const INTERNAL_PORT_END = 5000;
15
15
  const HEALTH_CHECK_INTERVAL = process.env.HEALTH_CHECK_INTERVAL || 30000; // 30 secondes par défaut
@@ -413,6 +413,52 @@ app.get('/proxy/routes', (req, res) => {
413
413
  });
414
414
  });
415
415
 
416
+ /**
417
+ * POST /proxy/check
418
+ * Déclenche manuellement un health check pour une route spécifique
419
+ * Body: { path: "/myapp" }
420
+ */
421
+ app.post('/proxy/check', async (req, res) => {
422
+ const { path } = req.body;
423
+
424
+ if (!path) {
425
+ return res.status(400).json({
426
+ success: false,
427
+ error: 'Path is required'
428
+ });
429
+ }
430
+
431
+ const normalizedPath = path.startsWith('/') ? path : `/${path}`;
432
+ const route = registry.routes.get(normalizedPath);
433
+
434
+ if (!route) {
435
+ return res.status(404).json({
436
+ success: false,
437
+ error: 'Path not found'
438
+ });
439
+ }
440
+
441
+ console.log(`[MANUAL HEALTH CHECK] Checking ${normalizedPath}...`);
442
+ const isHealthy = await checkServerHealth(normalizedPath, route);
443
+
444
+ if (!isHealthy) {
445
+ await unregisterServer(normalizedPath);
446
+ return res.json({
447
+ success: true,
448
+ path: normalizedPath,
449
+ healthy: false,
450
+ message: 'Server was unhealthy and has been removed'
451
+ });
452
+ }
453
+
454
+ res.json({
455
+ success: true,
456
+ path: normalizedPath,
457
+ healthy: true,
458
+ message: 'Server is healthy'
459
+ });
460
+ });
461
+
416
462
  /**
417
463
  * GET /proxy/health
418
464
  * Health check du proxy
@@ -581,6 +627,40 @@ app.get('/', (req, res) => {
581
627
  .service-link:hover {
582
628
  opacity: 0.9;
583
629
  }
630
+ .service-actions {
631
+ display: flex;
632
+ gap: 1rem;
633
+ align-items: center;
634
+ }
635
+ .check-btn {
636
+ background: rgba(255, 255, 255, 0.1);
637
+ color: #e4e4e7;
638
+ border: 1px solid rgba(255, 255, 255, 0.2);
639
+ padding: 0.5rem 1rem;
640
+ border-radius: 8px;
641
+ cursor: pointer;
642
+ font-size: 0.85rem;
643
+ font-weight: 500;
644
+ transition: all 0.2s;
645
+ }
646
+ .check-btn:hover {
647
+ background: rgba(255, 255, 255, 0.15);
648
+ border-color: rgba(255, 255, 255, 0.3);
649
+ }
650
+ .check-btn.loading {
651
+ opacity: 0.5;
652
+ cursor: not-allowed;
653
+ }
654
+ .check-btn.healthy {
655
+ background: rgba(16, 185, 129, 0.2);
656
+ border-color: rgba(16, 185, 129, 0.4);
657
+ color: #10b981;
658
+ }
659
+ .check-btn.unhealthy {
660
+ background: rgba(239, 68, 68, 0.2);
661
+ border-color: rgba(239, 68, 68, 0.4);
662
+ color: #ef4444;
663
+ }
584
664
  .empty-state {
585
665
  text-align: center;
586
666
  padding: 4rem 2rem;
@@ -648,9 +728,14 @@ app.get('/', (req, res) => {
648
728
  <span>Port interne: ${route.port}</span>
649
729
  <span>Enregistré: ${new Date(route.registeredAt).toLocaleString('fr-FR')}</span>
650
730
  </div>
651
- <a href="${escapeHtml(route.path)}" class="service-link">
652
- Accéder au service
653
- </a>
731
+ <div class="service-actions">
732
+ <a href="${escapeHtml(route.path)}" class="service-link">
733
+ Accéder au service →
734
+ </a>
735
+ <button onclick="checkHealth('${escapeHtml(route.path)}', this)" class="check-btn">
736
+ Vérifier la santé
737
+ </button>
738
+ </div>
654
739
  </div>
655
740
  `).join('')}
656
741
  </div>
@@ -666,6 +751,51 @@ app.get('/', (req, res) => {
666
751
  <p>API: <a href="/proxy/routes">/proxy/routes</a> | <a href="/proxy/health">/proxy/health</a></p>
667
752
  </footer>
668
753
  </div>
754
+
755
+ <script>
756
+ async function checkHealth(path, btn) {
757
+ if (btn.classList.contains('loading')) return;
758
+
759
+ const originalText = btn.innerText;
760
+ btn.innerText = 'Vérification...';
761
+ btn.classList.add('loading');
762
+
763
+ try {
764
+ const response = await fetch('/proxy/check', {
765
+ method: 'POST',
766
+ headers: { 'Content-Type': 'application/json' },
767
+ body: JSON.stringify({ path })
768
+ });
769
+
770
+ const data = await response.json();
771
+
772
+ if (data.healthy) {
773
+ btn.innerText = '✅ Sain';
774
+ btn.classList.remove('loading');
775
+ btn.classList.add('healthy');
776
+ setTimeout(() => {
777
+ btn.innerText = originalText;
778
+ btn.classList.remove('healthy');
779
+ }, 3000);
780
+ } else {
781
+ btn.innerText = '❌ Hors ligne';
782
+ btn.classList.remove('loading');
783
+ btn.classList.add('unhealthy');
784
+
785
+ // Si le serveur a été supprimé, on rafraîchit la liste après un court délai
786
+ setTimeout(() => {
787
+ window.location.reload();
788
+ }, 2000);
789
+ }
790
+ } catch (error) {
791
+ btn.innerText = '⚠️ Erreur';
792
+ btn.classList.remove('loading');
793
+ setTimeout(() => {
794
+ btn.innerText = originalText;
795
+ }, 3000);
796
+ }
797
+ }
798
+ </script>
669
799
  </body>
670
800
  </html>
671
801
  `.trim();