refactor: clean up bunker implementation for better maintainability

- Extract reconnectBunkerSigner into reusable helper function
- Reduce excessive debug logging in App.tsx (90+ lines → 30 lines)
- Simplify account restoration logic with cleaner conditionals
- Remove verbose signing logs from highlightCreationService
- Keep only essential error logs for debugging
- Follows DRY principles and applesauce patterns
This commit is contained in:
Gigi
2025-10-16 22:32:06 +02:00
parent 118ab46ac0
commit bf849c9faa
3 changed files with 46 additions and 93 deletions

View File

@@ -8,6 +8,7 @@ import { AccountManager, Accounts } from 'applesauce-accounts'
import { registerCommonAccountTypes } from 'applesauce-accounts/accounts' import { registerCommonAccountTypes } from 'applesauce-accounts/accounts'
import { RelayPool } from 'applesauce-relay' import { RelayPool } from 'applesauce-relay'
import { NostrConnectSigner } from 'applesauce-signers' import { NostrConnectSigner } from 'applesauce-signers'
import { reconnectBunkerSigner } from './services/nostrConnect'
import { createAddressLoader } from 'applesauce-loaders/loaders' import { createAddressLoader } from 'applesauce-loaders/loaders'
import Bookmarks from './components/Bookmarks' import Bookmarks from './components/Bookmarks'
import RouteDebug from './components/RouteDebug' import RouteDebug from './components/RouteDebug'
@@ -192,51 +193,29 @@ function App() {
// NostrConnectAccount.fromJSON needs this to restore the signer // NostrConnectAccount.fromJSON needs this to restore the signer
const pool = new RelayPool() const pool = new RelayPool()
NostrConnectSigner.pool = pool NostrConnectSigner.pool = pool
console.log('[bunker] ✅ Pool assigned to NostrConnectSigner (before account load)')
// Create a relay group for better event deduplication and management
pool.group(RELAYS) pool.group(RELAYS)
console.log('[bunker] Created relay group with', RELAYS.length, 'relays (including local)')
// Load persisted accounts from localStorage // Load persisted accounts from localStorage
try { try {
const accountsJson = localStorage.getItem('accounts') const accountsJson = localStorage.getItem('accounts')
console.log('[bunker] Raw accounts from localStorage:', accountsJson) if (accountsJson) {
await accounts.fromJSON(JSON.parse(accountsJson))
}
const json = JSON.parse(accountsJson || '[]') // Restore active account
console.log('[bunker] Parsed accounts:', json.length, 'accounts')
await accounts.fromJSON(json)
console.log('[bunker] Loaded', accounts.accounts.length, 'accounts from storage')
console.log('[bunker] Account types:', accounts.accounts.map(a => ({ id: a.id, type: a.type })))
// Load active account from storage
const activeId = localStorage.getItem('active') const activeId = localStorage.getItem('active')
console.log('[bunker] Active ID from localStorage:', activeId) if (activeId && accounts.getAccount(activeId)) {
accounts.setActive(activeId)
if (activeId) {
const account = accounts.getAccount(activeId)
console.log('[bunker] Found account for ID?', !!account, account?.type)
if (account) {
accounts.setActive(activeId)
console.log('[bunker] ✅ Restored active account:', activeId, 'type:', account.type)
} else {
console.warn('[bunker] ⚠️ Active ID found but account not in list')
}
} else {
console.log('[bunker] No active account ID in localStorage')
} }
} catch (err) { } catch (err) {
console.error('[bunker] Failed to load accounts from storage:', err) console.error('[bunker] Failed to restore accounts:', err)
} }
// Subscribe to accounts changes and persist to localStorage // Persist accounts to localStorage
const accountsSub = accounts.accounts$.subscribe(() => { const accountsSub = accounts.accounts$.subscribe(() => {
localStorage.setItem('accounts', JSON.stringify(accounts.toJSON())) localStorage.setItem('accounts', JSON.stringify(accounts.toJSON()))
}) })
// Subscribe to active account changes and persist to localStorage
const activeSub = accounts.active$.subscribe((account) => { const activeSub = accounts.active$.subscribe((account) => {
if (account) { if (account) {
localStorage.setItem('active', account.id) localStorage.setItem('active', account.id)
@@ -245,68 +224,20 @@ function App() {
} }
}) })
// Reconnect bunker signers when active account changes // Reconnect bunker signers on page load
// Keep track of which accounts we've already reconnected to avoid double-connecting
const reconnectedAccounts = new Set<string>() const reconnectedAccounts = new Set<string>()
const bunkerReconnectSub = accounts.active$.subscribe(async (account) => {
const bunkerReconnectSub = accounts.active$.subscribe(async (account) => { if (account?.type === 'nostr-connect' && !reconnectedAccounts.has(account.id)) {
console.log('[bunker] Active account changed:', { reconnectedAccounts.add(account.id)
hasAccount: !!account,
type: account?.type, try {
id: account?.id await reconnectBunkerSigner(account as Accounts.NostrConnectAccount<unknown>, pool)
}) console.log('[bunker] Reconnected to bunker signer')
} catch (error) {
if (account && account.type === 'nostr-connect') { console.error('[bunker] Failed to reconnect signer:', error)
const nostrConnectAccount = account as Accounts.NostrConnectAccount<unknown> }
}
// Skip if we've already reconnected this account })
if (reconnectedAccounts.has(account.id)) {
console.log('[bunker] ⏭️ Already reconnected this account, skipping')
return
}
console.log('[bunker] Account detected. Status:', {
listening: nostrConnectAccount.signer.listening,
isConnected: nostrConnectAccount.signer.isConnected,
hasRemote: !!nostrConnectAccount.signer.remote,
bunkerRelays: nostrConnectAccount.signer.relays
})
try {
// Add bunker's relays to the pool so signing requests can be sent/received
const bunkerRelays = nostrConnectAccount.signer.relays || []
console.log('[bunker] Adding bunker relays to pool:', bunkerRelays)
pool.group(bunkerRelays)
// Just ensure the signer is listening for responses - don't call connect() again
// The fromBunkerURI already connected with permissions during login
if (!nostrConnectAccount.signer.listening) {
console.log('[bunker] Opening signer subscription...')
await nostrConnectAccount.signer.open()
console.log('[bunker] ✅ Signer subscription opened')
} else {
console.log('[bunker] ✅ Signer already listening')
}
// Mark as connected so requireConnection() doesn't call connect() again
// The bunker remembers the permissions from the initial connection
nostrConnectAccount.signer.isConnected = true
console.log('[bunker] Final signer status:', {
listening: nostrConnectAccount.signer.listening,
isConnected: nostrConnectAccount.signer.isConnected,
remote: nostrConnectAccount.signer.remote,
relays: nostrConnectAccount.signer.relays
})
// Mark this account as reconnected
reconnectedAccounts.add(account.id)
console.log('[bunker] 🎉 Signer ready for signing')
} catch (error) {
console.error('[bunker] ❌ Failed to open signer:', error)
}
}
})
// Keep all relay connections alive indefinitely by creating a persistent subscription // Keep all relay connections alive indefinitely by creating a persistent subscription
// This prevents disconnection when no other subscriptions are active // This prevents disconnection when no other subscriptions are active

View File

@@ -116,9 +116,7 @@ export async function createHighlight(
} }
// Sign the event // Sign the event
console.log('[bunker] Signing highlight event...', { kind: highlightEvent.kind, tags: highlightEvent.tags.length })
const signedEvent = await factory.sign(highlightEvent) const signedEvent = await factory.sign(highlightEvent)
console.log('[bunker] ✅ Highlight signed successfully!', { id: signedEvent.id.slice(0, 8) })
// Use unified write service to store and publish // Use unified write service to store and publish
await publishEvent(relayPool, eventStore, signedEvent) await publishEvent(relayPool, eventStore, signedEvent)

View File

@@ -1,4 +1,6 @@
import { NostrConnectSigner } from 'applesauce-signers' import { NostrConnectSigner } from 'applesauce-signers'
import { Accounts } from 'applesauce-accounts'
import { RelayPool } from 'applesauce-relay'
/** /**
* Get default NIP-46 permissions for bunker connections * Get default NIP-46 permissions for bunker connections
@@ -24,3 +26,25 @@ export function getDefaultBunkerPermissions(): string[] {
] ]
} }
/**
* Reconnect a bunker signer after page load
* Ensures the signer is listening and connected to the correct relays
*/
export async function reconnectBunkerSigner(
account: Accounts.NostrConnectAccount<unknown>,
pool: RelayPool
): Promise<void> {
// Add bunker relays to pool for signing communication
if (account.signer.relays) {
pool.group(account.signer.relays)
}
// Open signer subscription if not already listening
if (!account.signer.listening) {
await account.signer.open()
}
// Mark as connected (bunker remembers permissions from initial connection)
account.signer.isConnected = true
}