diff --git a/src/App.vue b/src/App.vue index c710041..7acc8a8 100644 --- a/src/App.vue +++ b/src/App.vue @@ -10,8 +10,7 @@ import { identity } from '@/composables/useIdentity' import { toast } from 'vue-sonner' import { config } from '@/lib/config' -const relays = config.nostr.relays -const { isConnected, isConnecting, error, connect, disconnect } = useNostr({ relays }) +const { isConnected, isConnecting, error, connect, disconnect } = useNostr() const showPasswordDialog = ref(false) diff --git a/src/components/nostr/NostrFeed.vue b/src/components/nostr/NostrFeed.vue index f611520..e0b82c5 100644 --- a/src/components/nostr/NostrFeed.vue +++ b/src/components/nostr/NostrFeed.vue @@ -18,8 +18,7 @@ const notes = ref([]) const isLoading = ref(true) const error = ref(null) -const relayUrls = props.relays || config.nostr.relays -const { disconnect } = useNostr({ relays: relayUrls }) +const { getClient } = useNostr(props.relays ? { relays: props.relays } : undefined) // Get admin/moderator pubkeys from centralized config const adminPubkeys = config.nostr.adminPubkeys @@ -29,7 +28,7 @@ async function loadNotes() { isLoading.value = true error.value = null - const client = new NostrClient({ relays: relayUrls }) + const client = getClient() await client.connect() // Configure fetch options based on feed type diff --git a/src/composables/useNostr.ts b/src/composables/useNostr.ts index dc198eb..ecee0bf 100644 --- a/src/composables/useNostr.ts +++ b/src/composables/useNostr.ts @@ -1,38 +1,24 @@ -import { ref } from 'vue' -import { NostrClient, type NostrClientConfig } from '@/lib/nostr/client' +import { storeToRefs } from 'pinia' +import { useNostrStore } from '@/stores/nostr' +import type { NostrClientConfig } from '@/lib/nostr/client' -export function useNostr(config: NostrClientConfig) { - const client = new NostrClient(config) - const isConnected = ref(false) - const isConnecting = ref(false) - const error = ref(null) - - async function connect() { - try { - error.value = null - 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 - } +export function useNostr(config?: NostrClientConfig) { + const store = useNostrStore() + + // If custom relays are provided, update the store + if (config?.relays) { + store.setRelayUrls(config.relays) } - function disconnect() { - client.disconnect() - isConnected.value = false - isConnecting.value = false - error.value = null - } + // Return reactive refs from the store + const { isConnected, isConnecting, error } = storeToRefs(store) return { isConnected, isConnecting, error, - connect, - disconnect + connect: store.connect, + disconnect: store.disconnect, + getClient: store.getClient } } \ No newline at end of file diff --git a/src/composables/useSocial.ts b/src/composables/useSocial.ts index 51a6112..f1db92f 100644 --- a/src/composables/useSocial.ts +++ b/src/composables/useSocial.ts @@ -4,8 +4,11 @@ import { createTextNote, createReaction, createProfileMetadata } from '@/lib/nos import { identity } from '@/composables/useIdentity' import { toast } from 'vue-sonner' -export function useSocial(relayUrls: string[]) { - const client = new NostrClient({ relays: relayUrls }) +import { useNostr } from './useNostr' + +export function useSocial(relayUrls?: string[]) { + const { getClient } = useNostr(relayUrls ? { relays: relayUrls } : undefined) + const client = getClient() const isPublishing = ref(false) const profiles = ref(new Map()) @@ -152,5 +155,4 @@ export function useSocial(relayUrls: string[]) { } // Export singleton instance for global use -import { config } from '@/lib/config' -export const social = useSocial(config.nostr.relays) \ No newline at end of file +export const social = useSocial() \ No newline at end of file diff --git a/src/stores/nostr.ts b/src/stores/nostr.ts index 02401d5..47b78a9 100644 --- a/src/stores/nostr.ts +++ b/src/stores/nostr.ts @@ -1,5 +1,7 @@ import { defineStore } from 'pinia' import { ref } from 'vue' +import { NostrClient } from '@/lib/nostr/client' +import { config } from '@/lib/config' // Define an interface for the account object interface NostrAccount { @@ -8,16 +10,67 @@ interface NostrAccount { } export const useNostrStore = defineStore('nostr', () => { + // Connection state const isConnected = ref(false) - const relayUrls = ref([]) + const isConnecting = ref(false) + const error = ref(null) + + // Configuration + const relayUrls = ref(config.nostr.relays) const account = ref(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 { + 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) { isConnected.value = value } function setRelayUrls(urls: string[]) { relayUrls.value = urls + // Recreate client with new relays + if (client) { + client.disconnect() + client = null + } } function setAccount(nostrAccount: NostrAccount | null) { @@ -25,9 +78,17 @@ export const useNostrStore = defineStore('nostr', () => { } return { + // State isConnected, + isConnecting, + error, relayUrls, account, + + // Actions + connect, + disconnect, + getClient, setConnected, setRelayUrls, setAccount,