import { type ChatService, type SyncCompletion, type SyncProgress, } from './chat/index.js'; /** Events emitted by one account-owned chat service into the shared UI/push hub. */ export interface AccountRuntimeEventReporter { conversation(input: { id: string; state: 'replied'; unread: number }): unknown; reply(input: { conversationId: string; id: string; username: string; body?: string }): unknown; mediaReceived(input: { conversationId: string; username: string; count: number }): unknown; sync(input: | { phase: 'started'; id: string; kind: 'delta' | 'full' } | { phase: 'progress'; id: string; kind: 'delta' | 'full'; current: number; total?: number; label?: string } | { phase: 'completed'; id: string; kind: 'delta' | 'full'; processed: number } | { phase: 'failed'; id: string; kind: 'delta' | 'full'; error: string } ): unknown; } type AccountChatEventSource = Pick< ChatService, 'setProgressListener' | 'setNewReplyListener' | 'setMediaReceivedListener' >; /** Connects one account-owned ChatService to the process-wide event stream. */ export function wireAccountChatEvents( chatService: AccountChatEventSource, events: AccountRuntimeEventReporter, accountId: string, ): void { let activeSync: SyncProgress | null = null; chatService.setProgressListener((progress, completion) => { if (progress) { const id = accountSyncId(accountId, progress.startedAt); if (progress.phase === 'starting') { events.sync({ phase: 'started', id, kind: progress.kind }); } else { events.sync({ phase: 'progress', id, kind: progress.kind, current: progress.current, total: progress.total, label: progress.label ?? progress.phase, }); } activeSync = progress; return; } if (!activeSync) return; reportSyncCompletion(events, accountId, activeSync, completion); activeSync = null; }); chatService.setMediaReceivedListener(({ conversationId, username, count }) => { events.mediaReceived({ conversationId, username, count }); }); chatService.setNewReplyListener(({ conversationId, replyId, username, replySnippet }) => { events.conversation({ id: conversationId, state: 'replied', unread: 1 }); events.reply({ conversationId, id: replyId, username, body: replySnippet }); }); } function reportSyncCompletion( events: AccountRuntimeEventReporter, accountId: string, progress: SyncProgress, completion?: SyncCompletion, ): void { const id = accountSyncId(accountId, progress.startedAt); if (completion?.status === 'failed') { events.sync({ phase: 'failed', id, kind: progress.kind, error: completion.error }); return; } events.sync({ phase: 'completed', id, kind: progress.kind, processed: progress.current }); } function accountSyncId(accountId: string, startedAt: number): string { return `chat-${accountId}-${startedAt}`; }