feat: Automatic LID/PN Chat Merge - Resolve WhatsApp Conversation Duplication
feat: Automatic LID/PN Chat Merge - Resolve WhatsApp Conversation Duplication
This commit is contained in:
@@ -1306,6 +1306,48 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
||||
'fallback LID mappings are now available from update event'
|
||||
)
|
||||
}
|
||||
|
||||
// Automatic chat merge: notify consumers about LID→PN mapping
|
||||
// This allows ZPRO and other consumers to merge/rename chats accordingly
|
||||
// Collect all merge notifications to emit in a single batch
|
||||
const mergeNotifications: ChatUpdate[] = []
|
||||
const mergedAt = Date.now()
|
||||
|
||||
for (const mapping of mappings) {
|
||||
const lidUser = jidNormalizedUser(mapping.lid)
|
||||
const pnUser = jidNormalizedUser(mapping.pn)
|
||||
|
||||
if (lidUser && pnUser && lidUser !== pnUser) {
|
||||
logger.debug(
|
||||
{ lid: lidUser, pn: pnUser },
|
||||
'collected chat update for LID→PN merge notification'
|
||||
)
|
||||
|
||||
mergeNotifications.push({
|
||||
id: pnUser,
|
||||
merged: true,
|
||||
previousId: lidUser,
|
||||
mergedAt
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Emit single batch of merge notifications for better performance
|
||||
if (mergeNotifications.length > 0) {
|
||||
logger.debug(
|
||||
{ count: mergeNotifications.length },
|
||||
'emitting batch of chat merge notifications'
|
||||
)
|
||||
ev.emit('chats.update', mergeNotifications)
|
||||
}
|
||||
|
||||
// Log warning if some mappings failed to store
|
||||
if (result.errors > 0) {
|
||||
logger.warn(
|
||||
{ errors: result.errors, total: mappings.length, notified: mergeNotifications.length },
|
||||
'some LID-PN mappings failed to store, but merge notifications were sent'
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn({ count: mappings.length, error }, 'Failed to store LID-PN mappings')
|
||||
}
|
||||
|
||||
@@ -75,6 +75,12 @@ export type ChatUpdate = Partial<
|
||||
conditional: (bufferedData: BufferedEventData) => boolean | undefined
|
||||
/** last update time */
|
||||
timestamp?: number
|
||||
/** indicates if this chat was merged from LID to PN */
|
||||
merged?: boolean
|
||||
/** previous chat ID before merge (LID format) */
|
||||
previousId?: string
|
||||
/** timestamp when the merge occurred */
|
||||
mergedAt?: number
|
||||
}
|
||||
>
|
||||
|
||||
|
||||
@@ -189,6 +189,7 @@ export type BufferedEventData = {
|
||||
messageReactions: { [key: string]: { key: WAMessageKey; reactions: proto.IReaction[] } }
|
||||
messageReceipts: { [key: string]: { key: WAMessageKey; userReceipt: proto.IUserReceipt[] } }
|
||||
groupUpdates: { [jid: string]: Partial<GroupMetadata> }
|
||||
lidMappings: { [key: string]: LIDMapping }
|
||||
}
|
||||
|
||||
export type BaileysEvent = keyof BaileysEventMap
|
||||
|
||||
@@ -83,7 +83,8 @@ const BUFFERABLE_EVENT = [
|
||||
'messages.delete',
|
||||
'messages.reaction',
|
||||
'message-receipt.update',
|
||||
'groups.update'
|
||||
'groups.update',
|
||||
'lid-mapping.update'
|
||||
] as const
|
||||
|
||||
type BufferableEvent = (typeof BUFFERABLE_EVENT)[number]
|
||||
@@ -882,7 +883,8 @@ const makeBufferData = (): BufferedEventData => {
|
||||
messageReactions: {},
|
||||
messageDeletes: {},
|
||||
messageReceipts: {},
|
||||
groupUpdates: {}
|
||||
groupUpdates: {},
|
||||
lidMappings: {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1197,6 +1199,16 @@ function append<E extends BufferableEvent>(
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
case 'lid-mapping.update':
|
||||
const lidMappings = eventData as BaileysEventMap['lid-mapping.update']
|
||||
for (const mapping of lidMappings) {
|
||||
const key = `${mapping.lid}-${mapping.pn}`
|
||||
if (!data.lidMappings[key]) {
|
||||
data.lidMappings[key] = mapping
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
default:
|
||||
throw new Error(`"${event}" cannot be buffered`)
|
||||
@@ -1325,6 +1337,11 @@ function consolidateEvents(data: BufferedEventData) {
|
||||
map['groups.update'] = groupUpdateList
|
||||
}
|
||||
|
||||
const lidMappingList = Object.values(data.lidMappings)
|
||||
if (lidMappingList.length) {
|
||||
map['lid-mapping.update'] = lidMappingList
|
||||
}
|
||||
|
||||
return map
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user