Three fixes for "the channel grid loads slowly and not all videos come in even
when they show on other grids":
1. Race condition (primary "won't load" cause). loadUserVideos() bumps a shared
currentVideoLoadToken and only renders if its token is still current. A burst
of refresh triggers — e.g. the NIP-71 ingest flushing repeatedly right after
a channel opens (RELAY STORM in the logs) — supersedes every in-flight load
before it paints, so the grid stays on "Loading videos…". Add
requestChannelVideoLoad(): while a load for the same channel is in flight, a
refresh flags a single trailing rerun instead of starting a competing load;
navigation still starts immediately. All three call sites routed through it.
2. Slowness from hung relays. The per-relay pool.list() fan-out had no timeout,
so one relay that never sends EOSE stalled the merged render. Add
raceListWithTimeout() (exported, pure) bounding each list() to 8s, resolving
to [] on timeout/rejection.
3. Completeness/parity. The channel grid sourced only nostrClient.allEvents + a
scoped relay fetch, which can diverge from the shared feed cache the other
grids render from. getCachedChannelVideoEvents() now also unions the author's
videos from nostrService.getActiveVideosByAuthors() (same videosMap-backed
author index), so a video shown on another grid is present here by construction.
Tests: tests/channel-relay-timeout.test.mjs (5).
Co-Authored-By: Claude Opus 4.8 <[email protected]>