/** * Service Worker sync handler - executes sync operations in main thread * Listens to requests from Service Worker and executes them */ import { platformSyncService } from './platformSync' import { syncUserContentToCache } from './userContentSync' import { publishWorker } from './publishWorker' import { nostrService } from './nostr' import { swClient } from './swClient' import type { Event } from 'nostr-tools' class ServiceWorkerSyncHandler { private initialized = false /** * Initialize the sync handler * Sets up message listeners from Service Worker */ async initialize(): Promise { if (this.initialized) { return } if (typeof window === 'undefined') { return } try { await swClient.register() this.registerMessageHandlers() this.initialized = true console.warn('[SWSyncHandler] Initialized') } catch (error) { console.error('[SWSyncHandler] Initialization failed:', error) } } private registerMessageHandlers(): void { swClient.onMessage('SYNC_REQUEST', (data: unknown) => { void this.handleSyncRequestMessage(data) }) swClient.onMessage('PUBLISH_WORKER_REQUEST', () => { void this.handlePublishWorkerRequest() }) swClient.onMessage('PUBLISH_REQUEST', (data: unknown) => { void this.handlePublishRequestMessage(data) }) swClient.onMessage('NOTIFICATION_DETECT_REQUEST', (data: unknown) => { void this.handleNotificationDetectRequestMessage(data) }) } private async handleSyncRequestMessage(data: unknown): Promise { const syncData = data as { syncType: string; userPubkey?: string } if (syncData.syncType === 'platform') { await this.handlePlatformSyncRequest() return } if (syncData.syncType === 'user' && syncData.userPubkey) { await this.handleUserSyncRequest(syncData.userPubkey) } } private async handlePublishRequestMessage(data: unknown): Promise { const publishData = data as { event: Event; relays: string[] } await this.handlePublishRequest(publishData.event, publishData.relays) } private async handleNotificationDetectRequestMessage(data: unknown): Promise { const detectData = data as { userPubkey: string } await this.handleNotificationDetectRequest(detectData.userPubkey) } /** * Handle platform sync request from Service Worker */ private async handlePlatformSyncRequest(): Promise { try { console.warn('[SWSyncHandler] Executing platform sync request') await platformSyncService.startSync() } catch (error) { console.error('[SWSyncHandler] Error in platform sync:', error) } } /** * Handle user sync request from Service Worker */ private async handleUserSyncRequest(userPubkey: string): Promise { try { console.warn('[SWSyncHandler] Executing user sync request for:', userPubkey) await syncUserContentToCache(userPubkey) } catch (error) { console.error('[SWSyncHandler] Error in user sync:', error) } } /** * Handle publish worker request from Service Worker */ private async handlePublishWorkerRequest(): Promise { try { console.warn('[SWSyncHandler] Executing publish worker request') // Trigger publish worker processing // The publishWorker will process unpublished objects await publishWorker['processUnpublished']() } catch (error) { console.error('[SWSyncHandler] Error in publish worker:', error) } } /** * Handle notification detection request from Service Worker * Le Service Worker détecte les changements indépendamment * Ce handler exécute la détection dans le thread principal et crée les notifications via writeService */ private async handleNotificationDetectRequest(userPubkey: string): Promise { try { console.warn('[SWSyncHandler] Executing notification detection request for:', userPubkey) const { notificationDetector } = await import('./notificationDetector') // Scanner IndexedDB pour détecter les nouveaux événements await notificationDetector.scan() // Les notifications sont créées via notificationDetector qui utilise notificationService // qui utilise maintenant writeService pour écrire via Web Worker } catch (error) { console.error('[SWSyncHandler] Error in notification detection:', error) } } /** * Handle publish request from Service Worker * Uses websocketService to route events to Service Worker */ private async handlePublishRequest(event: Event, relays: string[]): Promise { try { console.warn('[SWSyncHandler] Executing publish request for event:', event.id) const { websocketService } = await import('./websocketService') const { publishLog } = await import('./publishLog') // Publish to specified relays via websocketService (routes to Service Worker) const statuses = await websocketService.publishEvent(event, relays) const successfulRelays = logPublishStatuses({ publishLog, eventId: event.id, relays, statuses }) // Update published status in IndexedDB await updatePublishedStatusUnsafe(event.id, successfulRelays.length > 0 ? successfulRelays : false) } catch (error) { console.error('[SWSyncHandler] Error in publish request:', error) } } } export const swSyncHandler = new ServiceWorkerSyncHandler() function logPublishStatuses(params: { publishLog: { logPublication: (params: { eventId: string; relayUrl: string; success: boolean; error?: string }) => Promise } eventId: string relays: string[] statuses: Array<{ success: boolean; error?: string }> }): string[] { const successfulRelays: string[] = [] params.statuses.forEach((status, index) => { const relayUrl = params.relays[index] if (!relayUrl) { return } if (status.success) { successfulRelays.push(relayUrl) void params.publishLog.logPublication({ eventId: params.eventId, relayUrl, success: true }) return } const errorMessage = status.error ?? 'Unknown error' console.error(`[SWSyncHandler] Relay ${relayUrl} failed:`, errorMessage) void params.publishLog.logPublication({ eventId: params.eventId, relayUrl, success: false, error: errorMessage }) }) return successfulRelays } async function updatePublishedStatusUnsafe(eventId: string, published: false | string[]): Promise { const service = nostrService as unknown as { updatePublishedStatus: (eventId: string, published: false | string[]) => Promise } await service.updatePublishedStatus(eventId, published) }