Commit Graph

1533 Commits

Author SHA1 Message Date
Gigi
51b7e53385 debug: add extensive logging to track bookmark flow
Simplified to only show unencrypted bookmarks:
- Skip encrypted events entirely (no decrypt for now)
- This eliminates all parse errors

Added comprehensive logging:
- Controller: log when building, how many items, how many listeners, when emitting
- App: log when subscribing, when receiving bookmarks, when loading state changes

This will help identify where the disconnect is between controller and sidebar.
2025-10-17 23:27:04 +02:00
Gigi
8dbb18b1c8 fix: only build bookmarks from ready events (unencrypted or decrypted)
Filter events in buildAndEmitBookmarks to avoid parse errors:
- Unencrypted events: always included
- Encrypted events: only included if already decrypted

Progressive flow:
- Unencrypted event arrives → build bookmarks immediately
- Encrypted event arrives → wait for decrypt → then build bookmarks
- Each build only processes ready events (no parse errors)

Sidebar now populates with unencrypted bookmarks immediately, encrypted ones appear after decrypt.
2025-10-17 23:24:17 +02:00
Gigi
88bc7f690e feat: add progressive bookmark updates via callback pattern
Changed bookmark controller to emit updates progressively:
- Unencrypted events: immediate buildAndEmitBookmarks call
- Encrypted events: buildAndEmitBookmarks after decrypt completes
- Each update emits new bookmark list to subscribers

Removed coalescing/scheduling logic (scheduleBookmarkUpdate):
- Direct callback pattern is simpler and more predictable
- Updates happen exactly when events are ready

Progressive sidebar population now works correctly without parse errors.
2025-10-17 23:19:32 +02:00
Gigi
29ef21a1fa fix: restore Debug page decrypt display via onDecryptComplete callback
Added onDecryptComplete callback to controller:
- Controller emits decrypt results (eventId, publicCount, privateCount)
- Debug subscribes to see decryption progress
- setDecryptedEvents updated with decrypt results for UI display

Debug page now shows decrypted content counts for encrypted bookmark lists (like kind:30001 Amethyst-style NIP-04 bookmarks).
2025-10-17 23:14:10 +02:00
Gigi
7a75982715 fix: make controller onEvent non-blocking for queryEvents completion
Changed onEvent callback from async to synchronous:
- Removed await inside onEvent that was blocking observable
- Decryption now fires in background using .then()/.catch()
- Allows queryEvents to complete (EOSE) and trigger final bookmark build

This matches the working Debug pattern and allows bookmarks to appear in sidebar.
2025-10-17 23:12:19 +02:00
Gigi
f95f8f4bf1 refactor: remove deprecated bookmark service files
Deleted bookmarkService.ts and bookmarkStream.ts:
- All functionality now consolidated in bookmarkController.ts
- No more duplication of streaming/decrypt logic
- Single source of truth for bookmark loading
2025-10-17 23:09:23 +02:00
Gigi
9eef5855a9 feat: create shared bookmark controller for Debug-driven loading
Created bookmarkController.ts singleton:
- Encapsulates Debug's working streaming/decrypt logic
- API: start(), onRawEvent(), onBookmarks(), onLoading(), reset()
- Live deduplication, sequential decrypt, progressive updates

Updated App.tsx:
- Removed automatic loading triggers (useEffect)
- Subscribe to controller for bookmarks/loading state
- Manual refresh calls controller.start()

Updated Debug.tsx:
- Uses controller.start() instead of internal loader
- Subscribes to onRawEvent for UI display (unchanged)
- Pressing 'Load Bookmarks' now populates app sidebar

No automatic loads on login/mount. App passively receives updates from Debug-driven controller.
2025-10-17 23:08:36 +02:00
Gigi
2e70745bab fix: make bookmarksLoading optional in Me component
Made bookmarksLoading prop optional in MeProps since it's not currently used.
Reserved for future use when we want to show centralized loading state.

All linting and type checks now pass.
2025-10-17 22:52:16 +02:00
Gigi
8a971dfe52 refactor: pass bookmarks as props to Me component
Updated Me.tsx to receive bookmarks from centralized App state:
- Added bookmarks and bookmarksLoading to MeProps
- Removed local bookmarks state
- Removed bookmark caching (now handled at App level)

Updated Bookmarks.tsx to pass bookmarks props to Me component:
- Both 'me' and 'profile' views receive centralized bookmarks

