dynamic-self-register-proxy 1.0.2 → 1.0.4
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.
- package/README.md +45 -1
- package/package.json +1 -1
- package/proxy.js +49 -3
package/README.md
CHANGED
|
@@ -75,10 +75,44 @@ app.listen(port);
|
|
|
75
75
|
http://localhost:3000/myapp/ → votre application sur le port 4000
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
+
## Page d'accueil
|
|
79
|
+
|
|
80
|
+
L'URL racine `/` affiche une page listant tous les serveurs enregistrés avec des liens pour y accéder.
|
|
81
|
+
|
|
82
|
+
- **Navigateurs** (`Accept: text/html`) → Page HTML avec interface moderne
|
|
83
|
+
- **Clients API** (`Accept: application/json`) → Réponse JSON
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Accès navigateur : ouvrir http://localhost:3000/
|
|
87
|
+
|
|
88
|
+
# Accès API
|
|
89
|
+
curl -H "Accept: application/json" http://localhost:3000/
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Réponse JSON :**
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"status": "healthy",
|
|
96
|
+
"uptime": 3600,
|
|
97
|
+
"count": 2,
|
|
98
|
+
"routes": [
|
|
99
|
+
{
|
|
100
|
+
"path": "/api",
|
|
101
|
+
"port": 4000,
|
|
102
|
+
"name": "API Server",
|
|
103
|
+
"registeredAt": "2026-01-27T10:00:00.000Z",
|
|
104
|
+
"target": "http://localhost:4000"
|
|
105
|
+
}
|
|
106
|
+
],
|
|
107
|
+
"availablePorts": 998
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
78
111
|
## API du Proxy
|
|
79
112
|
|
|
80
113
|
| Endpoint | Méthode | Description |
|
|
81
114
|
|----------|---------|-------------|
|
|
115
|
+
| `/` | GET | Page d'accueil (HTML ou JSON selon Accept header) |
|
|
82
116
|
| `/proxy/register` | POST | Enregistre une nouvelle route |
|
|
83
117
|
| `/proxy/unregister` | DELETE | Supprime une route |
|
|
84
118
|
| `/proxy/routes` | GET | Liste toutes les routes |
|
|
@@ -332,6 +366,7 @@ proxy.setupHealthRoute(app, {
|
|
|
332
366
|
|
|
333
367
|
### Comportement
|
|
334
368
|
|
|
369
|
+
- **Période de grâce** : les nouveaux serveurs ont **60 secondes** après l'enregistrement avant d'être vérifiés (laisse le temps au serveur de démarrer)
|
|
335
370
|
- Le proxy vérifie tous les serveurs toutes les **30 secondes** (par défaut)
|
|
336
371
|
- Timeout de **5 secondes** par requête de health check
|
|
337
372
|
- Si la réponse n'est pas un code **200**, le serveur est automatiquement désenregistré
|
|
@@ -388,7 +423,8 @@ Dans votre fichier de configuration Claude Desktop (`claude_desktop_config.json`
|
|
|
388
423
|
"env": {
|
|
389
424
|
"PROXY_PORT": "8080",
|
|
390
425
|
"HEALTH_CHECK_INTERVAL": "60000",
|
|
391
|
-
"HEALTH_CHECK_TIMEOUT": "10000"
|
|
426
|
+
"HEALTH_CHECK_TIMEOUT": "10000",
|
|
427
|
+
"HEALTH_CHECK_GRACE_PERIOD": "120000"
|
|
392
428
|
}
|
|
393
429
|
}
|
|
394
430
|
}
|
|
@@ -402,6 +438,7 @@ Dans votre fichier de configuration Claude Desktop (`claude_desktop_config.json`
|
|
|
402
438
|
| `PROXY_PORT` | `3000` | Port d'écoute du proxy |
|
|
403
439
|
| `HEALTH_CHECK_INTERVAL` | `30000` | Intervalle du health check polling (ms) |
|
|
404
440
|
| `HEALTH_CHECK_TIMEOUT` | `5000` | Timeout pour chaque health check (ms) |
|
|
441
|
+
| `HEALTH_CHECK_GRACE_PERIOD` | `60000` | Période de grâce pour les nouveaux serveurs (ms) |
|
|
405
442
|
| `PROXY_URL` | `http://localhost:3000` | URL du proxy (pour les apps) |
|
|
406
443
|
| `APP_PATH` | `/example` | Chemin de l'application |
|
|
407
444
|
| `APP_NAME` | `Example App` | Nom de l'application |
|
|
@@ -417,6 +454,13 @@ const INTERNAL_PORT_START = 4000;
|
|
|
417
454
|
const INTERNAL_PORT_END = 5000;
|
|
418
455
|
```
|
|
419
456
|
|
|
457
|
+
## Fonctionnalités
|
|
458
|
+
|
|
459
|
+
- **Attribution sécurisée des ports** : utilisation d'un mutex pour éviter les conflits lors d'enregistrements simultanés
|
|
460
|
+
- **Période de grâce** : les nouveaux serveurs ne sont pas vérifiés immédiatement, leur laissant le temps de démarrer
|
|
461
|
+
- **Négociation de contenu** : l'URL racine `/` retourne HTML pour les navigateurs, JSON pour les API
|
|
462
|
+
- **Health check automatique** : désenregistrement automatique des serveurs non répondants
|
|
463
|
+
|
|
420
464
|
## Limitations
|
|
421
465
|
|
|
422
466
|
- Les routes sont stockées en mémoire (perdues au redémarrage du proxy)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dynamic-self-register-proxy",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
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
|
@@ -14,6 +14,7 @@ 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
|
|
16
16
|
const HEALTH_CHECK_TIMEOUT = process.env.HEALTH_CHECK_TIMEOUT || 5000; // 5 secondes timeout
|
|
17
|
+
const HEALTH_CHECK_GRACE_PERIOD = process.env.HEALTH_CHECK_GRACE_PERIOD || 60000; // 60 secondes de grâce pour les nouveaux serveurs
|
|
17
18
|
|
|
18
19
|
// ============================================
|
|
19
20
|
// REGISTRY - Stockage des routes en mémoire
|
|
@@ -166,19 +167,36 @@ async function unregisterServer(path) {
|
|
|
166
167
|
}
|
|
167
168
|
}
|
|
168
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Vérifie si un serveur est encore dans sa période de grâce
|
|
172
|
+
* @param {object} route - Les informations de la route
|
|
173
|
+
* @returns {boolean} - true si le serveur est encore en période de grâce
|
|
174
|
+
*/
|
|
175
|
+
function isInGracePeriod(route) {
|
|
176
|
+
const registeredAt = new Date(route.registeredAt).getTime();
|
|
177
|
+
const now = Date.now();
|
|
178
|
+
return (now - registeredAt) < HEALTH_CHECK_GRACE_PERIOD;
|
|
179
|
+
}
|
|
180
|
+
|
|
169
181
|
/**
|
|
170
182
|
* Effectue un health check sur tous les serveurs enregistrés
|
|
183
|
+
* Les serveurs récemment enregistrés (dans la période de grâce) sont ignorés
|
|
171
184
|
*/
|
|
172
185
|
async function performHealthChecks() {
|
|
173
186
|
if (registry.routes.size === 0) {
|
|
174
187
|
return;
|
|
175
188
|
}
|
|
176
189
|
|
|
177
|
-
console.log(`[HEALTH CHECK] Checking ${registry.routes.size} registered server(s)...`);
|
|
178
|
-
|
|
179
190
|
const checks = [];
|
|
191
|
+
let skippedCount = 0;
|
|
180
192
|
|
|
181
193
|
for (const [path, route] of registry.routes.entries()) {
|
|
194
|
+
// Ignore les serveurs en période de grâce
|
|
195
|
+
if (isInGracePeriod(route)) {
|
|
196
|
+
skippedCount++;
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
|
|
182
200
|
checks.push(
|
|
183
201
|
checkServerHealth(path, route).then(isHealthy => ({
|
|
184
202
|
path,
|
|
@@ -188,6 +206,16 @@ async function performHealthChecks() {
|
|
|
188
206
|
);
|
|
189
207
|
}
|
|
190
208
|
|
|
209
|
+
// Si tous les serveurs sont en période de grâce, pas de log
|
|
210
|
+
if (checks.length === 0) {
|
|
211
|
+
if (skippedCount > 0) {
|
|
212
|
+
console.log(`[HEALTH CHECK] ${skippedCount} server(s) in grace period, skipping checks`);
|
|
213
|
+
}
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
console.log(`[HEALTH CHECK] Checking ${checks.length} server(s)...${skippedCount > 0 ? ` (${skippedCount} in grace period)` : ''}`);
|
|
218
|
+
|
|
191
219
|
const results = await Promise.all(checks);
|
|
192
220
|
|
|
193
221
|
for (const { path, isHealthy } of results) {
|
|
@@ -401,6 +429,7 @@ app.get('/proxy/health', (req, res) => {
|
|
|
401
429
|
/**
|
|
402
430
|
* GET /
|
|
403
431
|
* Page d'accueil listant tous les serveurs disponibles
|
|
432
|
+
* Retourne du JSON si le client l'accepte (API), sinon du HTML (navigateur)
|
|
404
433
|
*/
|
|
405
434
|
app.get('/', (req, res) => {
|
|
406
435
|
const routes = [];
|
|
@@ -409,13 +438,29 @@ app.get('/', (req, res) => {
|
|
|
409
438
|
path,
|
|
410
439
|
port: value.port,
|
|
411
440
|
name: value.name,
|
|
412
|
-
registeredAt: value.registeredAt
|
|
441
|
+
registeredAt: value.registeredAt,
|
|
442
|
+
target: `http://localhost:${value.port}`
|
|
413
443
|
});
|
|
414
444
|
});
|
|
415
445
|
|
|
416
446
|
// Tri par nom
|
|
417
447
|
routes.sort((a, b) => a.name.localeCompare(b.name));
|
|
418
448
|
|
|
449
|
+
// Si le client accepte JSON (et pas spécifiquement HTML), retourne du JSON
|
|
450
|
+
const acceptHeader = req.get('Accept') || '';
|
|
451
|
+
const wantsJson = acceptHeader.includes('application/json') ||
|
|
452
|
+
(acceptHeader.includes('*/*') && !acceptHeader.includes('text/html'));
|
|
453
|
+
|
|
454
|
+
if (wantsJson) {
|
|
455
|
+
return res.json({
|
|
456
|
+
status: 'healthy',
|
|
457
|
+
uptime: process.uptime(),
|
|
458
|
+
count: routes.length,
|
|
459
|
+
routes,
|
|
460
|
+
availablePorts: (INTERNAL_PORT_END - INTERNAL_PORT_START) - registry.usedPorts.size
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
419
464
|
const html = `
|
|
420
465
|
<!DOCTYPE html>
|
|
421
466
|
<html lang="fr">
|
|
@@ -728,6 +773,7 @@ app.listen(PROXY_PORT, () => {
|
|
|
728
773
|
console.log(`Listening on port ${PROXY_PORT}`);
|
|
729
774
|
console.log(`Internal ports range: ${INTERNAL_PORT_START}-${INTERNAL_PORT_END}`);
|
|
730
775
|
console.log(`Health check interval: ${HEALTH_CHECK_INTERVAL}ms`);
|
|
776
|
+
console.log(`Health check grace period: ${HEALTH_CHECK_GRACE_PERIOD}ms`);
|
|
731
777
|
console.log('');
|
|
732
778
|
console.log('API Endpoints:');
|
|
733
779
|
console.log(' POST /proxy/register - Register a new route');
|