Harden API input validation, error handling, and optimistic rollbacks

Add try/catch around `request.json()` in all POST routes to return a
400 instead of crashing on malformed bodies. Validate `type` as a
strict `"movie" | "tv"` enum in search, discover, import, and resolve
routes. Validate `tmdbId` as a positive integer. Add a
`SORT_BY_PATTERN` regex and page-range check (1–500) to the discover
route. Wrap all outbound TMDB calls in try/catch and return 502 on
failure so clients get a structured error rather than an unhandled
rejection.

Fix optimistic-update rollbacks in `use-title-actions`: capture
`prevStatus` and `prevWatches` before each mutation and restore both
atoms in the catch block for catchUp, handleMarkSeason,
handleUnmarkSeason, and single-episode toggle.

Fix a bug in `getContinueWatchingFeed` where the watchDateMap could
hold a stale date for episodes watched more than once; the map now
keeps the most-recent `watchedAt` per episode.
This commit is contained in:
2026-03-05 13:16:08 -05:00
parent ff3c8a737b
commit f3a425a5a9
10 changed files with 240 additions and 76 deletions
+7 -2
View File
@@ -12,8 +12,13 @@ export async function POST(request: Request) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const body = await request.json();
const jobName = body?.jobName;
let body: unknown;
try {
body = await request.json();
} catch {
return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 });
}
const jobName = (body as { jobName?: unknown })?.jobName;
if (!jobName || typeof jobName !== "string") {
return NextResponse.json(