fix(frontend): park uploads that cannot succeed, and stop two false signals
The upload queue gains `parkedFor`, so a photo rejected for a reason that cannot change on its own stops re-pushing itself. A ban used to come back as a generic `forbidden`, which purged the blob and moved the row to `blocked` — a terminal state with no retry button — so lifting a ban restored everything except the photo actually in flight. Ban and release are now distinct codes that keep the blob, charge no attempt, and tell the guest what has to happen. `releaseResolvedParks` drains them at boot from /me/context, because the live `user-shown` / `event-opened` events only reach a tab that was open when the host acted, and the usual sequence is the other way round. Two signals were firing on nothing. A filtered feed set `feedStale` on EVERY delta without deduping — and the delta cursor boundary is inclusive while sse.ts deliberately rewinds `lastEventTime`, so deltas routinely re-return rows already delivered. With the backstop polling every 60-120s, a guest who tapped a hashtag got a "Neue Beiträge" pill they could never clear, each tap costing a full filtered refetch. It now dedupes in both branches. The SSE liveness backstop had the mirror problem: `noteDelivered` harvested id, upload_id AND user_id from every payload, so by the time anything was deleted or anyone banned, their ids were already marked delivered from ordinary traffic about live content. The `deleted_ids` and `hidden_user_ids` clauses were false essentially always, leaving a half-open socket undetected while a host moderated into a feed nobody was listening to. Each event now records only the id its own clause tests. Also: /admin no longer bounces to /join on a cleared session — AUTH_ROUTES had the `/admin` prefix, which suppressed clearAuth() on the dashboard and let the login guard bounce back. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -195,12 +195,12 @@
|
||||
clearTimeout(timer);
|
||||
action();
|
||||
};
|
||||
// Always strictly less than the dwell — see PRELOAD_HEADROOM_MS.
|
||||
const preloadBudget = Math.max(
|
||||
250,
|
||||
Math.min(PRELOAD_TIMEOUT_MS, dwellMs - PRELOAD_HEADROOM_MS)
|
||||
);
|
||||
timer = setTimeout(() => done(() => commit(candidates[i])), preloadBudget);
|
||||
// Always strictly less than the dwell — see PRELOAD_HEADROOM_MS.
|
||||
const preloadBudget = Math.max(
|
||||
250,
|
||||
Math.min(PRELOAD_TIMEOUT_MS, dwellMs - PRELOAD_HEADROOM_MS)
|
||||
);
|
||||
timer = setTimeout(() => done(() => commit(candidates[i])), preloadBudget);
|
||||
const pre = new Image();
|
||||
pre.src = candidates[i];
|
||||
pre.decode().then(
|
||||
@@ -445,6 +445,12 @@
|
||||
unsubs.push(onSseEvent('upload-processed', handleUploadProcessed));
|
||||
unsubs.push(onSseEvent('upload-deleted', handleUploadDeleted));
|
||||
unsubs.push(onSseEvent('user-hidden', handleUserHidden));
|
||||
// An unban restores that guest's photos to the eligible set. The periodic `reconcile`
|
||||
// below would pick this up on its own, but this is the projector nobody is standing at —
|
||||
// waiting a whole interval to un-hide photos the host has just decided are fine again is
|
||||
// needlessly visible. A full reconcile is the only correct response anyway: the hidden
|
||||
// cards were dropped from local state, so there is nothing to restore in place.
|
||||
unsubs.push(onSseEvent('user-shown', () => void reconcile()));
|
||||
unsubs.push(onSseEvent('feed-delta', handleFeedDelta));
|
||||
// Open the stream ourselves — a kiosk/projector loads /diashow directly (never
|
||||
// via /feed), so we can't rely on another page having opened the singleton
|
||||
@@ -515,8 +521,8 @@
|
||||
<div
|
||||
class="pointer-events-none absolute bottom-4 left-4 max-w-xs rounded-md bg-black/60 px-3 py-2 text-left text-xs text-white/70 backdrop-blur"
|
||||
>
|
||||
Dieser Browser kann den Bildschirm nicht wachhalten. Bitte die automatische
|
||||
Bildschirmsperre am Gerät deaktivieren.
|
||||
Dieser Browser kann den Bildschirm nicht wachhalten. Bitte die automatische Bildschirmsperre
|
||||
am Gerät deaktivieren.
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user