perf: optimize monitor runner, fix SSE leak, deduplicate shared utils
This commit is contained in:
+5
-1
@@ -1,6 +1,10 @@
|
||||
import postgres from "postgres";
|
||||
|
||||
const sql = postgres(process.env.DATABASE_URL ?? "postgres://pingql:pingql@localhost:5432/pingql");
|
||||
const sql = postgres(process.env.DATABASE_URL ?? "postgres://pingql:pingql@localhost:5432/pingql", {
|
||||
max: 20,
|
||||
idle_timeout: 30,
|
||||
connect_timeout: 10,
|
||||
});
|
||||
|
||||
export default sql;
|
||||
|
||||
|
||||
@@ -317,6 +317,10 @@ export function validateQuery(query: unknown, path = ""): ValidationError[] {
|
||||
if (typeof value !== "string") {
|
||||
errors.push({ path: keyPath, message: `${key} expects a string` });
|
||||
}
|
||||
} else if (key === "$consider") {
|
||||
if (value !== "up" && value !== "down") {
|
||||
errors.push({ path: keyPath, message: '$consider must be "up" or "down"' });
|
||||
}
|
||||
} else if (key.startsWith("$")) {
|
||||
// It's an operator inside a field condition — skip validation here
|
||||
} else {
|
||||
|
||||
@@ -1,29 +1,12 @@
|
||||
import { Elysia, t } from "elysia";
|
||||
import { createHmac, randomBytes } from "crypto";
|
||||
import sql from "../db";
|
||||
import { createRateLimiter } from "../utils/rate-limit";
|
||||
|
||||
const EMAIL_HMAC_KEY = process.env.EMAIL_HMAC_KEY || "pingql-default-hmac-key";
|
||||
|
||||
// ── Per-IP rate limiting for auth endpoints ───────────────────────────
|
||||
const authRateMap = new Map<string, { count: number; resetAt: number }>();
|
||||
|
||||
function checkAuthRateLimit(ip: string, maxPerMinute: number): boolean {
|
||||
const now = Date.now();
|
||||
const entry = authRateMap.get(ip);
|
||||
if (!entry || now > entry.resetAt) {
|
||||
authRateMap.set(ip, { count: 1, resetAt: now + 60_000 });
|
||||
return true;
|
||||
}
|
||||
entry.count++;
|
||||
return entry.count <= maxPerMinute;
|
||||
}
|
||||
|
||||
setInterval(() => {
|
||||
const now = Date.now();
|
||||
for (const [key, entry] of authRateMap) {
|
||||
if (now > entry.resetAt) authRateMap.delete(key);
|
||||
}
|
||||
}, 5 * 60_000);
|
||||
const checkAuthRateLimit = createRateLimiter();
|
||||
|
||||
function generateKey(): string {
|
||||
return randomBytes(32).toString("base64url");
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
export function createRateLimiter(windowMs = 60_000, cleanupIntervalMs = 5 * 60_000) {
|
||||
const map = new Map<string, { count: number; resetAt: number }>();
|
||||
|
||||
setInterval(() => {
|
||||
const now = Date.now();
|
||||
for (const [key, entry] of map) {
|
||||
if (now > entry.resetAt) map.delete(key);
|
||||
}
|
||||
}, cleanupIntervalMs);
|
||||
|
||||
return function check(key: string, max: number): boolean {
|
||||
const now = Date.now();
|
||||
const entry = map.get(key);
|
||||
if (!entry || now > entry.resetAt) {
|
||||
map.set(key, { count: 1, resetAt: now + windowMs });
|
||||
return true;
|
||||
}
|
||||
entry.count++;
|
||||
return entry.count <= max;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user