diff --git a/src/components/Debug.tsx b/src/components/Debug.tsx index 63ed6a4b..25dc2c38 100644 --- a/src/components/Debug.tsx +++ b/src/components/Debug.tsx @@ -7,14 +7,9 @@ import { useEventStore } from 'applesauce-react/hooks' import { Accounts } from 'applesauce-accounts' import { NostrConnectSigner } from 'applesauce-signers' import { RelayPool } from 'applesauce-relay' -import { Helpers } from 'applesauce-core' import { getDefaultBunkerPermissions } from '../services/nostrConnect' import { DebugBus, type DebugLogEntry } from '../utils/debugBus' import ThreePaneLayout from './ThreePaneLayout' -import { queryEvents } from '../services/dataFetch' -import { KINDS } from '../config/kinds' -import { collectBookmarksFromEvents } from '../services/bookmarkProcessing' -import type { NostrEvent } from '../services/bookmarkHelpers' import { Bookmark } from '../types/bookmarks' import { useBookmarksUI } from '../hooks/useBookmarksUI' import { useSettings } from '../hooks/useSettings' @@ -72,15 +67,8 @@ const Debug: React.FC = ({ const [isBunkerLoading, setIsBunkerLoading] = useState(false) const [bunkerError, setBunkerError] = useState(null) - // Bookmark loading state - const [bookmarkEvents, setBookmarkEvents] = useState([]) - const [isLoadingBookmarks, setIsLoadingBookmarks] = useState(false) - const [bookmarkStats, setBookmarkStats] = useState<{ public: number; private: number } | null>(null) + // Bookmark loading timing (actual loading uses centralized function) const [tLoadBookmarks, setTLoadBookmarks] = useState(null) - const [tDecryptBookmarks, setTDecryptBookmarks] = useState(null) - - // Individual event decryption results - const [decryptedEvents, setDecryptedEvents] = useState>(new Map()) // Live timing state const [liveTiming, setLiveTiming] = useState<{ @@ -109,63 +97,6 @@ const Debug: React.FC = ({ const hasNip04 = typeof (signer as { nip04?: { encrypt?: unknown; decrypt?: unknown } } | undefined)?.nip04?.encrypt === 'function' const hasNip44 = typeof (signer as { nip44?: { encrypt?: unknown; decrypt?: unknown } } | undefined)?.nip44?.encrypt === 'function' - const getKindName = (kind: number): string => { - switch (kind) { - case KINDS.ListSimple: return 'Simple List (10003)' - case KINDS.ListReplaceable: return 'Replaceable List (30003)' - case KINDS.List: return 'List (30001)' - case KINDS.WebBookmark: return 'Web Bookmark (39701)' - default: return `Kind ${kind}` - } - } - - const getEventSize = (evt: NostrEvent): number => { - const content = evt.content || '' - const tags = JSON.stringify(evt.tags || []) - return content.length + tags.length - } - - const hasEncryptedContent = (evt: NostrEvent): boolean => { - // Check for NIP-44 encrypted content (detected by Helpers) - if (Helpers.hasHiddenContent(evt)) return true - - // Check for NIP-04 encrypted content (base64 with ?iv= suffix) - if (evt.content && evt.content.includes('?iv=')) return true - - // Check for encrypted tags - if (Helpers.hasHiddenTags(evt) && !Helpers.isHiddenTagsUnlocked(evt)) return true - - return false - } - - const getBookmarkCount = (evt: NostrEvent): { public: number; private: number } => { - const publicTags = (evt.tags || []).filter((t: string[]) => t[0] === 'e' || t[0] === 'a') - const hasEncrypted = hasEncryptedContent(evt) - return { - public: publicTags.length, - private: hasEncrypted ? 1 : 0 // Can't know exact count until decrypted - } - } - - const formatBytes = (bytes: number): string => { - if (bytes < 1024) return `${bytes} B` - if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB` - return `${(bytes / (1024 * 1024)).toFixed(2)} MB` - } - - const getEventKey = (evt: NostrEvent): string => { - if (evt.kind === 30003 || evt.kind === 30001) { - // Replaceable: kind:pubkey:dtag - const dTag = evt.tags?.find((t: string[]) => t[0] === 'd')?.[1] || '' - return `${evt.kind}:${evt.pubkey}:${dTag}` - } else if (evt.kind === 10003) { - // Simple list: kind:pubkey - return `${evt.kind}:${evt.pubkey}` - } - // Web bookmarks: use event id (no deduplication) - return evt.id - } - const doEncrypt = async (mode: 'nip44' | 'nip04') => { if (!signer || !pubkey) return try { @@ -235,103 +166,20 @@ const Debug: React.FC = ({ } const handleLoadBookmarks = async () => { - if (!relayPool || !activeAccount) { - DebugBus.warn('debug', 'Cannot load bookmarks: missing relayPool or activeAccount') - return - } - - try { - setIsLoadingBookmarks(true) - setBookmarkStats(null) - setBookmarkEvents([]) // Clear existing events - DebugBus.info('debug', 'Loading bookmark events...') - - // Start timing - const start = performance.now() - setLiveTiming(prev => ({ ...prev, loadBookmarks: { startTime: start } })) - - // Get signer for auto-decryption - const fullAccount = accountManager.getActive() - const signerCandidate = fullAccount || activeAccount - - // Use onEvent callback to stream events as they arrive - // Trust EOSE - completes when relays finish, no artificial timeouts - const rawEvents = await queryEvents( - relayPool, - { kinds: [KINDS.ListSimple, KINDS.ListReplaceable, KINDS.List, KINDS.WebBookmark], authors: [activeAccount.pubkey] }, - { - onEvent: async (evt) => { - // Add event immediately with live deduplication - setBookmarkEvents(prev => { - // Create unique key for deduplication - const key = getEventKey(evt) - - // Find existing event with same key - const existingIdx = prev.findIndex(e => getEventKey(e) === key) - - if (existingIdx >= 0) { - // Replace if newer - const existing = prev[existingIdx] - if ((evt.created_at || 0) > (existing.created_at || 0)) { - const newEvents = [...prev] - newEvents[existingIdx] = evt - return newEvents - } - return prev // Keep existing (it's newer) - } - - // Add new event - return [...prev, evt] - }) - - // Auto-decrypt if event has encrypted content - if (hasEncryptedContent(evt)) { - console.log('[bunker] 🔓 Auto-decrypting event', evt.id.slice(0, 8)) - try { - const { publicItemsAll, privateItemsAll } = await collectBookmarksFromEvents( - [evt], - activeAccount, - signerCandidate - ) - setDecryptedEvents(prev => new Map(prev).set(evt.id, { - public: publicItemsAll.length, - private: privateItemsAll.length - })) - console.log('[bunker] ✅ Auto-decrypted:', evt.id.slice(0, 8), { - public: publicItemsAll.length, - private: privateItemsAll.length - }) - } catch (error) { - console.error('[bunker] ❌ Auto-decrypt failed:', evt.id.slice(0, 8), error) - } - } - } - } - ) - - const ms = Math.round(performance.now() - start) - setLiveTiming(prev => ({ ...prev, loadBookmarks: undefined })) - setTLoadBookmarks(ms) - - DebugBus.info('debug', `Loaded ${rawEvents.length} bookmark events`, { - kinds: rawEvents.map(e => e.kind).join(', '), - ms - }) - } catch (error) { - setLiveTiming(prev => ({ ...prev, loadBookmarks: undefined })) - DebugBus.error('debug', 'Failed to load bookmarks', error instanceof Error ? error.message : String(error)) - } finally { - setIsLoadingBookmarks(false) - } + // Use the centralized bookmark loading (same as refresh button in sidebar) + const start = performance.now() + setLiveTiming(prev => ({ ...prev, loadBookmarks: { startTime: start } })) + + await onRefreshBookmarks() + + const ms = Math.round(performance.now() - start) + setLiveTiming(prev => ({ ...prev, loadBookmarks: undefined })) + setTLoadBookmarks(ms) } const handleClearBookmarks = () => { - setBookmarkEvents([]) - setBookmarkStats(null) setTLoadBookmarks(null) - setTDecryptBookmarks(null) - setDecryptedEvents(new Map()) - DebugBus.info('debug', 'Cleared bookmark data') + DebugBus.info('debug', 'Cleared bookmark timing data') } const handleBunkerLogin = async () => { @@ -588,15 +436,19 @@ const Debug: React.FC = ({ {/* Bookmark Loading Section */}

Bookmark Loading

-
Test bookmark loading with auto-decryption (kinds: 10003, 30003, 30001, 39701)
+
+ Uses centralized bookmark loading (same as refresh button in sidebar) +
+ Bookmarks: {bookmarks.length > 0 ? `${bookmarks[0]?.individualBookmarks?.length || 0} items` : '0 items'} +
-
- {bookmarkStats && ( -
-
Decrypted Bookmarks:
-
-
Public: {bookmarkStats.public}
-
Private: {bookmarkStats.private}
-
Total: {bookmarkStats.public + bookmarkStats.private}
-
-
- )} - - {bookmarkEvents.length > 0 && ( -
-
Loaded Events ({bookmarkEvents.length}):
-
- {bookmarkEvents.map((evt, idx) => { - const dTag = evt.tags?.find((t: string[]) => t[0] === 'd')?.[1] - const titleTag = evt.tags?.find((t: string[]) => t[0] === 'title')?.[1] - const size = getEventSize(evt) - const counts = getBookmarkCount(evt) - const hasEncrypted = hasEncryptedContent(evt) - const decryptResult = decryptedEvents.get(evt.id) - - return ( -
-
{getKindName(evt.kind)}
- {dTag &&
d-tag: {dTag}
} - {titleTag &&
title: {titleTag}
} -
-
Size: {formatBytes(size)}
-
Public: {counts.public}
- {hasEncrypted &&
🔒 Has encrypted content
} -
- {decryptResult && ( -
-
✓ Decrypted: {decryptResult.public} public, {decryptResult.private} private
-
- )} -
ID: {evt.id}
-
- ) - })} -
-
- )} +
+ â„šī¸ This button calls the same centralized bookmark loading function as the refresh button in the sidebar. + Check the sidebar to see the loaded bookmarks, or check the console for [app] logs. +
{/* Debug Logs Section */}