(options: {
adapter: SessionRuntimeAdapter
sessionIds: string[]
timeRange: ContactsTimeRangeState
factsCache: ContactsFactsCacheContext | null
onProgress?: (progress: ContactsComputeProgress) => void
})
| 142 | } |
| 143 | |
| 144 | function computeContacts(options: { |
| 145 | adapter: SessionRuntimeAdapter |
| 146 | sessionIds: string[] |
| 147 | timeRange: ContactsTimeRangeState |
| 148 | factsCache: ContactsFactsCacheContext | null |
| 149 | onProgress?: (progress: ContactsComputeProgress) => void |
| 150 | }): BuildContactsResult { |
| 151 | const diagnostics = createEmptyDiagnostics() |
| 152 | const accumulators = new Map<string, ContactAccumulator>() |
| 153 | let processedSessions = 0 |
| 154 | |
| 155 | for (const sessionId of options.sessionIds) { |
| 156 | options.onProgress?.({ processedSessions, totalSessions: options.sessionIds.length, currentSessionId: sessionId }) |
| 157 | try { |
| 158 | const facts = getSessionFacts(options.adapter, sessionId, options.timeRange, options.factsCache) |
| 159 | applySessionFacts(accumulators, diagnostics, sessionId, facts) |
| 160 | } catch (error) { |
| 161 | diagnostics.skippedFailedSessions++ |
| 162 | appLogger.error('contacts', `failed to process contact session: ${sessionId}`, error) |
| 163 | } finally { |
| 164 | processedSessions++ |
| 165 | options.onProgress?.({ processedSessions, totalSessions: options.sessionIds.length, currentSessionId: sessionId }) |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | diagnostics.contactsEnabled = diagnostics.activePrivateSessionCount > MIN_PRIVATE_SESSIONS_FOR_CONTACTS |
| 170 | const contacts = buildContactItems([...accumulators.values()]) |
| 171 | return { contacts, diagnostics } |
| 172 | } |
| 173 | |
| 174 | function findGlobalLatestMessageTs( |
| 175 | adapter: SessionRuntimeAdapter, |
no test coverage detected