diff options
| author | Fuwn <[email protected]> | 2026-02-12 00:49:03 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-12 00:49:42 -0800 |
| commit | 2911927a2d9fdd5616c2eda5643143f601068888 (patch) | |
| tree | 79726e2f2babc4a1da58c30b59d22981fbbdfe26 /apps/web/lib | |
| parent | Redump latest Supabase schema (diff) | |
| download | asa.news-2911927a2d9fdd5616c2eda5643143f601068888.tar.xz asa.news-2911927a2d9fdd5616c2eda5643143f601068888.zip | |
fix: prevent read entries from reverting to unread on re-fetch
Root cause: cleanup_stale_entries deleted read-but-unsaved entries from
active feeds, then the Go worker re-inserted them with new UUIDs,
orphaning the user_entry_states rows and making entries appear unread.
- cleanup_stale_entries: skip feeds with active subscribers and preserve
entries that have been read (not just saved)
- Go parser: normalize GUIDs by trimming whitespace and stripping
tracking query parameters from URL-based identifiers
- Go writer: preserve original published_at on upsert instead of
overwriting, preventing old entries from jumping to timeline top
- get_unread_counts: apply same time boundary as get_timeline so
ancient re-inserted entries don't inflate counts
- Realtime listener: ignore INSERT events for entries older than 48h
to suppress misleading "new entries" notifications from re-inserts
Diffstat (limited to 'apps/web/lib')
| -rw-r--r-- | apps/web/lib/hooks/use-realtime-entries.ts | 14 |
1 files changed, 13 insertions, 1 deletions
diff --git a/apps/web/lib/hooks/use-realtime-entries.ts b/apps/web/lib/hooks/use-realtime-entries.ts index 22551f9..63d0eed 100644 --- a/apps/web/lib/hooks/use-realtime-entries.ts +++ b/apps/web/lib/hooks/use-realtime-entries.ts @@ -9,6 +9,7 @@ import { useNotificationStore } from "@/lib/stores/notification-store" import { useUserInterfaceStore } from "@/lib/stores/user-interface-store" const DEBOUNCE_MILLISECONDS = 3000 +const STALE_ENTRY_THRESHOLD_HOURS = 48 export function useRealtimeEntries() { const queryClient = useQueryClient() @@ -66,7 +67,18 @@ export function useRealtimeEntries() { schema: "public", table: "entries", }, - () => { + (payload) => { + const publishedAt = payload.new?.published_at + if (publishedAt) { + const entryAge = + Date.now() - new Date(publishedAt).getTime() + const thresholdMilliseconds = + STALE_ENTRY_THRESHOLD_HOURS * 60 * 60 * 1000 + if (entryAge > thresholdMilliseconds) { + return + } + } + pendingCountReference.current++ if (debounceTimerReference.current) { |