@@ -91,4 +91,272 @@ describe('processHistoryMessage', () => {
9191 } )
9292 } )
9393 } )
94+
95+ describe ( 'LID-PN mapping extraction from conversations' , ( ) => {
96+ it ( 'should extract mapping when chat.id is LID and pnJid exists' , ( ) => {
97+ const historySync : proto . IHistorySync = {
98+ syncType : proto . HistorySync . HistorySyncType . INITIAL_BOOTSTRAP ,
99+ conversations : [
100+ {
101+ id : '11111111111111@lid' ,
102+ pnJid : '1234567890123@s.whatsapp.net'
103+ }
104+ ]
105+ }
106+
107+ const result = processHistoryMessage ( historySync )
108+
109+ expect ( result . lidPnMappings ) . toContainEqual ( {
110+ lid : '11111111111111@lid' ,
111+ pn : '1234567890123@s.whatsapp.net'
112+ } )
113+ } )
114+
115+ it ( 'should extract mapping when chat.id is PN and lidJid exists' , ( ) => {
116+ const historySync : proto . IHistorySync = {
117+ syncType : proto . HistorySync . HistorySyncType . INITIAL_BOOTSTRAP ,
118+ conversations : [
119+ {
120+ id : '1234567890123@s.whatsapp.net' ,
121+ lidJid : '11111111111111@lid'
122+ }
123+ ]
124+ }
125+
126+ const result = processHistoryMessage ( historySync )
127+
128+ expect ( result . lidPnMappings ) . toContainEqual ( {
129+ lid : '11111111111111@lid' ,
130+ pn : '1234567890123@s.whatsapp.net'
131+ } )
132+ } )
133+
134+ it ( 'should not extract mapping for group chats' , ( ) => {
135+ const historySync : proto . IHistorySync = {
136+ syncType : proto . HistorySync . HistorySyncType . INITIAL_BOOTSTRAP ,
137+ conversations : [
138+ {
139+ id : '123456789012345678@g.us' ,
140+ lidJid : '11111111111111@lid' ,
141+ pnJid : '1234567890123@s.whatsapp.net'
142+ }
143+ ]
144+ }
145+
146+ const result = processHistoryMessage ( historySync )
147+
148+ expect ( result . lidPnMappings ) . toEqual ( [ ] )
149+ } )
150+
151+ it ( 'should combine mappings from phoneNumberToLidMappings and conversations' , ( ) => {
152+ const historySync : proto . IHistorySync = {
153+ syncType : proto . HistorySync . HistorySyncType . INITIAL_BOOTSTRAP ,
154+ phoneNumberToLidMappings : [ { lidJid : '11111111111111@lid' , pnJid : '1111111111111@s.whatsapp.net' } ] ,
155+ conversations : [
156+ {
157+ id : '22222222222222@lid' ,
158+ pnJid : '2222222222222@s.whatsapp.net'
159+ }
160+ ]
161+ }
162+
163+ const result = processHistoryMessage ( historySync )
164+
165+ expect ( result . lidPnMappings ) . toHaveLength ( 2 )
166+ expect ( result . lidPnMappings ) . toContainEqual ( {
167+ lid : '11111111111111@lid' ,
168+ pn : '1111111111111@s.whatsapp.net'
169+ } )
170+ expect ( result . lidPnMappings ) . toContainEqual ( {
171+ lid : '22222222222222@lid' ,
172+ pn : '2222222222222@s.whatsapp.net'
173+ } )
174+ } )
175+
176+ it ( 'should extract mapping for hosted LID users' , ( ) => {
177+ const historySync : proto . IHistorySync = {
178+ syncType : proto . HistorySync . HistorySyncType . INITIAL_BOOTSTRAP ,
179+ conversations : [
180+ {
181+ id : '11111111111111@hosted.lid' ,
182+ pnJid : '1234567890123@hosted'
183+ }
184+ ]
185+ }
186+
187+ const result = processHistoryMessage ( historySync )
188+
189+ expect ( result . lidPnMappings ) . toContainEqual ( {
190+ lid : '11111111111111@hosted.lid' ,
191+ pn : '1234567890123@hosted'
192+ } )
193+ } )
194+
195+ it ( 'should extract mapping for hosted PN users' , ( ) => {
196+ const historySync : proto . IHistorySync = {
197+ syncType : proto . HistorySync . HistorySyncType . INITIAL_BOOTSTRAP ,
198+ conversations : [
199+ {
200+ id : '1234567890123@hosted' ,
201+ lidJid : '11111111111111@hosted.lid'
202+ }
203+ ]
204+ }
205+
206+ const result = processHistoryMessage ( historySync )
207+
208+ expect ( result . lidPnMappings ) . toContainEqual ( {
209+ lid : '11111111111111@hosted.lid' ,
210+ pn : '1234567890123@hosted'
211+ } )
212+ } )
213+
214+ it ( 'should extract mapping from userReceipt when pnJid is missing and chat.id is LID' , ( ) => {
215+ // Based on real-world case: LID chat without pnJid but userReceipt contains PN
216+ // See: https://github.com/WhiskeySockets/Baileys/pull/2282#issuecomment-3777941679
217+ const historySync : proto . IHistorySync = {
218+ syncType : proto . HistorySync . HistorySyncType . INITIAL_BOOTSTRAP ,
219+ conversations : [
220+ {
221+ id : '211071956705386@lid' ,
222+ // pnJid is intentionally missing
223+ messages : [
224+ {
225+ message : {
226+ key : {
227+ remoteJid : '211071956705386@lid' ,
228+ fromMe : true ,
229+ id : '3EB052FF8D9D00646C9994'
230+ } ,
231+ messageTimestamp : 1768320044 ,
232+ userReceipt : [
233+ {
234+ userJid : '5518999991234@s.whatsapp.net' ,
235+ receiptTimestamp : 1768320045 ,
236+ readTimestamp : 1768327083
237+ }
238+ ]
239+ }
240+ }
241+ ]
242+ }
243+ ]
244+ }
245+
246+ const result = processHistoryMessage ( historySync )
247+
248+ expect ( result . lidPnMappings ) . toContainEqual ( {
249+ lid : '211071956705386@lid' ,
250+ pn : '5518999991234@s.whatsapp.net'
251+ } )
252+ } )
253+
254+ it ( 'should not extract mapping from userReceipt when pnJid already exists' , ( ) => {
255+ const historySync : proto . IHistorySync = {
256+ syncType : proto . HistorySync . HistorySyncType . INITIAL_BOOTSTRAP ,
257+ conversations : [
258+ {
259+ id : '211071956705386@lid' ,
260+ pnJid : '5518888881234@s.whatsapp.net' , // pnJid exists
261+ messages : [
262+ {
263+ message : {
264+ key : {
265+ remoteJid : '211071956705386@lid' ,
266+ fromMe : true ,
267+ id : '3EB052FF8D9D00646C9994'
268+ } ,
269+ userReceipt : [
270+ {
271+ userJid : '5518999991234@s.whatsapp.net' // different PN
272+ }
273+ ]
274+ }
275+ }
276+ ]
277+ }
278+ ]
279+ }
280+
281+ const result = processHistoryMessage ( historySync )
282+
283+ // Should use pnJid, not userReceipt
284+ expect ( result . lidPnMappings ) . toContainEqual ( {
285+ lid : '211071956705386@lid' ,
286+ pn : '5518888881234@s.whatsapp.net'
287+ } )
288+ // Should NOT contain the userReceipt PN
289+ expect ( result . lidPnMappings ) . not . toContainEqual ( {
290+ lid : '211071956705386@lid' ,
291+ pn : '5518999991234@s.whatsapp.net'
292+ } )
293+ } )
294+
295+ it ( 'should not extract mapping from userReceipt when fromMe is false' , ( ) => {
296+ const historySync : proto . IHistorySync = {
297+ syncType : proto . HistorySync . HistorySyncType . INITIAL_BOOTSTRAP ,
298+ conversations : [
299+ {
300+ id : '211071956705386@lid' ,
301+ messages : [
302+ {
303+ message : {
304+ key : {
305+ remoteJid : '211071956705386@lid' ,
306+ fromMe : false , // Not from me
307+ id : '3EB052FF8D9D00646C9994'
308+ } ,
309+ userReceipt : [
310+ {
311+ userJid : '5518999991234@s.whatsapp.net'
312+ }
313+ ]
314+ }
315+ }
316+ ]
317+ }
318+ ]
319+ }
320+
321+ const result = processHistoryMessage ( historySync )
322+
323+ // Should not extract mapping when fromMe is false
324+ expect ( result . lidPnMappings ) . not . toContainEqual ( {
325+ lid : '211071956705386@lid' ,
326+ pn : '5518999991234@s.whatsapp.net'
327+ } )
328+ } )
329+
330+ it ( 'should not extract mapping from userReceipt when userJid is also a LID' , ( ) => {
331+ const historySync : proto . IHistorySync = {
332+ syncType : proto . HistorySync . HistorySyncType . INITIAL_BOOTSTRAP ,
333+ conversations : [
334+ {
335+ id : '211071956705386@lid' ,
336+ messages : [
337+ {
338+ message : {
339+ key : {
340+ remoteJid : '211071956705386@lid' ,
341+ fromMe : true ,
342+ id : '3EB052FF8D9D00646C9994'
343+ } ,
344+ userReceipt : [
345+ {
346+ userJid : '152230971891797@lid' // Also a LID, not a PN
347+ }
348+ ]
349+ }
350+ }
351+ ]
352+ }
353+ ]
354+ }
355+
356+ const result = processHistoryMessage ( historySync )
357+
358+ // Should not create a LID->LID mapping
359+ expect ( result . lidPnMappings ) . toHaveLength ( 0 )
360+ } )
361+ } )
94362} )
0 commit comments