diff --git a/backend/src/handlers/feed.rs b/backend/src/handlers/feed.rs index 830a634..29e46e3 100644 --- a/backend/src/handlers/feed.rs +++ b/backend/src/handlers/feed.rs @@ -172,6 +172,11 @@ pub struct DeltaQuery { pub struct DeltaResponse { pub uploads: Vec, pub deleted_ids: Vec, + /// True when the upload query hit `DELTA_LIMIT`: the response carries only the + /// newest slice of the gap, so the client must fall back to a full feed refresh + /// rather than merging (the older missed uploads are absent and unrecoverable + /// via a later delta, which advances `since` past them). + pub truncated: bool, } pub async fn feed_delta( @@ -197,6 +202,10 @@ pub async fn feed_delta( .fetch_all(&state.pool) .await?; + // Hit the cap => this is only the newest slice of a larger gap. Signal the + // client to full-refresh instead of merging a partial delta. + let truncated = rows.len() as i64 >= DELTA_LIMIT; + let deleted_ids: Vec<(Uuid,)> = sqlx::query_as( "SELECT id FROM upload WHERE event_id = $1 AND deleted_at IS NOT NULL AND deleted_at > $2", @@ -229,6 +238,7 @@ pub async fn feed_delta( Ok(Json(DeltaResponse { uploads, deleted_ids: deleted_ids.into_iter().map(|r| r.0).collect(), + truncated, })) } diff --git a/frontend/src/app.html b/frontend/src/app.html index 87b0e0c..b17193e 100644 --- a/frontend/src/app.html +++ b/frontend/src/app.html @@ -21,7 +21,10 @@ theme=dark don't flash a white screen. Mirrors the logic in `src/lib/theme-store.ts`; kept in sync by hand (it's 6 lines). --> -