Files
HealthLog/src/app/api/monitoring/glitchtip/route.ts
T
Marc-André BombeckandClaude Opus 4.7 02b99553b9 chore(style): repo-wide prettier sweep before v1.4.6 tag
Long-overdue prettier sweep; prettier had drifted vs. checked-in code
across ~130 files (mostly long-argument line-break wrapping in TS and
table-padding in markdown). Pure formatting — no semantic changes —
and required to clear the v1.4.6 release gate's `pnpm format:check`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 02:27:17 +02:00

69 lines
2.1 KiB
TypeScript

import { NextRequest } from "next/server";
import { z } from "zod/v4";
import { apiError, apiSuccess, getClientIp } from "@/lib/api-response";
import { checkRateLimit } from "@/lib/rate-limit";
import { getGlitchtipSettings } from "@/lib/monitoring-settings";
import { sendGlitchtipEvent } from "@/lib/monitoring/glitchtip";
import { apiHandler } from "@/lib/api-handler";
import { annotate, getEvent } from "@/lib/logging/context";
const clientErrorSchema = z.object({
message: z.string().min(1).max(2000),
stack: z.string().max(20000).optional(),
level: z.enum(["error", "warning", "info"]).optional(),
type: z.string().max(120).optional(),
url: z.string().max(2000).optional(),
userAgent: z.string().max(1000).optional(),
});
export const POST = apiHandler(async (request: NextRequest) => {
annotate({ action: { name: "monitoring.glitchtip.report" } });
const ip = getClientIp(request);
const rl = await checkRateLimit(`glitchtip:${ip}`, 20, 60 * 1000);
if (!rl.allowed) return apiError("Rate limit exceeded", 429);
const settings = await getGlitchtipSettings();
if (!settings.glitchtipEnabled || !settings.glitchtipDsn) {
return apiSuccess({ skipped: true });
}
let body: unknown;
try {
body = await request.json();
} catch {
return apiError("Invalid JSON data", 422);
}
const parsed = clientErrorSchema.safeParse(body);
if (!parsed.success) return apiError("Invalid error data", 422);
const delivery = await sendGlitchtipEvent({
dsn: settings.glitchtipDsn,
input: {
environment: settings.glitchtipEnvironment || "production",
message: parsed.data.message,
stack: parsed.data.stack,
level: parsed.data.level ?? "error",
type: parsed.data.type,
url: parsed.data.url,
userAgent: parsed.data.userAgent,
sourceTag: "healthlog-client",
},
});
if (!delivery.ok) {
getEvent()?.addWarning(
"Glitchtip event rejected: " +
delivery.method +
" " +
delivery.status +
" " +
delivery.details,
);
return apiError("Glitchtip could not accept error", 502);
}
return apiSuccess({ sent: true });
});