Files
boris/src/services/offlineSyncService.ts
Gigi adf73cb9d1 fix: resolve all linting and type errors
- Fix empty catch blocks by adding explanatory comments
- Remove unused variables or prefix with underscore
- Remove orphaned object literals from removed console.log statements
- Fix unnecessary dependency array entries
- Ensure all empty code blocks have comments to satisfy eslint no-empty rule
2025-10-19 22:41:35 +02:00

137 lines
3.4 KiB
TypeScript

import { RelayPool } from 'applesauce-relay'
import { NostrEvent } from 'nostr-tools'
import { IEventStore } from 'applesauce-core'
import { RELAYS } from '../config/relays'
import { isLocalRelay } from '../utils/helpers'
let isSyncing = false
// Track events created during offline period
const offlineCreatedEvents = new Set<string>()
// Track events currently being synced
const syncingEvents = new Set<string>()
// Callbacks to notify when sync state changes
const syncStateListeners: Array<(eventId: string, isSyncing: boolean) => void> = []
/**
* Marks an event as created during offline period
*/
export function markEventAsOfflineCreated(eventId: string): void {
offlineCreatedEvents.add(eventId)
}
/**
* Check if an event is currently being synced
*/
export function isEventSyncing(eventId: string): boolean {
return syncingEvents.has(eventId)
}
/**
* Subscribe to sync state changes
*/
export function onSyncStateChange(callback: (eventId: string, isSyncing: boolean) => void): () => void {
syncStateListeners.push(callback)
return () => {
const index = syncStateListeners.indexOf(callback)
if (index > -1) syncStateListeners.splice(index, 1)
}
}
/**
* Notify listeners of sync state change
*/
function notifySyncStateChange(eventId: string, isSyncing: boolean): void {
syncStateListeners.forEach(listener => listener(eventId, isSyncing))
}
/**
* 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,
eventStore: IEventStore
): Promise<void> {
if (isSyncing) {
return
}
isSyncing = true
try {
const remoteRelays = RELAYS.filter(url => !isLocalRelay(url))
if (remoteRelays.length === 0) {
isSyncing = false
return
}
if (offlineCreatedEvents.size === 0) {
isSyncing = false
return
}
// Get events from EventStore using the tracked IDs
const eventsToSync: NostrEvent[] = []
for (const eventId of offlineCreatedEvents) {
const event = eventStore.getEvent(eventId)
if (event) {
eventsToSync.push(event)
}
}
if (eventsToSync.length === 0) {
isSyncing = false
offlineCreatedEvents.clear()
return
}
// Deduplicate events by id
const uniqueEvents = Array.from(
new Map(eventsToSync.map(e => [e.id, e])).values()
)
// Mark all events as syncing
uniqueEvents.forEach(event => {
syncingEvents.add(event.id)
notifySyncStateChange(event.id, true)
})
// Publish to remote relays
const successfulIds: string[] = []
for (const event of uniqueEvents) {
try {
await relayPool.publish(remoteRelays, event)
successfulIds.push(event.id)
} catch (error) {
// Silently fail for individual events
}
}
// Clear syncing state and offline tracking for successful events
successfulIds.forEach(eventId => {
syncingEvents.delete(eventId)
offlineCreatedEvents.delete(eventId)
notifySyncStateChange(eventId, false)
})
// Clear syncing state for failed events
uniqueEvents.forEach(event => {
if (!successfulIds.includes(event.id)) {
syncingEvents.delete(event.id)
notifySyncStateChange(event.id, false)
}
})
} catch (error) {
// Silently fail
} finally {
isSyncing = false
}
}