All bookmark data now flows from App.tsx -> Bookmarks.tsx -> Me.tsx with no duplicate fetching or local state.
2025-10-17 22:50:07 +02:00
Gigi
a004e96eca feat: extract bookmark streaming helpers and centralize loading
Created bookmarkStream.ts with shared helpers:
- getEventKey: deduplication logic
- hasEncryptedContent: encryption detection
- loadBookmarksStream: streaming with non-blocking decryption

Refactored bookmarkService.ts to use shared helpers:
- Uses loadBookmarksStream for consistent behavior with Debug page
- Maintains progressive loading via callbacks
- Added accountManager parameter to fetchBookmarks

Updated App.tsx to pass accountManager to fetchBookmarks:
- Progressive loading indicators via onProgressUpdate callback

All bookmark loading now uses the same battle-tested streaming logic as Debug page.
2025-10-17 22:47:20 +02:00
Gigi
ce2432632c refactor: consolidate bookmark loading into single centralized function
Removed duplicate bookmark loading logic from Debug page:
- Debug 'Load Bookmarks' button now calls centralized onRefreshBookmarks
- Removed redundant state (bookmarkEvents, bookmarkStats, decryptedEvents)
- Removed unused helper functions (getKindName, getEventSize, etc.)
- Cleaned up imports (Helpers, queryEvents, collectBookmarksFromEvents)
- Simplified UI to show timing only, bookmarks visible in sidebar

Now there's truly ONE place for bookmark loading (bookmarkService.ts),
called from App.tsx and used throughout the app. Debug page's button
is now the same as clicking refresh in the bookmark sidebar.
2025-10-17 22:28:35 +02:00
Gigi
56b3100c8e fix: correct TypeScript types in Debug component
Fixed type error in Debug.tsx:
- Changed highlightVisibility from string to proper HighlightVisibility object
- Used 'support' prop instead of invalid 'children' prop for ThreePaneLayout
- Set showSupport={true} to properly render debug content

All linting and type checks now pass.
2025-10-17 22:19:09 +02:00
Gigi
327d65a128 feat: add bookmarks sidebar to Debug page
Added ThreePaneLayout to Debug page so bookmarks are visible:
- Debug page now has same layout as other pages
- Shows bookmarks sidebar on the left
- Debug content in the main pane
- Can compare centralized app bookmarks with Debug bookmarks side-by-side

This makes it easy to verify that centralized bookmark loading
works the same as the Debug page implementation.
2025-10-17 22:17:11 +02:00
Gigi
e5a7a07deb fix: bookmark loading completing properly now
Fixed critical issue where async operations in onEvent callback
were blocking the queryEvents observable from completing:

Changes:
1. Removed async/await from onEvent callback
   - Now just collects events synchronously
   - No blocking operations in the stream

2. Moved auto-decryption to after query completes
   - Batch process encrypted events after EOSE
   - Sequential decryption (cleaner, more predictable)

3. Simplified useEffect triggers in App.tsx
   - Removed duplicate mount + account change effects
   - Single effect handles both cases

Result: Query now completes properly, bookmarks load and display.
2025-10-17 22:13:58 +02:00
Gigi
5bd57573be debug: add detailed logging for bookmark loading
Added comprehensive console logs to diagnose bookmark loading issue:
- [app] prefix for all bookmark-related logs
- Log account pubkey being used
- Log each event as it arrives
- Log auto-decrypt attempts
- Log final processing steps
- Log when no bookmarks found

This will help identify where the bookmark loading is failing.
2025-10-17 22:11:47 +02:00
Gigi
c2223e6b08 feat: centralize bookmark loading with streaming and auto-decrypt
Implemented centralized bookmark loading system:
- Bookmarks loaded in App.tsx with streaming + auto-decrypt pattern
- Load triggers: login, app mount, manual refresh only
- No redundant fetching on route changes

Changes:
1. bookmarkService.ts: Refactored fetchBookmarks for streaming
   - Events stream with onEvent callback
   - Auto-decrypt encrypted content (NIP-04/NIP-44) as events arrive
   - Progressive UI updates during loading

2. App.tsx: Added centralized bookmark state
   - bookmarks and bookmarksLoading state in AppRoutes
   - loadBookmarks function with streaming support
   - Load on mount if account exists (app reopen)
   - Load when activeAccount changes (login)
   - handleRefreshBookmarks for manual refresh
   - Pass props to all Bookmarks components

3. Bookmarks.tsx: Accept bookmarks as props
   - Receive bookmarks, bookmarksLoading, onRefreshBookmarks
   - Pass onRefreshBookmarks to useBookmarksData

