@imenam/self-register-proxy 1.0.46 → 1.0.48
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 +6 -0
- package/config.js +72 -72
- package/meta-config.js +336 -336
- package/package.json +2 -3
- package/routes/metaConfig.js +180 -180
- package/routes/registration.js +240 -240
- package/services/healthCheck.js +95 -95
- package/services/portManager.js +137 -137
- package/services/proxyRouter.js +99 -99
- package/services/registry.js +41 -41
- package/terminal-server.js +154 -154
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imenam/self-register-proxy",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.48",
|
|
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": {
|
|
@@ -28,8 +28,7 @@
|
|
|
28
28
|
"scripts": {
|
|
29
29
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
30
30
|
"start": "node proxy.js",
|
|
31
|
-
"example": "node example-app.js"
|
|
32
|
-
"release": "npm version patch && npm publish --access public && git push origin main --follow-tags"
|
|
31
|
+
"example": "node example-app.js"
|
|
33
32
|
},
|
|
34
33
|
"keywords": [
|
|
35
34
|
"proxy",
|
package/routes/metaConfig.js
CHANGED
|
@@ -1,180 +1,180 @@
|
|
|
1
|
-
const { Router } = require('express');
|
|
2
|
-
const metaConfig = require('../meta-config');
|
|
3
|
-
const { requireAuth } = require('../services/auth');
|
|
4
|
-
const { registry } = require('../services/registry');
|
|
5
|
-
const { renderMetaConfigs } = require('../views/metaConfigs');
|
|
6
|
-
const { PROXY_NAME, OPENCODE_CLEAN_UP, ADMIN_PASSWORD } = require('../config');
|
|
7
|
-
|
|
8
|
-
const router = Router();
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* GET /proxy/mcp-configurations
|
|
12
|
-
* Découvre les configurations disponibles auprès de tous les MCPs enregistrés
|
|
13
|
-
*/
|
|
14
|
-
router.get('/proxy/mcp-configurations', requireAuth, async (req, res) => {
|
|
15
|
-
try {
|
|
16
|
-
const results = await metaConfig.discoverConfigurations(registry.routes);
|
|
17
|
-
const compatible = results.filter(r => r.configurations !== null);
|
|
18
|
-
const incompatible = results.filter(r => r.configurations === null);
|
|
19
|
-
|
|
20
|
-
res.json({ success: true, compatible: compatible.length, incompatible: incompatible.length, results });
|
|
21
|
-
} catch (error) {
|
|
22
|
-
console.error('[META-CONFIG] Discovery error:', error.message);
|
|
23
|
-
res.status(500).json({ success: false, error: error.message });
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* GET /proxy/meta-configs
|
|
29
|
-
* Liste toutes les méta-configurations sauvegardées
|
|
30
|
-
*/
|
|
31
|
-
router.get('/proxy/meta-configs', requireAuth, (req, res) => {
|
|
32
|
-
const data = metaConfig.getAll();
|
|
33
|
-
res.json({ success: true, metaConfigs: data.metaConfigs, activeMetaConfig: data.activeMetaConfig });
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* POST /proxy/meta-configs
|
|
38
|
-
* Crée une nouvelle méta-configuration
|
|
39
|
-
*/
|
|
40
|
-
router.post('/proxy/meta-configs', requireAuth, (req, res) => {
|
|
41
|
-
const { id, name, description, mappings } = req.body;
|
|
42
|
-
|
|
43
|
-
if (!id || !name) {
|
|
44
|
-
return res.status(400).json({ success: false, error: 'id and name are required' });
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
const created = metaConfig.create(id, name, description, mappings);
|
|
49
|
-
console.log(`[META-CONFIG] Created: ${id}`);
|
|
50
|
-
res.json({ success: true, metaConfig: { id, ...created } });
|
|
51
|
-
} catch (error) {
|
|
52
|
-
const status = error.message.includes('already exists') ? 409 : 500;
|
|
53
|
-
res.status(status).json({ success: false, error: error.message });
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* PUT /proxy/meta-configs/:id
|
|
59
|
-
* Met à jour une méta-configuration existante
|
|
60
|
-
*/
|
|
61
|
-
router.put('/proxy/meta-configs/:id', requireAuth, (req, res) => {
|
|
62
|
-
const { id } = req.params;
|
|
63
|
-
const { name, description, mappings } = req.body;
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
const updated = metaConfig.update(id, { name, description, mappings });
|
|
67
|
-
console.log(`[META-CONFIG] Updated: ${id}`);
|
|
68
|
-
res.json({ success: true, metaConfig: { id, ...updated } });
|
|
69
|
-
} catch (error) {
|
|
70
|
-
const status = error.message.includes('not found') ? 404 : 500;
|
|
71
|
-
res.status(status).json({ success: false, error: error.message });
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* DELETE /proxy/meta-configs/:id
|
|
77
|
-
* Supprime une méta-configuration
|
|
78
|
-
*/
|
|
79
|
-
router.delete('/proxy/meta-configs/:id', requireAuth, (req, res) => {
|
|
80
|
-
const { id } = req.params;
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
metaConfig.remove(id);
|
|
84
|
-
console.log(`[META-CONFIG] Deleted: ${id}`);
|
|
85
|
-
res.json({ success: true, deleted: id });
|
|
86
|
-
} catch (error) {
|
|
87
|
-
const status = error.message.includes('not found') ? 404 : 500;
|
|
88
|
-
res.status(status).json({ success: false, error: error.message });
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* POST /proxy/meta-configs/:id/apply
|
|
94
|
-
* Applique une méta-configuration
|
|
95
|
-
*/
|
|
96
|
-
router.post('/proxy/meta-configs/:id/apply', requireAuth, async (req, res) => {
|
|
97
|
-
const { id } = req.params;
|
|
98
|
-
|
|
99
|
-
try {
|
|
100
|
-
const result = await metaConfig.applyMetaConfig(id, registry.routes);
|
|
101
|
-
console.log(`[META-CONFIG] Applied "${id}": ${result.success ? 'all OK' : 'some failures'}`);
|
|
102
|
-
res.json({ success: result.success, warnings: result.warnings, metaConfigId: id, results: result.results });
|
|
103
|
-
} catch (error) {
|
|
104
|
-
const status = error.message.includes('not found') ? 404 : 500;
|
|
105
|
-
res.status(status).json({ success: false, error: error.message });
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* GET /proxy/meta-configs/active/sync
|
|
111
|
-
* Vérifie si les configurations actives des MCPs correspondent à la méta-config active
|
|
112
|
-
*/
|
|
113
|
-
router.get('/proxy/meta-configs/active/sync', requireAuth, async (req, res) => {
|
|
114
|
-
const activeId = metaConfig.getActive();
|
|
115
|
-
console.log(`[META-CONFIG SYNC] activeId = ${JSON.stringify(activeId)}`);
|
|
116
|
-
|
|
117
|
-
if (!activeId) {
|
|
118
|
-
return res.json({ synced: true, activeMetaConfigId: null });
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const activeCfg = metaConfig.getById(activeId);
|
|
122
|
-
console.log(`[META-CONFIG SYNC] mappings = ${JSON.stringify(activeCfg?.mappings)}`);
|
|
123
|
-
if (!activeCfg) {
|
|
124
|
-
return res.json({ synced: true, activeMetaConfigId: null });
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
try {
|
|
128
|
-
const results = await metaConfig.discoverConfigurations(registry.routes);
|
|
129
|
-
console.log(`[META-CONFIG SYNC] discoverConfigurations results:`);
|
|
130
|
-
results.forEach(r => {
|
|
131
|
-
if (r.configurations) {
|
|
132
|
-
const active = r.configurations.find(c => c.active);
|
|
133
|
-
console.log(` ${r.path} → configs: [${r.configurations.map(c => `${c.id}${c.active ? '*' : ''}`).join(', ')}] — active: ${JSON.stringify(active?.id ?? null)}`);
|
|
134
|
-
} else {
|
|
135
|
-
console.log(` ${r.path} → error: ${r.error}`);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
const conflicts = [];
|
|
140
|
-
|
|
141
|
-
for (const [mcpPath, expectedConfigId] of Object.entries(activeCfg.mappings)) {
|
|
142
|
-
const mcpResult = results.find(r => r.path === mcpPath);
|
|
143
|
-
if (!mcpResult) {
|
|
144
|
-
console.log(` [META-CONFIG SYNC] ${mcpPath} → MCP non trouvé dans les résultats, ignoré`);
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
if (!mcpResult.configurations) {
|
|
148
|
-
console.log(` [META-CONFIG SYNC] ${mcpPath} → pas de configurations (erreur: ${mcpResult.error}), ignoré`);
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const activeConfig = mcpResult.configurations.find(c => c.active);
|
|
153
|
-
const actualConfigId = activeConfig ? activeConfig.id : null;
|
|
154
|
-
|
|
155
|
-
console.log(` [META-CONFIG SYNC] ${mcpPath} → attendu: ${JSON.stringify(expectedConfigId)} | actuel: ${JSON.stringify(actualConfigId)} | match: ${actualConfigId === expectedConfigId}`);
|
|
156
|
-
|
|
157
|
-
if (actualConfigId !== expectedConfigId) {
|
|
158
|
-
conflicts.push({ path: mcpPath, expected: expectedConfigId, actual: actualConfigId });
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
console.log(`[META-CONFIG SYNC] synced=${conflicts.length === 0}, conflicts=${JSON.stringify(conflicts)}`);
|
|
163
|
-
res.json({ synced: conflicts.length === 0, activeMetaConfigId: activeId, conflicts });
|
|
164
|
-
} catch (error) {
|
|
165
|
-
console.error('[META-CONFIG SYNC] Erreur:', error.message);
|
|
166
|
-
res.status(500).json({ success: false, error: error.message });
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* GET /proxy/meta-configs-ui
|
|
172
|
-
* Interface de gestion des méta-configurations
|
|
173
|
-
*/
|
|
174
|
-
router.get('/proxy/meta-configs-ui', requireAuth, (req, res) => {
|
|
175
|
-
const data = metaConfig.getAll();
|
|
176
|
-
const html = renderMetaConfigs(PROXY_NAME, data.metaConfigs, data.activeMetaConfig, OPENCODE_CLEAN_UP, !!ADMIN_PASSWORD);
|
|
177
|
-
res.type('html').send(html);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
module.exports = router;
|
|
1
|
+
const { Router } = require('express');
|
|
2
|
+
const metaConfig = require('../meta-config');
|
|
3
|
+
const { requireAuth } = require('../services/auth');
|
|
4
|
+
const { registry } = require('../services/registry');
|
|
5
|
+
const { renderMetaConfigs } = require('../views/metaConfigs');
|
|
6
|
+
const { PROXY_NAME, OPENCODE_CLEAN_UP, ADMIN_PASSWORD } = require('../config');
|
|
7
|
+
|
|
8
|
+
const router = Router();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* GET /proxy/mcp-configurations
|
|
12
|
+
* Découvre les configurations disponibles auprès de tous les MCPs enregistrés
|
|
13
|
+
*/
|
|
14
|
+
router.get('/proxy/mcp-configurations', requireAuth, async (req, res) => {
|
|
15
|
+
try {
|
|
16
|
+
const results = await metaConfig.discoverConfigurations(registry.routes);
|
|
17
|
+
const compatible = results.filter(r => r.configurations !== null);
|
|
18
|
+
const incompatible = results.filter(r => r.configurations === null);
|
|
19
|
+
|
|
20
|
+
res.json({ success: true, compatible: compatible.length, incompatible: incompatible.length, results });
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error('[META-CONFIG] Discovery error:', error.message);
|
|
23
|
+
res.status(500).json({ success: false, error: error.message });
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* GET /proxy/meta-configs
|
|
29
|
+
* Liste toutes les méta-configurations sauvegardées
|
|
30
|
+
*/
|
|
31
|
+
router.get('/proxy/meta-configs', requireAuth, (req, res) => {
|
|
32
|
+
const data = metaConfig.getAll();
|
|
33
|
+
res.json({ success: true, metaConfigs: data.metaConfigs, activeMetaConfig: data.activeMetaConfig });
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* POST /proxy/meta-configs
|
|
38
|
+
* Crée une nouvelle méta-configuration
|
|
39
|
+
*/
|
|
40
|
+
router.post('/proxy/meta-configs', requireAuth, (req, res) => {
|
|
41
|
+
const { id, name, description, mappings } = req.body;
|
|
42
|
+
|
|
43
|
+
if (!id || !name) {
|
|
44
|
+
return res.status(400).json({ success: false, error: 'id and name are required' });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const created = metaConfig.create(id, name, description, mappings);
|
|
49
|
+
console.log(`[META-CONFIG] Created: ${id}`);
|
|
50
|
+
res.json({ success: true, metaConfig: { id, ...created } });
|
|
51
|
+
} catch (error) {
|
|
52
|
+
const status = error.message.includes('already exists') ? 409 : 500;
|
|
53
|
+
res.status(status).json({ success: false, error: error.message });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* PUT /proxy/meta-configs/:id
|
|
59
|
+
* Met à jour une méta-configuration existante
|
|
60
|
+
*/
|
|
61
|
+
router.put('/proxy/meta-configs/:id', requireAuth, (req, res) => {
|
|
62
|
+
const { id } = req.params;
|
|
63
|
+
const { name, description, mappings } = req.body;
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const updated = metaConfig.update(id, { name, description, mappings });
|
|
67
|
+
console.log(`[META-CONFIG] Updated: ${id}`);
|
|
68
|
+
res.json({ success: true, metaConfig: { id, ...updated } });
|
|
69
|
+
} catch (error) {
|
|
70
|
+
const status = error.message.includes('not found') ? 404 : 500;
|
|
71
|
+
res.status(status).json({ success: false, error: error.message });
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* DELETE /proxy/meta-configs/:id
|
|
77
|
+
* Supprime une méta-configuration
|
|
78
|
+
*/
|
|
79
|
+
router.delete('/proxy/meta-configs/:id', requireAuth, (req, res) => {
|
|
80
|
+
const { id } = req.params;
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
metaConfig.remove(id);
|
|
84
|
+
console.log(`[META-CONFIG] Deleted: ${id}`);
|
|
85
|
+
res.json({ success: true, deleted: id });
|
|
86
|
+
} catch (error) {
|
|
87
|
+
const status = error.message.includes('not found') ? 404 : 500;
|
|
88
|
+
res.status(status).json({ success: false, error: error.message });
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* POST /proxy/meta-configs/:id/apply
|
|
94
|
+
* Applique une méta-configuration
|
|
95
|
+
*/
|
|
96
|
+
router.post('/proxy/meta-configs/:id/apply', requireAuth, async (req, res) => {
|
|
97
|
+
const { id } = req.params;
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const result = await metaConfig.applyMetaConfig(id, registry.routes);
|
|
101
|
+
console.log(`[META-CONFIG] Applied "${id}": ${result.success ? 'all OK' : 'some failures'}`);
|
|
102
|
+
res.json({ success: result.success, warnings: result.warnings, metaConfigId: id, results: result.results });
|
|
103
|
+
} catch (error) {
|
|
104
|
+
const status = error.message.includes('not found') ? 404 : 500;
|
|
105
|
+
res.status(status).json({ success: false, error: error.message });
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* GET /proxy/meta-configs/active/sync
|
|
111
|
+
* Vérifie si les configurations actives des MCPs correspondent à la méta-config active
|
|
112
|
+
*/
|
|
113
|
+
router.get('/proxy/meta-configs/active/sync', requireAuth, async (req, res) => {
|
|
114
|
+
const activeId = metaConfig.getActive();
|
|
115
|
+
console.log(`[META-CONFIG SYNC] activeId = ${JSON.stringify(activeId)}`);
|
|
116
|
+
|
|
117
|
+
if (!activeId) {
|
|
118
|
+
return res.json({ synced: true, activeMetaConfigId: null });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const activeCfg = metaConfig.getById(activeId);
|
|
122
|
+
console.log(`[META-CONFIG SYNC] mappings = ${JSON.stringify(activeCfg?.mappings)}`);
|
|
123
|
+
if (!activeCfg) {
|
|
124
|
+
return res.json({ synced: true, activeMetaConfigId: null });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
const results = await metaConfig.discoverConfigurations(registry.routes);
|
|
129
|
+
console.log(`[META-CONFIG SYNC] discoverConfigurations results:`);
|
|
130
|
+
results.forEach(r => {
|
|
131
|
+
if (r.configurations) {
|
|
132
|
+
const active = r.configurations.find(c => c.active);
|
|
133
|
+
console.log(` ${r.path} → configs: [${r.configurations.map(c => `${c.id}${c.active ? '*' : ''}`).join(', ')}] — active: ${JSON.stringify(active?.id ?? null)}`);
|
|
134
|
+
} else {
|
|
135
|
+
console.log(` ${r.path} → error: ${r.error}`);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const conflicts = [];
|
|
140
|
+
|
|
141
|
+
for (const [mcpPath, expectedConfigId] of Object.entries(activeCfg.mappings)) {
|
|
142
|
+
const mcpResult = results.find(r => r.path === mcpPath);
|
|
143
|
+
if (!mcpResult) {
|
|
144
|
+
console.log(` [META-CONFIG SYNC] ${mcpPath} → MCP non trouvé dans les résultats, ignoré`);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (!mcpResult.configurations) {
|
|
148
|
+
console.log(` [META-CONFIG SYNC] ${mcpPath} → pas de configurations (erreur: ${mcpResult.error}), ignoré`);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const activeConfig = mcpResult.configurations.find(c => c.active);
|
|
153
|
+
const actualConfigId = activeConfig ? activeConfig.id : null;
|
|
154
|
+
|
|
155
|
+
console.log(` [META-CONFIG SYNC] ${mcpPath} → attendu: ${JSON.stringify(expectedConfigId)} | actuel: ${JSON.stringify(actualConfigId)} | match: ${actualConfigId === expectedConfigId}`);
|
|
156
|
+
|
|
157
|
+
if (actualConfigId !== expectedConfigId) {
|
|
158
|
+
conflicts.push({ path: mcpPath, expected: expectedConfigId, actual: actualConfigId });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
console.log(`[META-CONFIG SYNC] synced=${conflicts.length === 0}, conflicts=${JSON.stringify(conflicts)}`);
|
|
163
|
+
res.json({ synced: conflicts.length === 0, activeMetaConfigId: activeId, conflicts });
|
|
164
|
+
} catch (error) {
|
|
165
|
+
console.error('[META-CONFIG SYNC] Erreur:', error.message);
|
|
166
|
+
res.status(500).json({ success: false, error: error.message });
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* GET /proxy/meta-configs-ui
|
|
172
|
+
* Interface de gestion des méta-configurations
|
|
173
|
+
*/
|
|
174
|
+
router.get('/proxy/meta-configs-ui', requireAuth, (req, res) => {
|
|
175
|
+
const data = metaConfig.getAll();
|
|
176
|
+
const html = renderMetaConfigs(PROXY_NAME, data.metaConfigs, data.activeMetaConfig, OPENCODE_CLEAN_UP, !!ADMIN_PASSWORD);
|
|
177
|
+
res.type('html').send(html);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
module.exports = router;
|