refactor: use applesauce EventStore for offline event management

Major improvements:
- Store highlights in EventStore immediately when created
- Query EventStore instead of local relays for offline sync
- Pass eventStore to highlight creation service and hooks
- Simplified offline sync: no more relay queries, just EventStore lookups
- More efficient and reliable offline event tracking
- Better integration with applesauce architecture

Benefits:
- Faster sync (no relay queries needed)
- More reliable (events always in EventStore)
- Cleaner code (leveraging applesauce patterns)
- Better separation of concerns
This commit is contained in:
Gigi
2025-10-09 13:54:47 +01:00
parent 95162d4423
commit d294287c64
5 changed files with 45 additions and 56 deletions

View File

@@ -59,6 +59,7 @@ const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
useOfflineSync({
relayPool,
account: activeAccount,
eventStore,
relayStatuses,
enabled: true
})
@@ -129,6 +130,7 @@ const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
} = useHighlightCreation({
activeAccount,
relayPool,
eventStore,
currentArticle,
selectedUrl,
readerContent,

View File

@@ -1,6 +1,7 @@
import { useCallback, useRef } from 'react'
import { RelayPool } from 'applesauce-relay'
import { NostrEvent } from 'nostr-tools'
import { IEventStore } from 'applesauce-core'
import { Highlight } from '../types/highlights'
import { ReadableContent } from '../services/readerService'
import { createHighlight } from '../services/highlightCreationService'
@@ -11,6 +12,7 @@ interface UseHighlightCreationParams {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
activeAccount: any
relayPool: RelayPool | null
eventStore: IEventStore | null
currentArticle: NostrEvent | undefined
selectedUrl: string | undefined
readerContent: ReadableContent | undefined
@@ -21,6 +23,7 @@ interface UseHighlightCreationParams {
export const useHighlightCreation = ({
activeAccount,
relayPool,
eventStore,
currentArticle,
selectedUrl,
readerContent,
@@ -38,7 +41,7 @@ export const useHighlightCreation = ({
}, [])
const handleCreateHighlight = useCallback(async (text: string) => {
if (!activeAccount || !relayPool) {
if (!activeAccount || !relayPool || !eventStore) {
console.error('Missing requirements for highlight creation')
return
}
@@ -61,6 +64,7 @@ export const useHighlightCreation = ({
source,
activeAccount,
relayPool,
eventStore,
contentForContext,
undefined,
settings
@@ -79,7 +83,7 @@ export const useHighlightCreation = ({
// Re-throw to allow parent to handle
throw error
}
}, [activeAccount, relayPool, currentArticle, selectedUrl, readerContent, onHighlightCreated, settings])
}, [activeAccount, relayPool, eventStore, currentArticle, selectedUrl, readerContent, onHighlightCreated, settings])
return {
highlightButtonRef,

View File

@@ -1,6 +1,6 @@
import { useEffect, useRef } from 'react'
import { RelayPool } from 'applesauce-relay'
import { IAccount } from 'applesauce-core/helpers'
import { IAccount, IEventStore } from 'applesauce-core'
import { syncLocalEventsToRemote } from '../services/offlineSyncService'
import { isLocalRelay } from '../utils/helpers'
import { RelayStatus } from '../services/relayStatusService'
@@ -8,6 +8,7 @@ import { RelayStatus } from '../services/relayStatusService'
interface UseOfflineSyncParams {
relayPool: RelayPool | null
account: IAccount | null
eventStore: IEventStore | null
relayStatuses: RelayStatus[]
enabled?: boolean
}
@@ -15,6 +16,7 @@ interface UseOfflineSyncParams {
export function useOfflineSync({
relayPool,
account,
eventStore,
relayStatuses,
enabled = true
}: UseOfflineSyncParams) {
@@ -27,7 +29,7 @@ export function useOfflineSync({
})
useEffect(() => {
if (!enabled || !relayPool || !account) return
if (!enabled || !relayPool || !account || !eventStore) return
const connectedRelays = relayStatuses.filter(r => r.isInPool)
const hasRemoteRelays = connectedRelays.some(r => !isLocalRelay(r.url))
@@ -57,11 +59,11 @@ export function useOfflineSync({
// Wait a moment for relays to fully establish connections
setTimeout(() => {
console.log('🚀 Starting sync after delay...')
syncLocalEventsToRemote(relayPool, account)
syncLocalEventsToRemote(relayPool, account, eventStore)
}, 2000)
}
previousStateRef.current.hasRemoteRelays = hasRemoteRelays
}, [relayPool, account, relayStatuses, enabled])
}, [relayPool, account, eventStore, relayStatuses, enabled])
}

View File

@@ -3,7 +3,7 @@ import { RelayPool } from 'applesauce-relay'
import { IAccount } from 'applesauce-accounts'
import { AddressPointer } from 'nostr-tools/nip19'
import { NostrEvent } from 'nostr-tools'
import { Helpers } from 'applesauce-core'
import { Helpers, IEventStore } from 'applesauce-core'
import { RELAYS } from '../config/relays'
import { Highlight } from '../types/highlights'
import { UserSettings } from './settingsService'
@@ -35,6 +35,7 @@ export async function createHighlight(
source: NostrEvent | string,
account: IAccount,
relayPool: RelayPool,
eventStore: IEventStore,
contentForContext?: string,
comment?: string,
settings?: UserSettings
@@ -143,6 +144,10 @@ export async function createHighlight(
eventId: signedEvent.id
})
// Store the event in the local EventStore immediately
eventStore.add(signedEvent)
console.log('💾 Stored highlight in EventStore:', signedEvent.id.slice(0, 8))
// If we're in local-only mode, mark this event for later sync
if (isLocalOnly) {
markEventAsOfflineCreated(signedEvent.id)

View File

@@ -1,6 +1,6 @@
import { RelayPool } from 'applesauce-relay'
import { NostrEvent } from 'nostr-tools'
import { IAccount } from 'applesauce-core/helpers'
import { IAccount, IEventStore } from 'applesauce-core'
import { RELAYS } from '../config/relays'
import { isLocalRelay } from '../utils/helpers'
@@ -19,10 +19,12 @@ export function markEventAsOfflineCreated(eventId: string): void {
/**
* Syncs local-only events to remote relays when coming back online
* Now uses applesauce EventStore instead of querying relays
*/
export async function syncLocalEventsToRemote(
relayPool: RelayPool,
account: IAccount
account: IAccount,
eventStore: IEventStore
): Promise<void> {
if (isSyncing) {
console.log('⏳ Sync already in progress, skipping...')
@@ -34,16 +36,9 @@ export async function syncLocalEventsToRemote(
isSyncing = true
try {
const localRelays = RELAYS.filter(isLocalRelay)
const remoteRelays = RELAYS.filter(url => !isLocalRelay(url))
console.log(`📡 Local relays: ${localRelays.length}, Remote relays: ${remoteRelays.length}`)
if (localRelays.length === 0) {
console.log('⚠️ No local relays available for sync')
isSyncing = false
return
}
console.log(`📡 Remote relays: ${remoteRelays.length}`)
if (remoteRelays.length === 0) {
console.log('⚠️ No remote relays available for sync')
@@ -51,49 +46,30 @@ export async function syncLocalEventsToRemote(
return
}
// Get events from local relays that were created in the last 24 hours
const since = Math.floor(Date.now() / 1000) - (24 * 60 * 60)
const eventsToSync: NostrEvent[] = []
console.log(`🔍 Querying local relays for events since ${new Date(since * 1000).toISOString()}...`)
// Query for user's events from local relays
const filters = [
{ kinds: [9802], authors: [account.pubkey], since }, // Highlights
{ kinds: [10003, 30003], authors: [account.pubkey], since }, // Bookmarks
]
for (const filter of filters) {
console.log(`🔎 Querying with filter:`, filter)
const events = await new Promise<NostrEvent[]>((resolve) => {
const collected: NostrEvent[] = []
const sub = relayPool.req(localRelays, filter, {
onevent: (event: NostrEvent) => {
console.log(`📥 Received event ${event.id.slice(0, 8)} (kind ${event.kind}) from local relay`)
collected.push(event)
},
oneose: () => {
console.log(`✅ EOSE received, collected ${collected.length} events`)
sub.close()
resolve(collected)
}
})
// Timeout after 10 seconds (increased from 5)
setTimeout(() => {
console.log(`⏱️ Query timeout, collected ${collected.length} events`)
sub.close()
resolve(collected)
}, 10000)
})
eventsToSync.push(...events)
if (offlineCreatedEvents.size === 0) {
console.log('✅ No offline events to sync')
isSyncing = false
return
}
console.log(`📊 Total events collected: ${eventsToSync.length}`)
// Get events from EventStore using the tracked IDs
const eventsToSync: NostrEvent[] = []
console.log(`🔍 Querying EventStore for ${offlineCreatedEvents.size} offline events...`)
for (const eventId of offlineCreatedEvents) {
const event = eventStore.getEvent(eventId)
if (event) {
console.log(`📥 Found event ${eventId.slice(0, 8)} (kind ${event.kind}) in EventStore`)
eventsToSync.push(event)
} else {
console.warn(`⚠️ Event ${eventId.slice(0, 8)} not found in EventStore`)
}
}
console.log(`📊 Total events to sync: ${eventsToSync.length}`)
if (eventsToSync.length === 0) {
console.log('✅ No local events to sync')
console.log('✅ No events found in EventStore to sync')
isSyncing = false
offlineCreatedEvents.clear()
return