4. useBookmarksData.ts: Simplified to accept bookmarks as props
   - Removed bookmark fetching logic
   - Removed handleFetchBookmarks function
   - Accept onRefreshBookmarks callback
   - Use onRefreshBookmarks in handleRefreshAll

5. Me.tsx: Removed fallback bookmark loading
   - Removed fetchBookmarks import and calls
   - Use bookmarks directly from props (centralized source)

Benefits:
- Single source of truth for bookmarks
- No duplicate fetching across components
- Streaming + auto-decrypt for better UX
- Simpler, more maintainable code
- DRY principle: one place for bookmark loading
2025-10-17 22:06:33 +02:00
Gigi
d1ffc8c3f9 feat: auto-decrypt bookmarks as they arrive
Simplified bookmark loading by chaining loading and decryption:
- Events with encrypted content are automatically decrypted as they arrive
- Removed separate "Decrypt" button - now automatic
- Removed individual decrypt buttons - happens automatically
- Removed handleDecryptSingleEvent and related state
- Cleaner UI with just "Load Bookmarks" and "Clear" buttons

Benefits:
- Simpler, more intuitive UX
- DRY - single flow instead of 2-step process
- Shows decryption results inline as events stream in
- Uses same collectBookmarksFromEvents for consistency

Each event with encrypted content (NIP-04 or NIP-44) is decrypted
immediately in the onEvent callback, with results displayed inline.
2025-10-17 21:44:55 +02:00
Gigi
5a5cd14df5 docs: add Amethyst-style bookmarks section to Amber.md
Documented kind:30001 bookmark format used by Amethyst:
- Public bookmarks in event tags
- Private bookmarks in encrypted content (NIP-04 or NIP-44)

Explained why explicit NIP-04 detection (?iv= check) is required:
- Helpers.hasHiddenContent() only detects NIP-44
- Without NIP-04 detection, private bookmarks never get decrypted

Added example event structure and implementation notes for both
display logic and decryption logic.
2025-10-17 21:41:25 +02:00
Gigi
2fb25da9d6 fix: detect and decrypt NIP-04 encrypted bookmark content
Added explicit NIP-04 detection in bookmarkProcessing.ts:
- Check for ?iv= in content (NIP-04 format)
- Previously only checked Helpers.hasHiddenContent() (NIP-44 only)
- Now decrypts both NIP-04 and NIP-44 encrypted bookmarks

This fixes individual bookmark decryption returning 0 private items
despite having encrypted content.
2025-10-17 21:39:15 +02:00
Gigi
21228cd212 refactor: unify debug logging under [bunker] prefix
Changed all debug console logs to use [bunker] prefix with emojis:
- 🔵 Individual decrypt clicked
- 🔓 Decrypting event (with details)
-  Event decrypted (with results)
- ⚠️  Warnings (no account, 0 private items)
-  Errors

Now users can filter console by 'bunker' to see all relevant logs.
2025-10-17 21:38:23 +02:00
Gigi
e0b86a84ba debug: add detailed logging for individual bookmark decryption
Added extensive debug logging to help diagnose decryption issues:
- Event details (kind, content length, encryption type)
- Signer information (type, availability)
- Warning when 0 private items found despite encrypted content

This will help identify why decryption might be failing silently.
2025-10-17 21:34:47 +02:00
Gigi
c3a4e41968 fix: detect NIP-04 encrypted content in bookmark events
Added explicit detection for NIP-04 encrypted content format:
- NIP-04: base64 content with ?iv= suffix
- NIP-44: detected by Helpers.hasHiddenContent()
- Encrypted tags: detected by Helpers.hasHiddenTags()

Created hasEncryptedContent() helper that checks all three cases.
Now properly shows padlock emoji and decrypt button for events with
NIP-04 encrypted content (like the example with ?iv=5KzDXv09...).
2025-10-17 21:31:21 +02:00
Gigi
f3205843ac fix: use consistent encrypted content detection for padlock and decrypt button
Fixed mismatch between padlock display and decrypt button visibility:
- Both now use Helpers.hasHiddenContent() and Helpers.hasHiddenTags()
- Previously padlock showed for ANY content, button only for encrypted
- Now both correctly detect actual encrypted content

This ensures decrypt buttons appear whenever padlocks are shown.
2025-10-17 21:27:02 +02:00
Gigi
9a03dd312f feat: add individual decrypt buttons for bookmark events
Added per-event decryption on debug page:
- Small 'decrypt' button appears on events with encrypted content
- Shows spinner while decrypting individual event
- Displays decryption results (public/private counts) inline
- Button disappears after successful decryption

