refactor: Simplify Nostr connection management and enhance store integration

- Refactor useNostr composable to utilize a centralized Pinia store for connection state and client management.
- Update NostrFeed and App components to leverage the new store-based approach for relay configuration and client instantiation.
- Remove direct relay URL handling from components, improving maintainability and consistency across the application.
This commit is contained in:
padreug 2025-07-02 19:49:06 +02:00
parent 0324cf8ec5
commit 236a8a59b9
5 changed files with 85 additions and 38 deletions

View file

@ -10,8 +10,7 @@ import { identity } from '@/composables/useIdentity'
import { toast } from 'vue-sonner' import { toast } from 'vue-sonner'
import { config } from '@/lib/config' import { config } from '@/lib/config'
const relays = config.nostr.relays const { isConnected, isConnecting, error, connect, disconnect } = useNostr()
const { isConnected, isConnecting, error, connect, disconnect } = useNostr({ relays })
const showPasswordDialog = ref(false) const showPasswordDialog = ref(false)

View file

@ -18,8 +18,7 @@ const notes = ref<NostrNote[]>([])
const isLoading = ref(true) const isLoading = ref(true)
const error = ref<Error | null>(null) const error = ref<Error | null>(null)
const relayUrls = props.relays || config.nostr.relays const { getClient } = useNostr(props.relays ? { relays: props.relays } : undefined)
const { disconnect } = useNostr({ relays: relayUrls })
// Get admin/moderator pubkeys from centralized config // Get admin/moderator pubkeys from centralized config
const adminPubkeys = config.nostr.adminPubkeys const adminPubkeys = config.nostr.adminPubkeys
@ -29,7 +28,7 @@ async function loadNotes() {
isLoading.value = true isLoading.value = true
error.value = null error.value = null
const client = new NostrClient({ relays: relayUrls }) const client = getClient()
await client.connect() await client.connect()
// Configure fetch options based on feed type // Configure fetch options based on feed type

View file

@ -1,38 +1,24 @@
import { ref } from 'vue' import { storeToRefs } from 'pinia'
import { NostrClient, type NostrClientConfig } from '@/lib/nostr/client' import { useNostrStore } from '@/stores/nostr'
import type { NostrClientConfig } from '@/lib/nostr/client'
export function useNostr(config: NostrClientConfig) { export function useNostr(config?: NostrClientConfig) {
const client = new NostrClient(config) const store = useNostrStore()
const isConnected = ref(false)
const isConnecting = ref(false)
const error = ref<Error | null>(null)
async function connect() { // If custom relays are provided, update the store
try { if (config?.relays) {
error.value = null store.setRelayUrls(config.relays)
isConnecting.value = true
await client.connect()
isConnected.value = client.isConnected
} catch (err) {
error.value = err instanceof Error ? err : new Error('Failed to connect')
isConnected.value = false
} finally {
isConnecting.value = false
}
} }
function disconnect() { // Return reactive refs from the store
client.disconnect() const { isConnected, isConnecting, error } = storeToRefs(store)
isConnected.value = false
isConnecting.value = false
error.value = null
}
return { return {
isConnected, isConnected,
isConnecting, isConnecting,
error, error,
connect, connect: store.connect,
disconnect disconnect: store.disconnect,
getClient: store.getClient
} }
} }

View file

@ -4,8 +4,11 @@ import { createTextNote, createReaction, createProfileMetadata } from '@/lib/nos
import { identity } from '@/composables/useIdentity' import { identity } from '@/composables/useIdentity'
import { toast } from 'vue-sonner' import { toast } from 'vue-sonner'
export function useSocial(relayUrls: string[]) { import { useNostr } from './useNostr'
const client = new NostrClient({ relays: relayUrls })
export function useSocial(relayUrls?: string[]) {
const { getClient } = useNostr(relayUrls ? { relays: relayUrls } : undefined)
const client = getClient()
const isPublishing = ref(false) const isPublishing = ref(false)
const profiles = ref(new Map<string, any>()) const profiles = ref(new Map<string, any>())
@ -152,5 +155,4 @@ export function useSocial(relayUrls: string[]) {
} }
// Export singleton instance for global use // Export singleton instance for global use
import { config } from '@/lib/config' export const social = useSocial()
export const social = useSocial(config.nostr.relays)

View file

@ -1,5 +1,7 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { ref } from 'vue' import { ref } from 'vue'
import { NostrClient } from '@/lib/nostr/client'
import { config } from '@/lib/config'
// Define an interface for the account object // Define an interface for the account object
interface NostrAccount { interface NostrAccount {
@ -8,16 +10,67 @@ interface NostrAccount {
} }
export const useNostrStore = defineStore('nostr', () => { export const useNostrStore = defineStore('nostr', () => {
// Connection state
const isConnected = ref(false) const isConnected = ref(false)
const relayUrls = ref<string[]>([]) const isConnecting = ref(false)
const error = ref<Error | null>(null)
// Configuration
const relayUrls = ref<string[]>(config.nostr.relays)
const account = ref<NostrAccount | null>(null) const account = ref<NostrAccount | null>(null)
// Singleton client instance
let client: NostrClient | null = null
// Get or create client instance
function getClient(): NostrClient {
if (!client) {
client = new NostrClient({ relays: relayUrls.value })
}
return client
}
// Connection management
async function connect(): Promise<void> {
try {
error.value = null
isConnecting.value = true
const nostrClient = getClient()
await nostrClient.connect()
isConnected.value = nostrClient.isConnected
} catch (err) {
error.value = err instanceof Error ? err : new Error('Failed to connect')
isConnected.value = false
throw err
} finally {
isConnecting.value = false
}
}
function disconnect(): void {
if (client) {
client.disconnect()
client = null
}
isConnected.value = false
isConnecting.value = false
error.value = null
}
// Configuration setters
function setConnected(value: boolean) { function setConnected(value: boolean) {
isConnected.value = value isConnected.value = value
} }
function setRelayUrls(urls: string[]) { function setRelayUrls(urls: string[]) {
relayUrls.value = urls relayUrls.value = urls
// Recreate client with new relays
if (client) {
client.disconnect()
client = null
}
} }
function setAccount(nostrAccount: NostrAccount | null) { function setAccount(nostrAccount: NostrAccount | null) {
@ -25,9 +78,17 @@ export const useNostrStore = defineStore('nostr', () => {
} }
return { return {
// State
isConnected, isConnected,
isConnecting,
error,
relayUrls, relayUrls,
account, account,
// Actions
connect,
disconnect,
getClient,
setConnected, setConnected,
setRelayUrls, setRelayUrls,
setAccount, setAccount,