From b6dad2429c11c0f0258227f1bde358558fa1e24b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20G=C3=B3mez?= Date: Fri, 16 Jan 2026 14:02:40 +0100 Subject: [PATCH] debug: Add comprehensive logging to diagnose live message delivery Added detailed logging throughout gift-wrap service to trace: - Timeline subscription firing - Gift wrap detection (symbol vs persisted) - Conversation updates - Rumor extraction Also fixed updateConversations to check persistedIds in addition to in-memory symbol, ensuring gift wraps are processed correctly even after persistence. This will help identify why messages don't appear live and require manual sync. --- src/services/gift-wrap.ts | 50 +++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/src/services/gift-wrap.ts b/src/services/gift-wrap.ts index 3098c52..129b3a9 100644 --- a/src/services/gift-wrap.ts +++ b/src/services/gift-wrap.ts @@ -363,15 +363,29 @@ class GiftWrapService { }; // Use timeline observable for reactive updates + console.log( + `[GiftWrap] Setting up timeline subscription for user ${this.userPubkey?.slice(0, 8)}`, + ); const sub = eventStore .timeline(reqFilter) .pipe(map((events) => events.sort((a, b) => b.created_at - a.created_at))) .subscribe((giftWraps) => { + console.log( + `[GiftWrap] 📬 Timeline subscription fired with ${giftWraps.length} gift wraps`, + ); + // Find new gift wraps that we haven't seen before const newGiftWraps = giftWraps.filter( (gw) => !this.giftWraps.some((existing) => existing.id === gw.id), ); + if (newGiftWraps.length > 0) { + console.log( + `[GiftWrap] Found ${newGiftWraps.length} new gift wraps:`, + newGiftWraps.map((gw) => gw.id.slice(0, 8)), + ); + } + this.giftWraps = giftWraps; this.giftWraps$.next(giftWraps); @@ -380,8 +394,14 @@ class GiftWrapService { if (!this.decryptStates.has(gw.id)) { // Check both in-memory unlock state and persisted IDs // Persisted IDs indicate content was decrypted in a previous session - const isUnlocked = - isGiftWrapUnlocked(gw) || this.persistedIds.has(gw.id); + const hasSymbol = isGiftWrapUnlocked(gw); + const hasPersisted = this.persistedIds.has(gw.id); + const isUnlocked = hasSymbol || hasPersisted; + + console.log( + `[GiftWrap] Gift wrap ${gw.id.slice(0, 8)}: symbol=${hasSymbol}, persisted=${hasPersisted}, unlocked=${isUnlocked}`, + ); + this.decryptStates.set(gw.id, { status: isUnlocked ? "success" : "pending", decryptedAt: isUnlocked ? Date.now() : undefined, @@ -442,14 +462,32 @@ class GiftWrapService { * preserving all fields (id, pubkey, created_at, kind, tags, content). */ private updateConversations() { + console.log( + `[GiftWrap] Updating conversations from ${this.giftWraps.length} gift wraps`, + ); const conversationMap = new Map(); const allRumors: Array<{ giftWrap: NostrEvent; rumor: Rumor }> = []; for (const gw of this.giftWraps) { - if (!isGiftWrapUnlocked(gw)) continue; + // Check both in-memory unlock state AND persisted IDs + // This is critical: gift wraps we just sent have the symbol, + // but after reload they only have persisted IDs + const isUnlocked = isGiftWrapUnlocked(gw) || this.persistedIds.has(gw.id); + + if (!isUnlocked) { + console.log( + `[GiftWrap] Skipping locked gift wrap ${gw.id.slice(0, 8)}`, + ); + continue; + } const rumor = getGiftWrapRumor(gw); - if (!rumor) continue; + if (!rumor) { + console.log( + `[GiftWrap] Gift wrap ${gw.id.slice(0, 8)} has no rumor (might need to load from cache)`, + ); + continue; + } // Collect all decrypted rumors (any kind) for future use allRumors.push({ giftWrap: gw, rumor }); @@ -482,6 +520,10 @@ class GiftWrapService { (b.lastMessage?.created_at ?? 0) - (a.lastMessage?.created_at ?? 0), ); + console.log( + `[GiftWrap] 💬 Updated conversations: ${conversations.length} conversations, ${allRumors.length} total rumors`, + ); + this.conversations$.next(conversations); }