mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-08-29 03:55:38 -04:00
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:
@@ -559,13 +559,29 @@ export async function getTitleWithChildren(id: string): Promise<{
|
||||
let titleSeasons: Season[] = [];
|
||||
|
||||
if (title.type === "tv") {
|
||||
const seasonRows = db
|
||||
let seasonRows = db
|
||||
.select()
|
||||
.from(seasons)
|
||||
.where(eq(seasons.titleId, title.id))
|
||||
.orderBy(seasons.seasonNumber)
|
||||
.all();
|
||||
|
||||
// Retry hydration when a TV title exists but no seasons were stored.
|
||||
if (seasonRows.length === 0) {
|
||||
try {
|
||||
const show = await getTvDetails(title.tmdbId);
|
||||
await refreshTvChildren(id, title.tmdbId, show.number_of_seasons);
|
||||
seasonRows = db
|
||||
.select()
|
||||
.from(seasons)
|
||||
.where(eq(seasons.titleId, title.id))
|
||||
.orderBy(seasons.seasonNumber)
|
||||
.all();
|
||||
} catch (err) {
|
||||
log.debug(`Failed to backfill missing seasons for title ${id}:`, err);
|
||||
}
|
||||
}
|
||||
|
||||
// Batch fetch all episodes for all seasons (1 query)
|
||||
const seasonIds = seasonRows.map((s) => s.id);
|
||||
const allEps =
|
||||
|
||||
Reference in New Issue
Block a user