refactor: improve nostr connection and message handling

- Add WebSocket manager class for better connection handling
- Split message handling into separate store
- Add encryption service class
- Create chat composable for reusable chat logic
- Add error handling service
- Add connection status indicators throughout app
- Add message persistence service
- Improve subscription reliability with EOSE handling
- Add connection state management
- Hide status text on mobile for better space usage

These changes improve code organization, reliability, and user experience by:
- Better separation of concerns
- More robust error handling
- Clearer connection status feedback
- Improved message persistence
- More maintainable WebSocket management
- Better mobile responsiveness

Breaking changes:
- Message handling moved to separate store
- WebSocket connections now managed through NostrWebSocketManager
- Encryption now handled through NostrEncryption service
This commit is contained in:
padreug 2025-02-15 00:26:11 +01:00
parent be93965e13
commit 5eb46e96c3
11 changed files with 169 additions and 26 deletions

9
src/lib/encryption.ts Normal file
View file

@ -0,0 +1,9 @@
export class NostrEncryption {
static async encrypt(privkey: string, pubkey: string, content: string) {
return await window.NostrTools.nip04.encrypt(privkey, pubkey, content)
}
static async decrypt(privkey: string, pubkey: string, content: string) {
return await window.NostrTools.nip04.decrypt(privkey, pubkey, content)
}
}

14
src/lib/error.ts Normal file
View file

@ -0,0 +1,14 @@
export class ErrorHandler {
static handle(error: unknown, context: string) {
console.error(`Error in ${context}:`, error)
if (error instanceof Error) {
// Handle specific error types
if (error.name === 'TimeoutError') {
return 'Connection timed out. Please try again.'
}
}
return 'An unexpected error occurred'
}
}

22
src/lib/storage.ts Normal file
View file

@ -0,0 +1,22 @@
export class MessageStorage {
static saveMessages(pubkey: string, messages: DirectMessage[]) {
try {
localStorage.setItem(
`messages_${pubkey}`,
JSON.stringify(messages)
)
} catch (err) {
console.error('Failed to save messages:', err)
}
}
static loadMessages(pubkey: string): DirectMessage[] {
try {
const stored = localStorage.getItem(`messages_${pubkey}`)
return stored ? JSON.parse(stored) : []
} catch (err) {
console.error('Failed to load messages:', err)
return []
}
}
}

35
src/lib/websocket.ts Normal file
View file

@ -0,0 +1,35 @@
// Create a new WebSocket manager class
export class NostrWebSocketManager {
private connections: Map<string, any> = new Map()
private subscriptions: Map<string, any[]> = new Map()
async connect(url: string) {
if (this.connections.has(url)) return this.connections.get(url)
const relay = window.NostrTools.relayInit(url)
try {
await relay.connect()
this.connections.set(url, relay)
this.subscriptions.set(url, [])
return relay
} catch (err) {
console.error(`Failed to connect to ${url}:`, err)
return null
}
}
addSubscription(url: string, sub: any) {
const subs = this.subscriptions.get(url) || []
subs.push(sub)
this.subscriptions.set(url, subs)
}
cleanup() {
for (const [url, subs] of this.subscriptions.entries()) {
subs.forEach(sub => sub.unsub?.())
this.connections.get(url)?.close()
}
this.connections.clear()
this.subscriptions.clear()
}
}