Uses Helpers.hasHiddenContent() and Helpers.hasHiddenTags() to detect
which events need decryption.

Allows testing individual event decryption without batch operation.
2025-10-17 21:25:28 +02:00
Gigi
b711b21048 feat: show correct connection type on debug page
Updated debug page to display the actual account type:
- Browser Extension (type: 'extension')
- Bunker Connection (type: 'nostr-connect')
- Account Connection (fallback)

Changes:
- Section title now reflects active account type
- Connection status message updated accordingly
- No longer always shows 'Bunker Connection' regardless of type

Makes it clear to users which authentication method they're using.
2025-10-17 21:21:39 +02:00
Gigi
8eaba04d91 refactor: disable account queue globally
Set accounts.disableQueue = true on AccountManager during initialization:
- Applies to all accounts automatically
- No need for temporary queue toggling in individual operations
- Makes all bunker requests instant (no internal queueing)

Removed temporary queue disabling from bookmarkProcessing.ts since
it's now globally disabled.

Updated Amber.md to document the global approach.

This eliminates the root cause of decrypt hangs - requests no longer
wait in an internal queue for previous requests to complete.
2025-10-17 21:19:21 +02:00
Gigi
0785b034e4 perf: use shorter timeouts for debug page bookmark loading
Reduced timeouts to trust EOSE from fast relays:
- Local: 800ms (down from 1200ms)
- Remote: 2000ms (down from 6000ms)

The query completes when relays send EOSE, not when timeout expires.
Fast relays send EOSE in <1 second, so total time should be much less
than the previous 6-second wait.

Result: Debug page bookmark loading now completes in ~1-2 seconds instead of always 6 seconds.
2025-10-17 21:06:05 +02:00
Gigi
47e698f197 feat: stream bookmark events on debug page
Implemented live streaming of bookmark events as they arrive from relays:
- Events appear immediately as relays respond
- Live deduplication of replaceable events (30003, 30001, 10003)
- Keep newest version when duplicates found
- Web bookmarks (39701) not deduplicated (each unique)

Benefits:
- Much more responsive UI - see events immediately
- Better user experience with progress visibility
- Deduplication happens in real-time

Uses queryEvents onEvent callback to process events as they stream in.
2025-10-17 21:01:10 +02:00
Gigi
3a752a761a refactor: remove artificial timeouts from bookmark decryption
Removed all withTimeout wrappers - now matches debug page behavior:
- Direct decrypt calls with no artificial timeouts
- Let operations fail naturally and quickly
- Bunker responds instantly (success or rejection)

No timeouts needed because:
1. Account queue is disabled (requests sent immediately)
2. Only decrypting truly encrypted content (no wasted attempts)
3. Bunker either succeeds quickly or fails quickly

This makes bookmark decryption instant, just like the debug page
encryption/decryption tests.
2025-10-17 20:54:45 +02:00
Gigi
f6cc49c07a fix: only decrypt events with actual encrypted content
Use applesauce Helpers.hasHiddenContent() instead of checking for
any content. This properly detects encrypted content and avoids
sending unnecessary decrypt requests to Amber for events that just
have plain text content.

Before: (evt.content && evt.content.length > 0)
After: Helpers.hasHiddenContent(evt)

Result:
- Only events with encrypted content sent to Amber
- Reduces unnecessary decrypt requests
- Faster bookmark loading
2025-10-17 20:53:25 +02:00
Gigi
5c4fca9cc9 docs: document critical queue disabling requirement in Amber.md
Added findings about applesauce-accounts queue issue:
- Queue MUST be disabled for batch decrypt operations
- Default queueing blocks all requests until first completes
- This was the primary cause of hangs and timeouts
- Updated performance improvements section with all optimizations
- Updated conclusion with key learnings

Ref: https://hzrd149.github.io/applesauce/typedoc/classes/applesauce-accounts.BaseAccount.html#disablequeue
2025-10-17 20:47:13 +02:00
Gigi
536a7ce1fa fix: disable account queue during batch decrypt operations
The applesauce BaseAccount queues requests by default, waiting for
each to complete before sending the next. This caused decrypt requests
to timeout before ever reaching Amber/bunker.

Solution:
- Set disableQueue=true before batch operations
- All decrypt requests sent immediately
- Restore original queue state after completion

This should fix the hanging/timeout issue where Amber never saw
the decrypt requests because they were stuck in the account's queue.

