@metric-im/administrate 1.0.1 → 1.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.
- package/multisite.mjs +42 -1
- package/package.json +1 -1
- package/.claude/settings.local.json +0 -10
package/multisite.mjs
CHANGED
|
@@ -19,6 +19,7 @@ export class MultiSite {
|
|
|
19
19
|
this.usedPorts = new Set();
|
|
20
20
|
this.healthCheckIntervals = new Map();
|
|
21
21
|
this.isShuttingDown = false;
|
|
22
|
+
this.errorLogTracker = new Map(); // Track error frequency for rate limiting
|
|
22
23
|
this.setupCleanup();
|
|
23
24
|
}
|
|
24
25
|
get spawnPort() {
|
|
@@ -176,6 +177,37 @@ export class MultiSite {
|
|
|
176
177
|
}
|
|
177
178
|
});
|
|
178
179
|
}
|
|
180
|
+
|
|
181
|
+
// Rate limit error logging to prevent spam
|
|
182
|
+
shouldLogError(target, clientIP) {
|
|
183
|
+
const key = `${clientIP}:${target}`;
|
|
184
|
+
const now = Date.now();
|
|
185
|
+
const logEntry = this.errorLogTracker.get(key);
|
|
186
|
+
|
|
187
|
+
if (!logEntry) {
|
|
188
|
+
this.errorLogTracker.set(key, { count: 1, firstSeen: now, lastLogged: now });
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
logEntry.count++;
|
|
193
|
+
|
|
194
|
+
// Reset counter if it's been more than 5 minutes since first error
|
|
195
|
+
if (now - logEntry.firstSeen > 300000) {
|
|
196
|
+
logEntry.count = 1;
|
|
197
|
+
logEntry.firstSeen = now;
|
|
198
|
+
logEntry.lastLogged = now;
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Log first error, then every 10th error, but not more than once per minute
|
|
203
|
+
if (logEntry.count === 1 ||
|
|
204
|
+
(logEntry.count % 10 === 0 && now - logEntry.lastLogged > 60000)) {
|
|
205
|
+
logEntry.lastLogged = now;
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
179
211
|
static async attach(app,options) {
|
|
180
212
|
const instance = new MultiSite(app,options);
|
|
181
213
|
instance.config = new Config();
|
|
@@ -205,6 +237,7 @@ export class MultiSite {
|
|
|
205
237
|
const method = req.method;
|
|
206
238
|
const isBodyMethod = ['POST', 'PUT', 'PATCH'].includes(method);
|
|
207
239
|
const payload = isBodyMethod ? req.body : null;
|
|
240
|
+
const clientIP = req.ip || req.connection.remoteAddress || req.headers['x-forwarded-for'];
|
|
208
241
|
|
|
209
242
|
// Debug logging for POST requests
|
|
210
243
|
if (method === 'POST') {
|
|
@@ -267,7 +300,15 @@ export class MultiSite {
|
|
|
267
300
|
res.status(response.status).set(cleanHeaders).send(response.data);
|
|
268
301
|
}
|
|
269
302
|
} catch (error) {
|
|
270
|
-
|
|
303
|
+
// Rate limit error logging to prevent spam
|
|
304
|
+
if (this.shouldLogError(target, clientIP)) {
|
|
305
|
+
const logEntry = this.errorLogTracker.get(`${clientIP}:${target}`);
|
|
306
|
+
if (logEntry && logEntry.count > 1) {
|
|
307
|
+
console.error(`${clientIP}:E: [Proxy] Error connecting to ${target}: ${error.message} (${logEntry.count} times)`);
|
|
308
|
+
} else {
|
|
309
|
+
console.error(`${clientIP}:E: [Proxy] Error connecting to ${target}: ${error.message}`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
271
312
|
|
|
272
313
|
// // Clean up dead processes
|
|
273
314
|
// this.removeDeadSites();
|
package/package.json
CHANGED