refactor: improve maintainability by reducing LOC/reuse

This commit is contained in:
2026-03-28 16:52:19 +04:00
parent 8831c9c7b4
commit 6dcb5c0a52
29 changed files with 311 additions and 468 deletions
+2 -76
View File
@@ -1,4 +1,5 @@
import postgres from "postgres";
import { migrate as sharedMigrate } from "../../shared/db";
const sql = postgres(process.env.DATABASE_URL ?? "postgres://pingql:pingql@localhost:5432/pingql", {
max: 20,
@@ -9,80 +10,5 @@ const sql = postgres(process.env.DATABASE_URL ?? "postgres://pingql:pingql@local
export default sql;
export async function migrate() {
await sql`CREATE EXTENSION IF NOT EXISTS pgcrypto`;
await sql`
CREATE TABLE IF NOT EXISTS accounts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
key TEXT NOT NULL UNIQUE,
email_hash TEXT,
created_at TIMESTAMPTZ DEFAULT now()
)
`;
await sql`
CREATE TABLE IF NOT EXISTS monitors (
id TEXT PRIMARY KEY DEFAULT encode(gen_random_bytes(8), 'hex'),
account_id UUID NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
name TEXT NOT NULL,
url TEXT NOT NULL,
method TEXT NOT NULL DEFAULT 'GET',
request_headers JSONB,
request_body TEXT,
timeout_ms INTEGER NOT NULL DEFAULT 30000,
interval_s INTEGER NOT NULL DEFAULT 60,
query JSONB,
enabled BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ DEFAULT now()
)
`;
await sql`
CREATE TABLE IF NOT EXISTS pings (
id BIGSERIAL PRIMARY KEY,
monitor_id TEXT NOT NULL REFERENCES monitors(id) ON DELETE CASCADE,
checked_at TIMESTAMPTZ NOT NULL DEFAULT now(),
scheduled_at TIMESTAMPTZ,
jitter_ms INTEGER,
status_code INTEGER,
latency_ms INTEGER,
up BOOLEAN NOT NULL,
error TEXT,
meta JSONB
)
`;
// Migrations for existing deployments
await sql`ALTER TABLE pings ADD COLUMN IF NOT EXISTS scheduled_at TIMESTAMPTZ`;
await sql`ALTER TABLE pings ADD COLUMN IF NOT EXISTS jitter_ms INTEGER`;
await sql`ALTER TABLE monitors ADD COLUMN IF NOT EXISTS regions TEXT[] NOT NULL DEFAULT '{}'`;
await sql`ALTER TABLE pings ADD COLUMN IF NOT EXISTS region TEXT`;
await sql`ALTER TABLE pings ADD COLUMN IF NOT EXISTS run_id TEXT`;
await sql`ALTER TABLE accounts ADD COLUMN IF NOT EXISTS plan TEXT NOT NULL DEFAULT 'free'`;
await sql`ALTER TABLE accounts ADD COLUMN IF NOT EXISTS plan_expires_at TIMESTAMPTZ`;
await sql`ALTER TABLE accounts ADD COLUMN IF NOT EXISTS plan_stack JSONB NOT NULL DEFAULT '[]'`;
await sql`CREATE INDEX IF NOT EXISTS idx_pings_monitor ON pings(monitor_id, checked_at DESC)`;
await sql`CREATE INDEX IF NOT EXISTS idx_pings_checked_at ON pings(checked_at)`;
// Response bodies stored separately to keep pings table lean
await sql`
CREATE TABLE IF NOT EXISTS ping_bodies (
ping_id BIGINT PRIMARY KEY REFERENCES pings(id) ON DELETE CASCADE,
body TEXT
)
`;
await sql`
CREATE TABLE IF NOT EXISTS api_keys (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
key TEXT NOT NULL UNIQUE,
account_id UUID NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
label TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT now(),
last_used_at TIMESTAMPTZ
)
`;
console.log("DB ready");
await sharedMigrate(sql);
}
+2 -9
View File
@@ -1,19 +1,12 @@
import { Elysia } from "elysia";
import { ingest } from "./routes/pings";
import { monitors } from "./routes/monitors";
import { account } from "./routes/auth";
import { internal } from "./routes/internal";
import { migrate } from "./db";
await migrate();
import { SECURITY_HEADERS } from "../../shared/auth";
const SECURITY_HEADERS = {
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"Strict-Transport-Security": "max-age=63072000; includeSubDomains",
"X-XSS-Protection": "0",
"Referrer-Policy": "strict-origin-when-cross-origin",
};
await migrate();
const elysia = new Elysia()
.get("/", () => ({
+6 -39
View File
@@ -1,33 +1,13 @@
import { Elysia, t } from "elysia";
import { createHmac, randomBytes } from "crypto";
import sql from "../db";
import { createRateLimiter } from "../utils/rate-limit";
import { getPlanLimits } from "../utils/plans";
import { createRateLimiter } from "../../../shared/rate-limit";
import { getPlanLimits } from "../../../shared/plans";
import { generateKey, hashEmail, resolveKey as sharedResolveKey, extractAuthKey, COOKIE_OPTS } from "../../../shared/auth";
// ── Per-IP rate limiting for auth endpoints ───────────────────────────
const checkAuthRateLimit = createRateLimiter();
const EMAIL_HMAC_KEY = process.env.EMAIL_HMAC_KEY || "pingql-default-hmac-key";
function generateKey(): string {
return randomBytes(32).toString("base64url");
}
function hashEmail(email: string): string {
return createHmac("sha256", EMAIL_HMAC_KEY).update(email.toLowerCase().trim()).digest("hex");
}
async function resolveKey(key: string): Promise<{ accountId: string; keyId: string | null; plan: string } | null> {
const [account] = await sql`SELECT id, plan FROM accounts WHERE key = ${key}`;
if (account) return { accountId: account.id, keyId: null, plan: account.plan };
const [apiKey] = await sql`SELECT k.id, k.account_id, a.plan FROM api_keys k JOIN accounts a ON a.id = k.account_id WHERE k.key = ${key}`;
if (apiKey) {
sql`UPDATE api_keys SET last_used_at = now() WHERE id = ${apiKey.id}`.catch(() => {});
return { accountId: apiKey.account_id, keyId: apiKey.id, plan: apiKey.plan };
}
return null;
async function resolveKey(key: string) {
return sharedResolveKey(sql, key);
}
export { resolveKey };
@@ -35,11 +15,7 @@ export { resolveKey };
export function requireAuth(app: Elysia) {
return app
.derive(async ({ headers, cookie, set }) => {
const authHeader = headers["authorization"] ?? "";
const bearer = authHeader.match(/^bearer\s+(.+)$/i)?.[1]?.trim();
const cookieKey = cookie?.pingql_key?.value;
const key = bearer || cookieKey;
const key = extractAuthKey(headers, cookie);
if (!key) {
set.status = 401;
return { accountId: null as string | null, keyId: null as string | null, plan: "free" as string };
@@ -59,15 +35,6 @@ export function requireAuth(app: Elysia) {
});
}
const COOKIE_OPTS = {
httpOnly: true,
secure: process.env.COOKIE_SECURE !== "false",
sameSite: "none" as const,
path: "/",
domain: process.env.COOKIE_DOMAIN ?? ".pingql.com",
maxAge: 60 * 60 * 24 * 30, // 30 days
};
export const account = new Elysia({ prefix: "/account" })
.post("/login", async ({ body, cookie, set, request }) => {
+1 -1
View File
@@ -3,7 +3,7 @@
import { Elysia } from "elysia";
import sql from "../db";
import { safeTokenCompare } from "../utils/token";
import { safeTokenCompare } from "../../../shared/auth";
export async function pruneOldPings(retentionDays = 90) {
const result = await sql`DELETE FROM pings WHERE checked_at < now() - ${retentionDays + ' days'}::interval`;
+1 -1
View File
@@ -2,7 +2,7 @@ import { Elysia, t } from "elysia";
import { requireAuth } from "./auth";
import sql from "../db";
import { validateMonitorUrl } from "../utils/ssrf";
import { getPlanLimits } from "../utils/plans";
import { getPlanLimits } from "../../../shared/plans";
const MonitorBody = t.Object({
name: t.String({ maxLength: 200, description: "Human-readable name" }),
+3 -8
View File
@@ -1,7 +1,7 @@
import { Elysia, t } from "elysia";
import sql from "../db";
import { resolveKey } from "./auth";
import { safeTokenCompare } from "../utils/token";
import { extractAuthKey, safeTokenCompare } from "../../../shared/auth";
// ── SSE bus ───────────────────────────────────────────────────────────────────
type SSEController = ReadableStreamDefaultController<Uint8Array>;
@@ -121,9 +121,7 @@ export const ingest = new Elysia()
// Fetch response body for a specific ping
.get("/pings/:id/body", async ({ params, headers, cookie, set }) => {
const authHeader = headers["authorization"] ?? "";
const bearer = authHeader.match(/^bearer\s+(.+)$/i)?.[1]?.trim();
const key = bearer ?? cookie?.pingql_key?.value;
const key = extractAuthKey(headers, cookie);
if (!key) { set.status = 401; return { error: "Unauthorized" }; }
const resolved = await resolveKey(key);
@@ -143,10 +141,7 @@ export const ingest = new Elysia()
// SSE: single stream for all of the account's monitors
.get("/account/stream", async ({ headers, cookie }) => {
const authHeader = headers["authorization"] ?? "";
const bearer = authHeader.match(/^bearer\s+(.+)$/i)?.[1]?.trim();
const key = bearer ?? cookie?.pingql_key?.value;
const key = extractAuthKey(headers, cookie);
if (!key) return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
const resolved = await resolveKey(key);
-42
View File
@@ -1,42 +0,0 @@
export type Plan = "free" | "pro" | "pro2x" | "pro4x" | "lifetime";
export interface PlanLimits {
maxMonitors: number;
minIntervalS: number;
maxRegions: number;
}
const PLANS: Record<Plan, PlanLimits> = {
free: { maxMonitors: 10, minIntervalS: 30, maxRegions: 1 },
pro: { maxMonitors: 200, minIntervalS: 5, maxRegions: 99 },
pro2x: { maxMonitors: 400, minIntervalS: 5, maxRegions: 99 },
pro4x: { maxMonitors: 800, minIntervalS: 5, maxRegions: 99 },
lifetime: { maxMonitors: 200, minIntervalS: 5, maxRegions: 99 },
};
export function getPlanLimits(plan: string): PlanLimits {
return PLANS[plan as Plan] || PLANS.free;
}
// Display helpers
export const PLAN_LABELS: Record<string, string> = {
free: "Free", pro: "Pro", pro2x: "Pro 2x", pro4x: "Pro 4x", lifetime: "Lifetime",
};
export const PRO_MULTIPLIERS = [
{ plan: "pro", label: "1x", monitors: 200, interval: "5s", priceMultiplier: 1 },
{ plan: "pro2x", label: "2x", monitors: 400, interval: "5s", priceMultiplier: 2 },
{ plan: "pro4x", label: "4x", monitors: 800, interval: "5s", priceMultiplier: 4 },
];
export const PRO_MONTHLY_USD = 12;
export const LIFETIME_USD = 140;
// Tier ranking for plan stacking decisions
const PLAN_RANK: Record<string, number> = {
free: 0, pro: 1, lifetime: 1, pro2x: 2, pro4x: 3,
};
export function planTier(plan: string): number {
return PLAN_RANK[plan] ?? 0;
}
-21
View File
@@ -1,21 +0,0 @@
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;
};
}
-9
View File
@@ -1,9 +0,0 @@
import { timingSafeEqual } from "crypto";
export function safeTokenCompare(a: string | undefined, b: string | undefined): boolean {
if (!a || !b) return false;
const bufA = Buffer.from(a);
const bufB = Buffer.from(b);
if (bufA.length !== bufB.length) return false;
return timingSafeEqual(bufA, bufB);
}