Ref: https://hzrd149.github.io/applesauce/typedoc/classes/applesauce-accounts.BaseAccount.html#disablequeue
2025-10-17 20:46:00 +02:00
Gigi
61072aef40 refactor: remove concurrent decryption in favor of sequential
Removed mapWithConcurrency hack:
- Simpler code with plain for loop
- More predictable behavior
- Better for bunker signers (network round-trips)
- Each decrypt happens in order, no race conditions

Sequential processing is cleaner and works better with remote signers.
2025-10-17 20:44:48 +02:00
Gigi
b7ec1fcf06 fix: add 5s timeout and smart encryption detection for bookmarks
Changes:
- Use 5-second timeout instead of 30 seconds
- Detect encryption method from content format
- NIP-04 has '?iv=' in content, NIP-44 doesn't
- Try the likely method first to avoid unnecessary timeouts
- Falls back to other method if first fails

This should:
- Prevent hanging forever (5s timeout)
- Be much faster than 30s when wrong method is tried
- Usually decrypt instantly when right method is used first
2025-10-17 20:42:46 +02:00
Gigi
d2fd8fb8fe perf: remove 30s timeout from bookmark decryption
The withTimeout wrapper was causing decrypt operations to wait
30 seconds before failing, even when bunker rejection was instant.

Now uses the same direct approach as the debug page encryption tests:
- No artificial timeouts
- Fast natural failures
- Should reduce decrypt time from 30s+ to near-instant

Fixes slow bookmark loading when bunker doesn't support nip44.
2025-10-17 20:40:07 +02:00
Gigi
68ee1b3122 feat: add clear button for bookmark data
- Right-aligned clear button in the same row as load/decrypt
- Clears events, stats, and timing data
- Disabled when no data to clear
2025-10-17 20:35:17 +02:00
Gigi
a37735fc1c refactor: show decrypted bookmarks above loaded events 2025-10-17 20:33:25 +02:00
Gigi
de0f587174 refactor: display bookmark event stats on separate lines 2025-10-17 20:21:24 +02:00
Gigi
f977561779 feat: restore padlock emoji for encrypted content indicator 2025-10-17 20:21:07 +02:00
Gigi
043ea168fb feat: display full event ID for easy copy/paste 2025-10-17 20:20:48 +02:00
Gigi
5336bafed4 refactor: remove emojis from bookmark event display 2025-10-17 20:20:24 +02:00
Gigi
c51291bf81 feat: add performance timing to bookmark loading and decryption
- Track load and decrypt operation durations
- Display live timing with spinner during operations
- Show completed timing in milliseconds
- Uses same Stat component as encryption timing
2025-10-17 20:19:48 +02:00
Gigi
489e48fe4d feat: enhance bookmark event display with detailed info
- Show kind names (Simple List, Replaceable List, etc)
- Display data size in human-readable format (B, KB, MB)
- Show count of public bookmarks per event
- Indicate presence of encrypted content
- Show d-tag and title for better identification
2025-10-17 20:17:58 +02:00
Gigi
744a145e9f fix: resolve linting errors in App.tsx and async.ts 2025-10-17 20:09:20 +02:00
Gigi
7ad925dbd3 feat: add bookmark loading and decryption section to debug page 2025-10-17 20:08:08 +02:00
Gigi
a69298a3a9 perf(bunker): non-blocking bookmark decryption with concurrency limit
- Add withTimeout and mapWithConcurrency helpers in utils/async.ts
- Refactor collectBookmarksFromEvents to decrypt with 6-way concurrency
- Public bookmarks collected immediately, private decrypted in parallel
- Each decrypt wrapped with 30s timeout safety net
- Document non-blocking publish and concurrent decrypt in Amber.md
2025-10-17 13:27:50 +02:00
Gigi
2c3aff0407 perf(bunker): make NIP-46 publish non-blocking at app wiring level; resolve immediately and let responses drive timing/results bunker-encrypt-decrypt 2025-10-17 13:09:42 +02:00
Gigi
aad35d41db fix(debug): return benign object from fire-and-forget publish so timing UI remains stable 2025-10-17 13:06:17 +02:00
Gigi
cc6189a5d9 perf(bunker): fire-and-forget NIP-46 publish in app wrapper so UI isn’t blocked waiting on relay publish; encryption/decryption results now display immediately on /debug 2025-10-17 13:04:59 +02:00
Gigi
18bf8f9a2c ui(debug): use existing color pattern for red disconnect button with proper styling and hover effects 2025-10-17 12:56:47 +02:00