mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-11 16:07:15 +02:00
perf: Make NIP-17 inbox sync on-demand for optimal login performance
This commit eliminates automatic inbox initialization on login, preventing
unwanted network requests and heavy I/O operations. Inbox sync now only
activates when users explicitly enable it.
## Problem
When logging in, the app would automatically:
- Initialize gift wrap service immediately
- Auto-enable inbox sync without user consent
- Load encrypted content from Dexie
- Wait up to 1 second for cache readiness
- Fetch inbox relay lists from network
- Subscribe to gift wrap events
- Open persistent relay connections
This caused:
- App hangs during login (network/IO blocking)
- Unwanted network activity before user opts in
- Poor performance on initial load
- Unnecessary resource consumption when DMs not needed
## Solution
### 1. On-Demand Initialization (useAccountSync.ts)
**Before**: Auto-init and auto-enable on every login
**After**: Watch settings$ and only init when user enables
```typescript
// Only initialize when user explicitly enables inbox sync
const settingsSub = giftWrapService.settings$.subscribe((settings) => {
if (settings.enabled && giftWrapService.userPubkey !== pubkey) {
giftWrapService.init(pubkey, signer);
}
});
```
### 2. Early Exit for Disabled State (gift-wrap.ts)
**Before**: Always loaded cache and relays, then checked enabled flag
**After**: Check enabled FIRST, exit early if disabled
```typescript
async init(pubkey: string, signer: ISigner | null) {
// Set basic properties
this.userPubkey = pubkey;
this.signer = signer;
// Early exit if disabled (prevents expensive operations)
if (!this.settings$.value.enabled) {
return;
}
// Only do expensive operations when enabled
await getStoredEncryptedContentIds();
await this.waitForCacheReady();
this.loadInboxRelays();
// ...
}
```
### 3. Updated Documentation
- Clarified on-demand initialization flow
- Updated lifecycle documentation with performance notes
- Changed "auto-enable" section to "on-demand" section
## Performance Impact
**Login Performance**:
- ✅ No automatic Dexie reads
- ✅ No cache waiting (up to 1s saved)
- ✅ No network requests for inbox relays
- ✅ No relay subscriptions until needed
- ✅ Instant login when DMs not needed
**User Control**:
- Users explicitly opt-in via InboxViewer toggle
- Clear UI feedback about enabling inbox sync
- No surprise network activity
**When Enabled**:
- Full functionality identical to before
- All optimizations from previous commits preserved
## Testing
- ✅ All 864 tests pass
- ✅ Build succeeds with no errors
- ✅ Verified on-demand initialization flow
- ✅ Confirmed no auto-init on login
## Files Changed
- `src/hooks/useAccountSync.ts` - Watch settings, init only when enabled
- `src/services/gift-wrap.ts` - Early exit if disabled, expose userPubkey
- `src/components/InboxViewer.tsx` - Updated comments
- `docs/gift-wrap-architecture.md` - Updated flow and lifecycle docs
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -124,14 +124,15 @@ Chat Component
|
||||
|
||||
### Receiving Messages (Inbox Flow)
|
||||
|
||||
1. **Account Login** → `useAccountSync` calls `giftWrapService.init(pubkey, signer)`
|
||||
2. **Fetch Inbox Relays** → Load kind 10050 from user's outbox relays
|
||||
3. **Subscribe to Gift Wraps** → Open subscription to inbox relays for `kind 1059` with `#p` = user pubkey
|
||||
4. **Gift Wrap Arrival** → EventStore receives event → GiftWrapService detects new gift wrap
|
||||
5. **Decrypt** (if auto-decrypt enabled) → Call `unlockGiftWrap(event, signer)`
|
||||
6. **Extract Rumor** → Get kind 14 DM from gift wrap inner content
|
||||
7. **Group into Conversations** → Compute conversation ID from participants → Update `conversations$` observable
|
||||
8. **UI Update** → InboxViewer/ChatViewer re-renders with new messages
|
||||
1. **User Enables Inbox Sync** → User toggles "Enable Inbox Sync" in InboxViewer settings
|
||||
2. **Service Initialization** → `useAccountSync` detects enabled setting and calls `giftWrapService.init(pubkey, signer)`
|
||||
3. **Fetch Inbox Relays** → Load kind 10050 from user's outbox relays
|
||||
4. **Subscribe to Gift Wraps** → Open subscription to inbox relays for `kind 1059` with `#p` = user pubkey
|
||||
5. **Gift Wrap Arrival** → EventStore receives event → GiftWrapService detects new gift wrap
|
||||
6. **Decrypt** (if auto-decrypt enabled) → Call `unlockGiftWrap(event, signer)`
|
||||
7. **Extract Rumor** → Get kind 14 DM from gift wrap inner content
|
||||
8. **Group into Conversations** → Compute conversation ID from participants → Update `conversations$` observable
|
||||
9. **UI Update** → InboxViewer/ChatViewer re-renders with new messages
|
||||
|
||||
### Sending Messages (Outbox Flow)
|
||||
|
||||
@@ -161,18 +162,19 @@ Chat Component
|
||||
|
||||
### Lifecycle
|
||||
|
||||
**Init** (on account login):
|
||||
**Init** (when user enables inbox sync):
|
||||
```typescript
|
||||
giftWrapService.init(pubkey, signer)
|
||||
1. Load persisted encrypted content IDs from Dexie
|
||||
2. Wait for cache readiness (prevents race condition)
|
||||
3. Subscribe to user's kind 10050 (inbox relays)
|
||||
4. Load stored gift wraps from Dexie into EventStore
|
||||
5. Subscribe to EventStore timeline for real-time updates
|
||||
6. Open persistent relay subscription for new gift wraps
|
||||
1. Check if enabled (early return if disabled for performance)
|
||||
2. Load persisted encrypted content IDs from Dexie
|
||||
3. Wait for cache readiness (prevents race condition)
|
||||
4. Subscribe to user's kind 10050 (inbox relays)
|
||||
5. Load stored gift wraps from Dexie into EventStore
|
||||
6. Subscribe to EventStore timeline for real-time updates
|
||||
7. Open persistent relay subscription for new gift wraps
|
||||
```
|
||||
|
||||
**Cleanup** (on account logout):
|
||||
**Cleanup** (on account logout or disable):
|
||||
```typescript
|
||||
giftWrapService.cleanup()
|
||||
1. Unsubscribe from all observables
|
||||
@@ -180,6 +182,8 @@ giftWrapService.cleanup()
|
||||
3. Clear in-memory state
|
||||
```
|
||||
|
||||
**Performance Note**: Init is only called when user explicitly enables inbox sync via InboxViewer toggle. This prevents automatic network requests and heavy I/O operations on login.
|
||||
|
||||
## Cache Strategy
|
||||
|
||||
### Encrypted Content Persistence
|
||||
@@ -231,13 +235,16 @@ giftWrapService.cleanup()
|
||||
- Clear UI feedback about why sending is blocked
|
||||
- Relay lists can be fetched in background without blocking UI
|
||||
|
||||
### Auto-Enable Inbox Sync
|
||||
### On-Demand Inbox Sync
|
||||
|
||||
**Default**: Inbox sync is **auto-enabled** on first login to ensure users receive DMs.
|
||||
**Default**: Inbox sync is **disabled** on login for optimal performance.
|
||||
|
||||
**Rationale**: Better UX to auto-enable with opt-out than require manual setup.
|
||||
**Rationale**: Prevents automatic network requests and heavy I/O operations on login. Users must explicitly enable inbox sync to receive DMs.
|
||||
|
||||
**User Control**: Settings UI allows disabling inbox sync and auto-decrypt.
|
||||
**User Control**:
|
||||
- Enable/disable inbox sync via toggle in InboxViewer
|
||||
- Configure auto-decrypt behavior in settings
|
||||
- Service initializes only when explicitly enabled
|
||||
|
||||
### Relay List Privacy
|
||||
|
||||
|
||||
Reference in New Issue
Block a user