Instant unread badges: remove event buffering, add kind:40002

Remove all event buffering from the relay client on both platforms so
unread badges appear the instant a WebSocket event arrives.

Desktop: remove MessageChannel-based event buffer from
relayClientSession.ts — handleEvent now calls subscription.onEvent()
directly. Mobile: remove Timer-based 16ms event buffer from
relay_session.dart — _handleEvent now calls liveSub.onEvent() directly
with inline dedup.

Add KIND_STREAM_MESSAGE_V2 (40002) to CHANNEL_EVENT_KINDS on desktop
and channelEventKinds on mobile so rich-format messages trigger instant
badge updates instead of waiting for the 60-second polling refetch.

Also includes NIP-RS cross-device read state sync (useReadStateSync
hook on desktop, ReadStateSyncNotifier on mobile), read state seeding
on first load, and a sync toggle in settings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Wes
2026-04-28 14:06:53 -07:00
parent 8a2562dfd5
commit 16c2ef7bea
27 changed files with 1681 additions and 239 deletions

View File

@@ -40,7 +40,7 @@ const overrides = new Map([
["src/features/settings/ui/SettingsView.tsx", 600],
["src/features/sidebar/ui/AppSidebar.tsx", 860], // channels + forums creation forms + Pulse nav
["src/features/tokens/ui/TokenSettingsCard.tsx", 800],
["src/shared/api/relayClientSession.ts", 890], // durable websocket session manager with reconnect/replay/recovery state + sendTypingIndicator + fetchChannelHistoryBefore + subscribeToChannelLive (huddle TTS) + subscribeToHuddleEvents (huddle indicator) + disconnect() for workspace switch teardown
["src/shared/api/relayClientSession.ts", 910], // durable websocket session manager with reconnect/replay/recovery state + sendTypingIndicator + fetchChannelHistoryBefore + subscribeToChannelLive (huddle TTS) + subscribeToHuddleEvents (huddle indicator) + disconnect() for workspace switch teardown + NIP-RS read state fetch/subscribe/publish + fetchOwnReadStateBlob
["src/shared/api/tauri.ts", 1100], // remote agent provider API bindings + canvas API functions
["src-tauri/src/lib.rs", 710], // sprout-media:// proxy + Range headers + Sprout nest init (ensure_nest) in setup() + huddle command registration + PTT global shortcut handler + persona pack commands + app_handle storage for event emission
["src-tauri/src/commands/media.rs", 720], // ffmpeg video transcode + poster frame extraction + run_ffmpeg_with_timeout (find_ffmpeg, is_video_file, transcode_to_mp4, extract_poster_frame, transcode_and_extract_poster) + spawn_blocking wrappers + tests
@@ -68,7 +68,7 @@ const overrides = new Map([
["src-tauri/src/relay.rs", 510], // +4 lines for NIP-OA auth tag injection in profile sync (build_profile_event) + verification test
["src-tauri/src/commands/pairing.rs", 550], // NIP-AB pairing actor: 3 Tauri commands + background WS task + NIP-42 auth + event parsing helpers
["src-tauri/src/lib.rs", 715], // +4 lines for PairingHandle managed state + 3 pairing command registrations
["src/shared/api/tauri.ts", 1125], // +14 lines for 3 NIP-AB pairing command wrappers + applyWorkspace
["src/shared/api/tauri.ts", 1140], // +14 lines for 3 NIP-AB pairing command wrappers + applyWorkspace + NIP-44 encrypt/decrypt wrappers
]);
async function walkFiles(directory) {