@nexustechpro/baileys 1.1.7 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ yarn pbjs -t static-module --no-beautify -w es6 --no-bundle --no-delimited --no-verify --no-comments -o ./index.js ./WAProto.proto;
2
+ yarn pbjs -t static-module --no-beautify -w es6 --no-bundle --no-delimited --no-verify ./WAProto.proto | yarn pbts --no-comments -o ./index.d.ts -;
3
+ node ./fix-imports.js
@@ -0,0 +1,3 @@
1
+ {
2
+ "version": [2, 3000, 1027934701]
3
+ }
@@ -1,151 +1,173 @@
1
- import { proto } from '../../WAProto/index.js'
2
- import { makeLibSignalRepository } from '../Signal/libsignal.js'
3
- import { Browsers } from '../Utils/browser-utils.js'
4
- import logger from '../Utils/logger.js'
1
+ import { createHash } from 'crypto';
2
+ import { createRequire } from 'module';
3
+ import { proto } from '../../WAProto/index.js';
4
+ import { makeLibSignalRepository } from '../Signal/libsignal.js';
5
+ import { Browsers } from '../Utils/browser-utils.js';
6
+ import logger from '../Utils/logger.js';
7
+ const require = createRequire(import.meta.url);
8
+ const PHONENUMBER_MCC = require('./phonenumber-mcc.json');
9
+ export { PHONENUMBER_MCC };
10
+ const version = [2, 3000, 1027934701];
5
11
 
6
- const version = [2, 3000, 1033105955]
12
+ export const UNAUTHORIZED_CODES = [401, 403, 419];
7
13
 
8
- export const UNAUTHORIZED_CODES = [401, 403, 419]
14
+ export const DEFAULT_ORIGIN = 'https://web.whatsapp.com';
15
+ export const CALL_VIDEO_PREFIX = 'https://call.whatsapp.com/video/';
16
+ export const CALL_AUDIO_PREFIX = 'https://call.whatsapp.com/voice/';
17
+ export const DEF_CALLBACK_PREFIX = 'CB:';
18
+ export const DEF_TAG_PREFIX = 'TAG:';
19
+ export const PHONE_CONNECTION_CB = 'CB:Pong';
9
20
 
10
- export const DEFAULT_ORIGIN = 'https://web.whatsapp.com'
11
- export const CALL_VIDEO_PREFIX = 'https://call.whatsapp.com/video/'
12
- export const CALL_AUDIO_PREFIX = 'https://call.whatsapp.com/voice/'
13
- export const DEF_CALLBACK_PREFIX = 'CB:'
14
- export const DEF_TAG_PREFIX = 'TAG:'
15
- export const PHONE_CONNECTION_CB = 'CB:Pong'
21
+ export const WA_ADV_ACCOUNT_SIG_PREFIX = Buffer.from([6, 0]);
22
+ export const WA_ADV_DEVICE_SIG_PREFIX = Buffer.from([6, 1]);
23
+ export const WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX = Buffer.from([6, 5]);
24
+ export const WA_ADV_HOSTED_DEVICE_SIG_PREFIX = Buffer.from([6, 6]);
16
25
 
17
- export const WA_ADV_ACCOUNT_SIG_PREFIX = Buffer.from([6, 0])
18
- export const WA_ADV_DEVICE_SIG_PREFIX = Buffer.from([6, 1])
19
- export const WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX = Buffer.from([6, 5])
20
- export const WA_ADV_HOSTED_DEVICE_SIG_PREFIX = Buffer.from([6, 6])
26
+ export const WA_DEFAULT_EPHEMERAL = 7 * 24 * 60 * 60;
21
27
 
22
- export const WA_DEFAULT_EPHEMERAL = 7 * 24 * 60 * 60
28
+ export const STATUS_EXPIRY_SECONDS = 24 * 60 * 60;
23
29
 
24
- export const STATUS_EXPIRY_SECONDS = 24 * 60 * 60
30
+ export const PLACEHOLDER_MAX_AGE_SECONDS = 14 * 24 * 60 * 60;
25
31
 
26
- export const PLACEHOLDER_MAX_AGE_SECONDS = 14 * 24 * 60 * 60
32
+ export const BATCH_SIZE = 500;
27
33
 
28
- export const BATCH_SIZE = 500
34
+ export const NOISE_MODE = 'Noise_XX_25519_AESGCM_SHA256\0\0\0\0';
35
+ export const DICT_VERSION = 3;
36
+ export const KEY_BUNDLE_TYPE = Buffer.from([5]);
37
+ export const NOISE_WA_HEADER = Buffer.from([87, 65, 6, DICT_VERSION]);
29
38
 
30
- export const NOISE_MODE = 'Noise_XX_25519_AESGCM_SHA256\0\0\0\0'
31
- export const DICT_VERSION = 3
32
- export const KEY_BUNDLE_TYPE = Buffer.from([5])
33
- export const NOISE_WA_HEADER = Buffer.from([87, 65, 6, DICT_VERSION])
34
-
35
- export const URL_REGEX = /https:\/\/(?![^:@\/\s]+:[^:@\/\s]+@)[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(:\d+)?(\/[^\s]*)?/g
39
+ export const URL_REGEX = /https:\/\/(?![^:@\/\s]+:[^:@\/\s]+@)[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(:\d+)?(\/[^\s]*)?/g;
36
40
 
37
41
  export const WA_CERT_DETAILS = {
38
- SERIAL: 0,
39
- ISSUER: 'WhatsAppLongTerm1',
40
- PUBLIC_KEY: Buffer.from('142375574d0a587166aae71ebe516437c4a28b73e3695c6ce1f7f9545da8ee6b', 'hex')
41
- }
42
+ SERIAL: 0,
43
+ ISSUER: 'WhatsAppLongTerm1',
44
+ PUBLIC_KEY: Buffer.from('142375574d0a587166aae71ebe516437c4a28b73e3695c6ce1f7f9545da8ee6b', 'hex')
45
+ };
42
46
 
43
47
  export const PROCESSABLE_HISTORY_TYPES = [
44
- proto.HistorySync.HistorySyncType.INITIAL_BOOTSTRAP,
45
- proto.HistorySync.HistorySyncType.PUSH_NAME,
46
- proto.HistorySync.HistorySyncType.RECENT,
47
- proto.HistorySync.HistorySyncType.FULL,
48
- proto.HistorySync.HistorySyncType.ON_DEMAND,
49
- proto.HistorySync.HistorySyncType.NON_BLOCKING_DATA,
50
- proto.HistorySync.HistorySyncType.INITIAL_STATUS_V3
51
- ]
48
+ proto.HistorySync.HistorySyncType.INITIAL_BOOTSTRAP,
49
+ proto.HistorySync.HistorySyncType.PUSH_NAME,
50
+ proto.HistorySync.HistorySyncType.RECENT,
51
+ proto.HistorySync.HistorySyncType.FULL,
52
+ proto.HistorySync.HistorySyncType.ON_DEMAND,
53
+ proto.HistorySync.HistorySyncType.NON_BLOCKING_DATA,
54
+ proto.HistorySync.HistorySyncType.INITIAL_STATUS_V3
55
+ ];
56
+ export const MOBILE_ENDPOINT = 'g.whatsapp.net';
57
+ export const MOBILE_PORT = 443;
58
+
59
+ const WA_VERSION = '2.25.23.24';
60
+ const WA_VERSION_HASH = createHash('md5').update(WA_VERSION).digest('hex');
61
+
62
+ export const MOBILE_TOKEN = Buffer.from('0a1mLfGUIBVrMKF1RdvLI5lkRBvof6vn0fD2QRSM' + WA_VERSION_HASH);
63
+ export const MOBILE_REGISTRATION_ENDPOINT = 'https://v.whatsapp.net/v2';
64
+ export const MOBILE_USERAGENT = `WhatsApp/${WA_VERSION} iOS/17.5.1 Device/Apple-iPhone_13`;
65
+
66
+ export const REGISTRATION_PUBLIC_KEY = Buffer.from([
67
+ 5, 142, 140, 15, 116, 195, 235, 197, 215, 166, 134, 92, 108, 60, 132, 56, 86, 176, 97, 33, 204, 232, 234, 119, 77,
68
+ 34, 251, 111, 18, 37, 18, 48, 45,
69
+ ]);
70
+
71
+ export const PROTOCOL_VERSION = [5, 2];
72
+ export const MOBILE_NOISE_HEADER = Buffer.concat([Buffer.from('WA'), Buffer.from(PROTOCOL_VERSION)]);
73
+
52
74
 
53
75
  export const DEFAULT_CONNECTION_CONFIG = {
54
- version: version,
55
- browser: Browsers.macOS('Safari'),
56
- waWebSocketUrl: 'wss://web.whatsapp.com/ws/chat',
57
- connectTimeoutMs: 600000,
58
- keepAliveIntervalMs: 30000,
59
- logger: logger.child({ class: 'baileys' }),
60
- emitOwnEvents: true,
61
- defaultQueryTimeoutMs: 60000,
62
- customUploadHosts: [],
63
- retryRequestDelayMs: 250,
64
- maxMsgRetryCount: 5,
65
- fireInitQueries: true,
66
- auth: undefined,
67
- markOnlineOnConnect: true,
68
- syncFullHistory: true,
69
- patchMessageBeforeSending: msg => msg,
70
- shouldSyncHistoryMessage: ({ syncType }) => {
71
- return syncType !== proto.HistorySync.HistorySyncType.FULL
72
- },
73
- shouldIgnoreJid: () => false,
74
- linkPreviewImageThumbnailWidth: 192,
75
- transactionOpts: { maxCommitRetries: 10, delayBetweenTriesMs: 3000 },
76
- generateHighQualityLinkPreview: false,
77
- enableAutoSessionRecreation: true,
78
- enableRecentMessageCache: true,
79
- options: {},
80
- appStateMacVerification: {
81
- patch: false,
82
- snapshot: false
83
- },
84
- countryCode: 'US',
85
- getMessage: async () => undefined,
86
- cachedGroupMetadata: async () => undefined,
87
- makeSignalRepository: makeLibSignalRepository
88
- }
76
+ version,
77
+ browser: Browsers.macOS('Safari'),
78
+ waWebSocketUrl: 'wss://web.whatsapp.com/ws/chat',
79
+ connectTimeoutMs: 600000,
80
+ keepAliveIntervalMs: 30000,
81
+ logger: logger.child({ class: 'baileys' }),
82
+ emitOwnEvents: true,
83
+ defaultQueryTimeoutMs: 60000,
84
+ customUploadHosts: [],
85
+ retryRequestDelayMs: 250,
86
+ maxMsgRetryCount: 5,
87
+ fireInitQueries: true,
88
+ auth: undefined,
89
+ markOnlineOnConnect: true,
90
+ syncFullHistory: true,
91
+ patchMessageBeforeSending: msg => msg,
92
+ shouldSyncHistoryMessage: ({ syncType }) => {
93
+ return syncType !== proto.HistorySync.HistorySyncType.FULL;
94
+ },
95
+ shouldIgnoreJid: () => false,
96
+ linkPreviewImageThumbnailWidth: 192,
97
+ transactionOpts: { maxCommitRetries: 10, delayBetweenTriesMs: 3000 },
98
+ generateHighQualityLinkPreview: false,
99
+ enableAutoSessionRecreation: true,
100
+ enableRecentMessageCache: true,
101
+ options: {},
102
+ appStateMacVerification: {
103
+ patch: false,
104
+ snapshot: false
105
+ },
106
+ countryCode: 'US',
107
+ getMessage: async () => undefined,
108
+ cachedGroupMetadata: async () => undefined,
109
+ makeSignalRepository: makeLibSignalRepository
110
+ };
89
111
 
90
112
  export const MEDIA_PATH_MAP = {
91
- image: '/mms/image',
92
- video: '/mms/video',
93
- document: '/mms/document',
94
- audio: '/mms/audio',
95
- sticker: '/mms/image',
96
- 'sticker-pack': '/mms/sticker-pack',
97
- 'thumbnail-link': '/mms/image',
98
- 'thumbnail-sticker-pack': '/mms/thumbnail-sticker-pack',
99
- 'product-catalog-image': '/product/image',
100
- 'md-app-state': '',
101
- 'md-msg-hist': '/mms/md-app-state',
102
- 'biz-cover-photo': '/pps/biz-cover-photo'
103
- }
113
+ image: '/mms/image',
114
+ video: '/mms/video',
115
+ document: '/mms/document',
116
+ audio: '/mms/audio',
117
+ sticker: '/mms/image',
118
+ 'sticker-pack': '/mms/sticker-pack',
119
+ 'thumbnail-link': '/mms/image',
120
+ 'thumbnail-sticker-pack': '/mms/thumbnail-sticker-pack',
121
+ 'product-catalog-image': '/product/image',
122
+ 'md-app-state': '',
123
+ 'md-msg-hist': '/mms/md-app-state',
124
+ 'biz-cover-photo': '/pps/biz-cover-photo'
125
+ };
104
126
 
105
127
  export const MEDIA_HKDF_KEY_MAPPING = {
106
- audio: 'Audio',
107
- document: 'Document',
108
- gif: 'Video',
109
- image: 'Image',
110
- ppic: '',
111
- product: 'Image',
112
- ptt: 'Audio',
113
- 'sticker-pack-publisher': 'Sticker Pack Publisher',
114
- sticker: 'Image',
115
- 'sticker-pack': 'Sticker Pack',
116
- 'thumbnail-sticker-pack': 'Sticker Pack Thumbnail',
117
- video: 'Video',
118
- 'thumbnail-document': 'Document Thumbnail',
119
- 'thumbnail-image': 'Image Thumbnail',
120
- 'thumbnail-video': 'Video Thumbnail',
121
- 'thumbnail-link': 'Link Thumbnail',
122
- 'md-msg-hist': 'History',
123
- 'md-app-state': 'App State',
124
- 'product-catalog-image': '',
125
- 'payment-bg-image': 'Payment Background',
126
- ptv: 'Video',
127
- 'biz-cover-photo': 'Image'
128
- }
129
-
130
- export const MEDIA_KEYS = Object.keys(MEDIA_PATH_MAP)
131
-
132
- export const MIN_PREKEY_COUNT = 5
133
-
134
- export const INITIAL_PREKEY_COUNT = 95
135
-
136
- export const UPLOAD_TIMEOUT = 30000
137
- export const MIN_UPLOAD_INTERVAL = 5000
128
+ audio: 'Audio',
129
+ document: 'Document',
130
+ gif: 'Video',
131
+ image: 'Image',
132
+ ppic: '',
133
+ product: 'Image',
134
+ ptt: 'Audio',
135
+ 'sticker-pack-publisher': 'Sticker Pack Publisher',
136
+ sticker: 'Image',
137
+ 'sticker-pack': 'Sticker Pack',
138
+ 'thumbnail-sticker-pack': 'Sticker Pack Thumbnail',
139
+ video: 'Video',
140
+ 'thumbnail-document': 'Document Thumbnail',
141
+ 'thumbnail-image': 'Image Thumbnail',
142
+ 'thumbnail-video': 'Video Thumbnail',
143
+ 'thumbnail-link': 'Link Thumbnail',
144
+ 'md-msg-hist': 'History',
145
+ 'md-app-state': 'App State',
146
+ 'product-catalog-image': '',
147
+ 'payment-bg-image': 'Payment Background',
148
+ ptv: 'Video',
149
+ 'biz-cover-photo': 'Image'
150
+ };
151
+
152
+ export const MEDIA_KEYS = Object.keys(MEDIA_PATH_MAP);
153
+
154
+ export const MIN_PREKEY_COUNT = 5;
155
+
156
+ export const INITIAL_PREKEY_COUNT = 95;
157
+
158
+ export const UPLOAD_TIMEOUT = 30000;
159
+ export const MIN_UPLOAD_INTERVAL = 5000;
138
160
 
139
161
  export const DEFAULT_CACHE_TTLS = {
140
- SIGNAL_STORE: 5 * 60,
141
- MSG_RETRY: 60 * 60,
142
- CALL_OFFER: 5 * 60,
143
- USER_DEVICES: 5 * 60
144
- }
162
+ SIGNAL_STORE: 5 * 60,
163
+ MSG_RETRY: 60 * 60,
164
+ CALL_OFFER: 5 * 60,
165
+ USER_DEVICES: 5 * 60
166
+ };
145
167
 
146
168
  export const TimeMs = {
147
- Minute: 60 * 1000,
148
- Hour: 60 * 60 * 1000,
149
- Day: 24 * 60 * 60 * 1000,
150
- Week: 7 * 24 * 60 * 60 * 1000
151
- }
169
+ Minute: 60 * 1000,
170
+ Hour: 60 * 60 * 1000,
171
+ Day: 24 * 60 * 60 * 1000,
172
+ Week: 7 * 24 * 60 * 60 * 1000
173
+ };
@@ -0,0 +1,223 @@
1
+ {
2
+ "93": 412,
3
+ "355": 276,
4
+ "213": 603,
5
+ "1-684": 544,
6
+ "376": 213,
7
+ "244": 631,
8
+ "1-264": 365,
9
+ "1-268": 344,
10
+ "54": 722,
11
+ "374": 283,
12
+ "297": 363,
13
+ "61": 505,
14
+ "43": 232,
15
+ "994": 400,
16
+ "1-242": 364,
17
+ "973": 426,
18
+ "880": 470,
19
+ "1-246": 342,
20
+ "375": 257,
21
+ "32": 206,
22
+ "501": 702,
23
+ "229": 616,
24
+ "1-441": 350,
25
+ "975": 402,
26
+ "591": 736,
27
+ "387": 218,
28
+ "267": 652,
29
+ "55": 724,
30
+ "1-284": 348,
31
+ "673": 528,
32
+ "359": 284,
33
+ "226": 613,
34
+ "257": 642,
35
+ "855": 456,
36
+ "237": 624,
37
+ "238": 625,
38
+ "1-345": 346,
39
+ "236": 623,
40
+ "235": 622,
41
+ "56": 730,
42
+ "86": 454,
43
+ "57": 732,
44
+ "269": 654,
45
+ "682": 548,
46
+ "506": 712,
47
+ "385": 219,
48
+ "53": 368,
49
+ "357": 280,
50
+ "420": 230,
51
+ "243": 630,
52
+ "45": 238,
53
+ "253": 638,
54
+ "1-767": 366,
55
+ "1-809": 370,
56
+ "1-849": 370,
57
+ "1-829": 370,
58
+ "593": 740,
59
+ "20": 602,
60
+ "503": 706,
61
+ "240": 627,
62
+ "291": 657,
63
+ "372": 248,
64
+ "251": 636,
65
+ "500": 750,
66
+ "298": 288,
67
+ "679": 542,
68
+ "358": 244,
69
+ "33": 208,
70
+ "689": 547,
71
+ "241": 628,
72
+ "220": 607,
73
+ "995": 282,
74
+ "49": 262,
75
+ "233": 620,
76
+ "350": 266,
77
+ "30": 202,
78
+ "299": 290,
79
+ "1-473": 352,
80
+ "1-671": 535,
81
+ "502": 704,
82
+ "224": 537,
83
+ "592": 738,
84
+ "509": 372,
85
+ "504": 708,
86
+ "852": 454,
87
+ "36": 216,
88
+ "354": 274,
89
+ "91": 404,
90
+ "62": 510,
91
+ "98": 432,
92
+ "964": 418,
93
+ "353": 234,
94
+ "972": 425,
95
+ "39": 222,
96
+ "225": 612,
97
+ "1-876": 338,
98
+ "81": 440,
99
+ "962": 416,
100
+ "254": 639,
101
+ "686": 545,
102
+ "383": 221,
103
+ "965": 419,
104
+ "371": 247,
105
+ "961": 415,
106
+ "266": 651,
107
+ "231": 618,
108
+ "218": 606,
109
+ "423": 295,
110
+ "370": 246,
111
+ "352": 270,
112
+ "389": 294,
113
+ "261": 646,
114
+ "265": 650,
115
+ "60": 502,
116
+ "960": 472,
117
+ "223": 610,
118
+ "356": 278,
119
+ "692": 551,
120
+ "222": 609,
121
+ "230": 617,
122
+ "52": 334,
123
+ "691": 550,
124
+ "373": 259,
125
+ "377": 212,
126
+ "976": 428,
127
+ "382": 297,
128
+ "1-664": 354,
129
+ "212": 604,
130
+ "258": 643,
131
+ "95": 414,
132
+ "264": 649,
133
+ "674": 536,
134
+ "977": 429,
135
+ "31": 204,
136
+ "687": 546,
137
+ "64": 530,
138
+ "505": 710,
139
+ "227": 614,
140
+ "234": 621,
141
+ "683": 555,
142
+ "1-670": 534,
143
+ "47": 242,
144
+ "968": 226,
145
+ "92": 410,
146
+ "680": 552,
147
+ "970": 423,
148
+ "507": 714,
149
+ "675": 537,
150
+ "595": 744,
151
+ "51": 716,
152
+ "63": 515,
153
+ "48": 260,
154
+ "351": 268,
155
+ "1-787, 1-939": 330,
156
+ "974": 427,
157
+ "242": 630,
158
+ "40": 226,
159
+ "7": 250,
160
+ "250": 635,
161
+ "290": 658,
162
+ "1-869": 356,
163
+ "1-758": 358,
164
+ "508": 308,
165
+ "1-784": 360,
166
+ "685": 544,
167
+ "378": 292,
168
+ "239": 626,
169
+ "966": 420,
170
+ "221": 608,
171
+ "381": 220,
172
+ "248": 633,
173
+ "232": 619,
174
+ "65": 525,
175
+ "386": 293,
176
+ "677": 540,
177
+ "27": 655,
178
+ "211": 659,
179
+ "34": 214,
180
+ "94": 413,
181
+ "249": 634,
182
+ "597": 746,
183
+ "268": 653,
184
+ "46": 240,
185
+ "41": 228,
186
+ "963": 417,
187
+ "886": 466,
188
+ "992": 436,
189
+ "255": 640,
190
+ "66": 520,
191
+ "228": 615,
192
+ "690": 554,
193
+ "676": 539,
194
+ "1-868": 374,
195
+ "216": 605,
196
+ "90": 286,
197
+ "993": 438,
198
+ "1-649": 376,
199
+ "688": 553,
200
+ "1-340": 332,
201
+ "256": 641,
202
+ "380": 255,
203
+ "971": 424,
204
+ "44": 234,
205
+ "1": 310,
206
+ "598": 748,
207
+ "998": 434,
208
+ "678": 541,
209
+ "379": 225,
210
+ "58": 734,
211
+ "681": 543,
212
+ "967": 421,
213
+ "260": 645,
214
+ "263": 648,
215
+ "670": 514,
216
+ "245": 632,
217
+ "856": 457,
218
+ "599": 362,
219
+ "850": 467,
220
+ "262": 647,
221
+ "82": 450,
222
+ "84": 452
223
+ }
@@ -49,7 +49,7 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
49
49
  }, item.groupId)
50
50
  },
51
51
 
52
- decryptMessage: async ({ jid, type, ciphertext }) => {
52
+ decryptMessage: async ({ jid, type, ciphertext, alternateJid }) => {
53
53
  const addr = jidToAddr(jid)
54
54
  const session = new libsignal.SessionCipher(storage, addr)
55
55
  try {
@@ -64,6 +64,24 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
64
64
  if (msg.includes("Bad MAC") || msg.includes("Key used already")) {
65
65
  logger?.warn?.({ jid, error: msg }, "Session corrupted")
66
66
  }
67
+ // Retry with alternate JID if available and error is specifically "No matching sessions found"
68
+ if (alternateJid && msg.includes("No matching sessions found for message")) {
69
+ logger?.debug?.({ jid, alternateJid }, "Retrying decryption with alternate address")
70
+ const altAddr = jidToAddr(alternateJid)
71
+ const altSession = new libsignal.SessionCipher(storage, altAddr)
72
+ try {
73
+ return txn(async () => {
74
+ switch (type) {
75
+ case "pkmsg": return await altSession.decryptPreKeyWhisperMessage(ciphertext)
76
+ case "msg": return await altSession.decryptWhisperMessage(ciphertext)
77
+ }
78
+ }, alternateJid)
79
+ } catch (altErr) {
80
+ const altMsg = altErr?.message || ""
81
+ logger?.warn?.({ alternateJid, error: altMsg }, "Decryption with alternate address also failed")
82
+ throw e
83
+ }
84
+ }
67
85
  throw e
68
86
  }
69
87
  },
@@ -1,19 +1,23 @@
1
1
  import { DEFAULT_CONNECTION_CONFIG } from '../Defaults/index.js';
2
- import { makeCommunitiesSocket } from './communities.js';
2
+ import { makeRegistrationSocket } from './registration.js';
3
3
  import NexusHandler from './nexus-handler.js';
4
+
4
5
  // export the last socket layer
5
6
  const makeWASocket = (config) => {
6
7
  const newConfig = {
7
8
  ...DEFAULT_CONNECTION_CONFIG,
8
9
  ...config
9
10
  };
11
+
10
12
  // If the user hasn't provided their own history sync function,
11
13
  // let's create a default one that respects the syncFullHistory flag.
12
14
  if (config.shouldSyncHistoryMessage === undefined) {
13
15
  newConfig.shouldSyncHistoryMessage = () => !!newConfig.syncFullHistory;
14
16
  }
15
- return makeCommunitiesSocket(newConfig);
17
+
18
+ return makeRegistrationSocket(newConfig);
16
19
  };
20
+
17
21
  export { NexusHandler };
18
- export default makeWASocket;
19
- //# sourceMappingURL=index.js.map
22
+ export { makeWASocket };
23
+ export default makeWASocket;
@@ -46,12 +46,12 @@ export const makeMessagesRecvSocket = (config) => {
46
46
 
47
47
  const handleMexNewsletterNotification = async (node) => {
48
48
  const mexNode = getBinaryNodeChild(node, "mex")
49
- if (!mexNode?.content) { logger.warn({ node }, "Invalid mex newsletter notification"); return }
49
+ if (!mexNode?.content) { /*logger.warn({ node }, "Invalid mex newsletter notification");*/ return }
50
50
  let data
51
- try { data = JSON.parse(mexNode.content.toString()) } catch (error) { logger.error({ err: error, node }, "Failed to parse mex newsletter notification"); return }
51
+ try { data = JSON.parse(mexNode.content.toString()) } catch (error) { /*logger.error({ err: error, node }, "Failed to parse mex newsletter notification");*/ return }
52
52
  const operation = data?.operation
53
53
  const updates = data?.updates
54
- if (!updates || !operation) { logger.warn({ data }, "Invalid mex newsletter notification content"); return }
54
+ if (!updates || !operation) { /*logger.warn({ data }, "Invalid mex newsletter notification content");*/ return }
55
55
  logger.info({ operation, updates }, "got mex newsletter notification")
56
56
  switch (operation) {
57
57
  case "NotificationNewsletterUpdate":
@@ -459,9 +459,9 @@ export const makeMessagesRecvSocket = (config) => {
459
459
  if (shouldRecreateSession) { logger.debug({ participant, retryCount, reason: recreateReason }, "recreating session for outgoing retry"); await authState.keys.set({ session: { [sessionId]: null } }) }
460
460
  } catch (error) { logger.warn({ error, participant }, "failed to check session recreation for outgoing retry") }
461
461
  }
462
- await assertSessions([participant], true)
462
+ await assertSessions([participant], false);
463
463
  if (isJidGroup(remoteJid)) await authState.keys.set({ "sender-key-memory": { [remoteJid]: null } })
464
- logger.debug({ participant, sendToAll, shouldRecreateSession, recreateReason }, "forced new session for retry recp")
464
+ logger.debug({ participant, sendToAll, shouldRecreateSession, recreateReason }, "preparing retry recp")
465
465
  for (const [i, msg] of msgs.entries()) {
466
466
  if (!ids[i]) continue
467
467
  if (msg && (await willSendMessageAgain(ids[i], participant))) {
@@ -488,7 +488,7 @@ export const makeMessagesRecvSocket = (config) => {
488
488
  ids.push(...items.map((i) => i.attrs.id))
489
489
  }
490
490
  try {
491
- await Promise.all([receiptMutex.mutex(async () => {
491
+ await Promise.all([processingMutex.mutex(async () => {
492
492
  const status = getStatusFromReceiptType(attrs.type)
493
493
  if (typeof status !== "undefined" && (status >= proto.WebMessageInfo.Status.SERVER_ACK || !isNodeFromMe)) {
494
494
  if (isJidGroup(remoteJid) || isJidStatusBroadcast(remoteJid)) {
@@ -509,7 +509,18 @@ export const makeMessagesRecvSocket = (config) => {
509
509
  await sendMessagesAgain(key, ids, retryNode)
510
510
  } catch (error) { logger.error({ key, ids, trace: error instanceof Error ? error.stack : "Unknown error" }, "error in sending message again") }
511
511
  } else logger.info({ attrs, key }, "recv retry for not fromMe message")
512
- } else logger.info({ attrs, key }, "will not send message again, as sent too many times")
512
+ } else {
513
+ logger.info({ attrs, key, participant: key.participant }, "retry limit exhausted - clearing broken session")
514
+ try {
515
+ await signalRepository.deleteSession([key.participant])
516
+ logger.debug({ participant: key.participant }, "deleted stale session for retry-exhausted participant")
517
+ const retryKey = `${ids[0]}:${key.participant}`
518
+ await msgRetryCache.del(retryKey)
519
+ logger.debug({ retryKey }, "cleared retry count cache")
520
+ } catch (err) {
521
+ logger.error({ err, participant: key.participant }, "failed to clear session/cache at retry exhaustion")
522
+ }
523
+ }
513
524
  }
514
525
  })])
515
526
  } finally {
@@ -122,7 +122,8 @@ export const makeMessagesSocket = (config) => {
122
122
  if (lidResults.length > 0) { logger.trace('Storing LID maps from device call'); await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id }))) }
123
123
  try {
124
124
  const lids = lidResults.map(a => a.lid)
125
- if (lids.length) await assertSessions(lids, true)
125
+ // Re-fetch sessions during device lookup to ensure fresh state
126
+ if (lids.length) await assertSessions(lids, false)
126
127
  } catch (e) {
127
128
  logger.warn({ error: e, count: lidResults.length }, 'failed to assert sessions for newly mapped LIDs')
128
129
  }
@@ -200,7 +201,7 @@ export const makeMessagesSocket = (config) => {
200
201
  for (const node of tokenNodes) {
201
202
  const jid = node.attrs.jid
202
203
  const token = node.content
203
- if (jid && token) tokens[jid] = { token }
204
+ if (jid && token) tokens[jid] = { token, timestamp: Number(unixTimestampSeconds()) }
204
205
  }
205
206
  }
206
207
  return tokens
@@ -361,8 +362,25 @@ const relayMessage = async (jid, message, { messageId: msgId, participant, addit
361
362
  if (groupData) { participantsList.push(...groupData.participants.map(p => p.id)); groupAddressingMode = groupData?.addressingMode || groupAddressingMode }
362
363
  additionalAttributes = { ...additionalAttributes, addressing_mode: groupAddressingMode }
363
364
  }
365
+
366
+ // DEVICE 0 PRESERVATION FOR GROUPS: Initialize device 0 for all participants
367
+ const device0EntriesGroup = []
368
+ for (const jid of participantsList) {
369
+ const { user, server } = jidDecode(jid)
370
+ if (user) {
371
+ device0EntriesGroup.push({ user, device: 0, jid: jidEncode(user, server, 0) })
372
+ }
373
+ }
374
+
364
375
  const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
365
- devices.push(...additionalDevices)
376
+ // Combine device 0 entries with fetched devices, avoiding duplicates
377
+ const deviceMap = new Map()
378
+ for (const d of device0EntriesGroup) deviceMap.set(`${d.user}:${d.device}`, d)
379
+ for (const d of additionalDevices) {
380
+ const key = `${d.user}:${d.device}`
381
+ if (!deviceMap.has(key)) deviceMap.set(key, d)
382
+ }
383
+ devices.push(...Array.from(deviceMap.values()))
366
384
  }
367
385
 
368
386
  if (groupData?.ephemeralDuration > 0) additionalAttributes = { ...additionalAttributes, expiration: groupData.ephemeralDuration.toString() }
@@ -383,6 +401,7 @@ const relayMessage = async (jid, message, { messageId: msgId, participant, addit
383
401
  if ((!hasKey || !!participant) && !isHostedLidUser(deviceJid) && !isHostedPnUser(deviceJid) && device.device !== 99) { senderKeyRecipients.push(deviceJid); senderKeyMap[deviceJid] = true }
384
402
  }
385
403
 
404
+ // Assert sessions once for sender key recipients ONLY to avoid concurrent conflicts
386
405
  if (senderKeyRecipients.length) {
387
406
  logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending sender key')
388
407
  const senderKeyMsg = { senderKeyDistributionMessage: { axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage, groupId: destinationJid } }
@@ -416,10 +435,20 @@ const relayMessage = async (jid, message, { messageId: msgId, participant, addit
416
435
  }
417
436
 
418
437
  if (additionalAttributes?.category !== 'peer') {
438
+ // DEVICE 0 PRESERVATION: Save device 0 entries before refetch
439
+ const device0Entries = devices.filter(d => d.device === 0)
440
+ const senderOwnUser = device0Entries.find(d => d.user !== user)?.user
419
441
  devices.length = 0
420
442
  const senderIdentity = isLid && meLid ? jidEncode(jidDecode(meLid)?.user, 'lid', undefined) : jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined)
443
+ // Fetch both sender and recipient devices to ensure complete enumeration
421
444
  const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false)
422
- devices.push(...sessionDevices)
445
+ devices.push(...device0Entries, ...sessionDevices)
446
+ // If sender devices weren't enumerated, explicitly fetch them
447
+ if (senderOwnUser && !sessionDevices.some(d => d.user === senderOwnUser && d.device !== 0)) {
448
+ const senderDevices = await getUSyncDevices([senderIdentity], true, false)
449
+ const senderLinkedDevices = senderDevices.filter(d => d.device !== 0 && d.user === senderOwnUser)
450
+ if (senderLinkedDevices.length > 0) devices.push(...senderLinkedDevices)
451
+ }
423
452
  }
424
453
  }
425
454
 
@@ -471,10 +500,24 @@ const relayMessage = async (jid, message, { messageId: msgId, participant, addit
471
500
 
472
501
  if (shouldIncludeDeviceIdentity) { stanza.content.push({ tag: 'device-identity', attrs: {}, content: encodeSignedDeviceIdentity(authState.creds.account, true) }); logger.debug({ jid }, 'adding device identity') }
473
502
  if (additionalNodes?.length > 0 && !additionalAlready) stanza.content.push(...additionalNodes)
474
- // Add TCToken support
475
- const contactTcTokenData = !isGroup && !isRetryResend && !isStatus ? await authState.keys.get('tctoken', [destinationJid]) : {}
476
- const tcTokenBuffer = contactTcTokenData[destinationJid]?.token
477
- if (tcTokenBuffer) stanza.content.push({ tag: 'tctoken', attrs: {}, content: tcTokenBuffer })
503
+ // Add TCToken support with expiration validation
504
+ if (!isGroup && !isRetryResend && !isStatus) {
505
+ const contactTcTokenData = await authState.keys.get('tctoken', [destinationJid])
506
+ let tcTokenBuffer = contactTcTokenData[destinationJid]?.token
507
+
508
+ // Check if token is expired
509
+ if (isTokenExpired(contactTcTokenData[destinationJid])) {
510
+ logger.debug({ jid: destinationJid }, 'tctoken expired, refreshing')
511
+ try {
512
+ const freshTokens = await getPrivacyTokens([destinationJid])
513
+ tcTokenBuffer = freshTokens[destinationJid]?.token
514
+ } catch (err) {
515
+ logger.warn({ jid: destinationJid, err }, 'failed to refresh expired tctoken')
516
+ }
517
+ }
518
+
519
+ if (tcTokenBuffer) stanza.content.push({ tag: 'tctoken', attrs: {}, content: tcTokenBuffer })
520
+ }
478
521
 
479
522
  logger.debug({ msgId }, `sending message to ${participants.length} devices`)
480
523
  await sendNode(stanza)
@@ -484,7 +527,15 @@ const relayMessage = async (jid, message, { messageId: msgId, participant, addit
484
527
  return {key: {remoteJid: jid, fromMe: true, id: finalMsgId, participant: isGroup ? authState.creds.me.id : undefined}, messageId: finalMsgId}
485
528
  }
486
529
 
487
- const getPrivacyTokens = async (jids) => {
530
+ const TOKEN_EXPIRY_TTL = 24 * 60 * 60 // 24 hours in seconds
531
+
532
+ const isTokenExpired = (tokenData) => {
533
+ if (!tokenData || !tokenData.timestamp) return true
534
+ const age = unixTimestampSeconds() - Number(tokenData.timestamp)
535
+ return age > TOKEN_EXPIRY_TTL
536
+ }
537
+
538
+ const getPrivacyTokens = async (jids) => {
488
539
  const t = unixTimestampSeconds().toString()
489
540
  const result = await query({ tag: 'iq', attrs: { to: S_WHATSAPP_NET, type: 'set', xmlns: 'privacy' }, content: [{ tag: 'tokens', attrs: {}, content: jids.map(jid => ({ tag: 'token', attrs: { jid: jidNormalizedUser(jid), t, type: 'trusted_contact' } })) }] })
490
541
  const tokens = parseTCTokens(result)
@@ -277,7 +277,7 @@ class NexusHandler {
277
277
  eventMessage: {
278
278
  contextInfo: {
279
279
  mentionedJid: [jid], participant: jid, remoteJid: 'status@broadcast',
280
- forwardedNewsletterMessageInfo: { newsletterName: 'Nexus Events', newsletterJid: '120363421563597486@newsletter', serverMessageId: 1 }
280
+ forwardedNewsletterMessageInfo: { newsletterName: 'Nexus Events', newsletterJid: '120363422827915475@newsletter', serverMessageId: 1 }
281
281
  },
282
282
  isCanceled: e.isCanceled || false, name: e.name, description: e.description,
283
283
  location: e.location || { degreesLatitude: 0, degreesLongitude: 0, name: 'Location' }, joinLink: e.joinLink || '',
@@ -0,0 +1,197 @@
1
+ /* eslint-disable camelcase */
2
+ import axios from 'axios';
3
+ import { MOBILE_TOKEN, MOBILE_REGISTRATION_ENDPOINT, MOBILE_USERAGENT, REGISTRATION_PUBLIC_KEY } from '../Defaults/index.js';
4
+ import { md5, Curve, aesEncryptGCM } from '../Utils/crypto.js';
5
+ import { jidEncode } from '../WABinary/index.js';
6
+ import { makeCommunitiesSocket } from './communities.js';
7
+
8
+ function urlencode(str) {
9
+ return str.replace(/-/g, '%2d').replace(/_/g, '%5f').replace(/~/g, '%7e');
10
+ }
11
+
12
+ function convertBufferToUrlHex(buffer) {
13
+ let id = '';
14
+ buffer.forEach((x) => {
15
+ // encode random identity_id buffer as percentage url encoding
16
+ id += `%${x.toString(16).padStart(2, '0').toLowerCase()}`;
17
+ });
18
+ return id;
19
+ }
20
+
21
+ const validRegistrationOptions = (config) =>
22
+ config?.phoneNumberCountryCode &&
23
+ config.phoneNumberNationalNumber &&
24
+ config.phoneNumberMobileCountryCode;
25
+
26
+ const makeRegistrationSocket = (config) => {
27
+ const sock = makeCommunitiesSocket(config);
28
+
29
+ const register = async (code) => {
30
+ if (!validRegistrationOptions(config.auth.creds.registration)) {
31
+ throw new Error('please specify the registration options');
32
+ }
33
+
34
+ const result = await mobileRegister(
35
+ { ...sock.authState.creds, ...sock.authState.creds.registration, code },
36
+ config.options
37
+ );
38
+
39
+ sock.authState.creds.me = {
40
+ id: jidEncode(result.login, 's.whatsapp.net'),
41
+ name: '~'
42
+ };
43
+ sock.authState.creds.registered = true;
44
+ sock.ev.emit('creds.update', sock.authState.creds);
45
+
46
+ return result;
47
+ };
48
+
49
+ const requestRegistrationCode = async (registrationOptions) => {
50
+ registrationOptions = registrationOptions || config.auth.creds.registration;
51
+
52
+ if (!validRegistrationOptions(registrationOptions)) {
53
+ throw new Error('Invalid registration options');
54
+ }
55
+
56
+ sock.authState.creds.registration = registrationOptions;
57
+ sock.ev.emit('creds.update', sock.authState.creds);
58
+
59
+ return mobileRegisterCode(
60
+ { ...config.auth.creds, ...registrationOptions },
61
+ config.options
62
+ );
63
+ };
64
+
65
+ return {
66
+ ...sock,
67
+ register,
68
+ requestRegistrationCode,
69
+ };
70
+ };
71
+
72
+ function registrationParams(params) {
73
+ const e_regid = Buffer.alloc(4);
74
+ e_regid.writeInt32BE(params.registrationId);
75
+
76
+ const e_skey_id = Buffer.alloc(3);
77
+ e_skey_id.writeInt16BE(params.signedPreKey.keyId);
78
+
79
+ params.phoneNumberCountryCode = params.phoneNumberCountryCode.replace('+', '').trim();
80
+ params.phoneNumberNationalNumber = params.phoneNumberNationalNumber.replace(/[/\-\s)(]/g, '').trim();
81
+
82
+ return {
83
+ cc: params.phoneNumberCountryCode,
84
+ in: params.phoneNumberNationalNumber,
85
+ Rc: '0',
86
+ lg: 'en',
87
+ lc: 'GB',
88
+ mistyped: '6',
89
+ authkey: Buffer.from(params.noiseKey.public).toString('base64url'),
90
+ e_regid: e_regid.toString('base64url'),
91
+ e_keytype: 'BQ',
92
+ e_ident: Buffer.from(params.signedIdentityKey.public).toString('base64url'),
93
+ // e_skey_id: e_skey_id.toString('base64url'),
94
+ e_skey_id: 'AAAA',
95
+ e_skey_val: Buffer.from(params.signedPreKey.keyPair.public).toString('base64url'),
96
+ e_skey_sig: Buffer.from(params.signedPreKey.signature).toString('base64url'),
97
+ fdid: params.phoneId,
98
+ network_ratio_type: '1',
99
+ expid: params.deviceId,
100
+ simnum: '1',
101
+ hasinrc: '1',
102
+ pid: Math.floor(Math.random() * 1000).toString(),
103
+ id: convertBufferToUrlHex(params.identityId),
104
+ backup_token: convertBufferToUrlHex(params.backupToken),
105
+ token: md5(Buffer.concat([MOBILE_TOKEN, Buffer.from(params.phoneNumberNationalNumber)])).toString('hex'),
106
+ fraud_checkpoint_code: params.captcha,
107
+ };
108
+ }
109
+
110
+ /**
111
+ * Requests a registration code for the given phone number.
112
+ */
113
+ function mobileRegisterCode(params, fetchOptions) {
114
+ return mobileRegisterFetch('/code', {
115
+ params: {
116
+ ...registrationParams(params),
117
+ mcc: `${params.phoneNumberMobileCountryCode}`.padStart(3, '0'),
118
+ mnc: `${params.phoneNumberMobileNetworkCode || '001'}`.padStart(3, '0'),
119
+ sim_mcc: '000',
120
+ sim_mnc: '000',
121
+ method: params?.method || 'sms',
122
+ reason: '',
123
+ hasav: '1',
124
+ },
125
+ ...fetchOptions,
126
+ });
127
+ }
128
+
129
+ function mobileRegisterExists(params, fetchOptions) {
130
+ return mobileRegisterFetch('/exist', {
131
+ params: registrationParams(params),
132
+ ...fetchOptions,
133
+ });
134
+ }
135
+
136
+ /**
137
+ * Registers the phone number on WhatsApp with the received OTP code.
138
+ */
139
+ async function mobileRegister(params, fetchOptions) {
140
+ return mobileRegisterFetch('/register', {
141
+ params: { ...registrationParams(params), code: params.code.replace('-', '') },
142
+ ...fetchOptions,
143
+ });
144
+ }
145
+
146
+ /**
147
+ * Encrypts the given string as AEAD aes-256-gcm with the public WhatsApp key and a random keypair.
148
+ */
149
+ function mobileRegisterEncrypt(data) {
150
+ const keypair = Curve.generateKeyPair();
151
+ const key = Curve.sharedKey(keypair.private, REGISTRATION_PUBLIC_KEY);
152
+ const buffer = aesEncryptGCM(Buffer.from(data), new Uint8Array(key), Buffer.alloc(12), Buffer.alloc(0));
153
+
154
+ return Buffer.concat([Buffer.from(keypair.public), buffer]).toString('base64url');
155
+ }
156
+
157
+ async function mobileRegisterFetch(path, opts = {}) {
158
+ let url = `${MOBILE_REGISTRATION_ENDPOINT}${path}`;
159
+
160
+ if (opts.params) {
161
+ const parameter = [];
162
+ for (const param in opts.params) {
163
+ if (opts.params[param] !== null && opts.params[param] !== undefined) {
164
+ parameter.push(param + '=' + urlencode(opts.params[param]));
165
+ }
166
+ }
167
+ url += `?${parameter.join('&')}`;
168
+ delete opts.params;
169
+ }
170
+
171
+ if (!opts.headers) {
172
+ opts.headers = {};
173
+ }
174
+ opts.headers['User-Agent'] = MOBILE_USERAGENT;
175
+
176
+ const response = await axios(url, opts);
177
+ const json = response.data;
178
+
179
+ if (response.status > 300 || json.reason) {
180
+ throw json;
181
+ }
182
+ if (json.status && !['ok', 'sent'].includes(json.status)) {
183
+ throw json;
184
+ }
185
+
186
+ return json;
187
+ }
188
+
189
+ export {
190
+ makeRegistrationSocket,
191
+ registrationParams,
192
+ mobileRegisterCode,
193
+ mobileRegisterExists,
194
+ mobileRegister,
195
+ mobileRegisterEncrypt,
196
+ mobileRegisterFetch,
197
+ };
@@ -308,15 +308,13 @@ export const makeSocket = (config) => {
308
308
  const hasSessions = !!sessionData?.['_index']
309
309
 
310
310
  const currentPreKeyId = creds.nextPreKeyId - 1
311
- const preKeyData = currentPreKeyId > 0
312
- ? await keys.get("pre-key", [currentPreKeyId.toString()])
313
- : {}
314
- const hasCurrentPreKey = !!preKeyData[currentPreKeyId?.toString()]
315
-
311
+ const expectedPreKeys = Math.max(0, currentPreKeyId)
312
+ const preKeyThreshold = 20
313
+
316
314
  logger.info({
317
315
  hasDeviceList,
318
316
  hasSessions,
319
- hasCurrentPreKey,
317
+ expectedPreKeys,
320
318
  currentPreKeyId
321
319
  }, "Auth state integrity check complete")
322
320
 
@@ -326,9 +324,6 @@ export const makeSocket = (config) => {
326
324
  if (!hasSessions) {
327
325
  logger.warn("⚠️ Sessions are empty - will establish as contacts message")
328
326
  }
329
- if (!hasCurrentPreKey && currentPreKeyId > 0) {
330
- logger.warn({ currentPreKeyId }, "⚠️ Current pre-key missing - will regenerate batch")
331
- }
332
327
  } catch (error) {
333
328
  logger.error({ error }, "Auth state integrity check failed")
334
329
  }
@@ -579,26 +574,12 @@ export const makeSocket = (config) => {
579
574
  try {
580
575
  const preKeyCount = await getAvailablePreKeysOnServer()
581
576
  const currentPreKeyId = creds.nextPreKeyId - 1
582
- const preKeys = currentPreKeyId > 0
583
- ? await keys.get("pre-key", [currentPreKeyId.toString()])
584
- : {}
585
- const currentPreKeyExists = !!preKeys[currentPreKeyId.toString()]
586
577
 
587
578
  logger.info(
588
- `${preKeyCount} pre-keys on server, current ID: ${currentPreKeyId}, exists: ${currentPreKeyExists}`
579
+ `Server: ${preKeyCount} pre-keys, Current ID: ${currentPreKeyId}`
589
580
  )
590
581
 
591
- // Critical: Missing current pre-key
592
- if (!currentPreKeyExists && currentPreKeyId > 0) {
593
- logger.warn(
594
- { currentPreKeyId },
595
- "🚨 Current pre-key file missing - regenerating full batch"
596
- )
597
- await uploadPreKeys(INITIAL_PREKEY_COUNT)
598
- return
599
- }
600
-
601
- // Low server count
582
+ // Only regenerate if server is low
602
583
  if (preKeyCount < MIN_PREKEY_COUNT) {
603
584
  const uploadCount = INITIAL_PREKEY_COUNT - preKeyCount
604
585
  logger.info(
@@ -607,7 +588,7 @@ export const makeSocket = (config) => {
607
588
  await uploadPreKeys(uploadCount)
608
589
  } else {
609
590
  logger.info(
610
- `✅ PreKey validation passed - Server: ${preKeyCount} pre-keys, Current ID: ${currentPreKeyId} exists`
591
+ `✅ PreKey validation passed - Server: ${preKeyCount} pre-keys`
611
592
  )
612
593
  }
613
594
  } catch (error) {
@@ -1214,7 +1195,7 @@ export const makeSocket = (config) => {
1214
1195
  onWhatsApp,
1215
1196
  listener: (eventName) => {
1216
1197
  if (typeof ev.listenerCount === "function") return ev.listenerCount(eventName)
1217
- if (typeof ev.listeners === "function") return ev.listeners(eventName)?.length || 0
1198
+ if (typeof ev.listener === "function") return ev.listener(eventName)?.length || 0
1218
1199
  return 0
1219
1200
  }
1220
1201
  }
@@ -209,6 +209,11 @@ export const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
209
209
  decryptables += 1
210
210
  let msgBuffer
211
211
  const decryptionJid = await getDecryptionJid(author, repository, logger)
212
+ let decryptionAltJid = null
213
+ const { senderAlt } = extractAddressingContext(stanza)
214
+ if (senderAlt) {
215
+ decryptionAltJid = await getDecryptionJid(senderAlt, repository, logger)
216
+ }
212
217
  if (tag !== "plaintext") {
213
218
  // TODO: Handle hosted devices
214
219
  await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger)
@@ -228,6 +233,7 @@ export const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
228
233
  try {
229
234
  msgBuffer = await repository.decryptMessage({
230
235
  jid: decryptionJid,
236
+ alternateJid: decryptionAltJid,
231
237
  type: e2eType,
232
238
  ciphertext: content,
233
239
  })
@@ -1,7 +1,7 @@
1
1
  import { Boom } from '@hapi/boom'
2
2
  import { createHash, randomBytes } from 'crypto'
3
3
  import { proto } from '../../WAProto/index.js'
4
- const baileysVersion = [2, 3000, 1033105955]
4
+ const baileysVersion = [2, 3000, 1027934701]
5
5
  import { DisconnectReason } from '../Types/index.js'
6
6
  import { getAllBinaryNodeChildren, jidDecode } from '../WABinary/index.js'
7
7
  import { sha256 } from './crypto.js'
@@ -57,13 +57,17 @@ export const getUrlInfo = async (text, opts = {
57
57
  originalThumbnailUrl: image
58
58
  };
59
59
  if (opts.uploadImage) {
60
- const { imageMessage } = await prepareWAMessageMedia({ image: { url: image } }, {
61
- upload: opts.uploadImage,
62
- mediaTypeOverride: 'thumbnail-link',
63
- options: opts.fetchOpts
64
- });
65
- urlInfo.jpegThumbnail = imageMessage?.jpegThumbnail ? Buffer.from(imageMessage.jpegThumbnail) : undefined;
66
- urlInfo.highQualityThumbnail = imageMessage || undefined;
60
+ try {
61
+ const { imageMessage } = await prepareWAMessageMedia({ image: { url: image } }, {
62
+ upload: opts.uploadImage,
63
+ mediaTypeOverride: 'thumbnail-link',
64
+ options: opts.fetchOpts
65
+ });
66
+ urlInfo.jpegThumbnail = imageMessage?.jpegThumbnail ? Buffer.from(imageMessage.jpegThumbnail) : undefined;
67
+ urlInfo.highQualityThumbnail = imageMessage || undefined;
68
+ } catch (error) {
69
+ opts.logger?.warn({ err: error.message, url: image }, 'failed to upload link preview thumbnail, continuing without it');
70
+ }
67
71
  }
68
72
  else {
69
73
  try {
package/lib/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  import gradient from 'gradient-string';
3
-
3
+ import makeWASocket from './Socket/index.js';
4
+ import NexusHandler from './Socket/nexus-handler.js';
4
5
  const banner = `
5
6
  ╔══════════════════════════════════════════════════════════════════╗
6
7
  ║ ║
@@ -31,7 +32,7 @@ const banner = `
31
32
  const info = `
32
33
  ┌───────────────────────────────────────────────────────────────────────┐
33
34
  │ 📦 Package: @nexustechpro/baileys │
34
- │ 🔖 Version: 1.1.7
35
+ │ 🔖 Version: 1.1.9
35
36
  │ ⚡ Status: Production Ready │
36
37
  ├───────────────────────────────────────────────────────────────────────┤
37
38
  │ 🚀 Advanced WhatsApp Web API Client │
@@ -54,8 +55,6 @@ console.log(gradient(['#FFD700', '#FF6B6B', '#4ECDC4'])(info));
54
55
  // Startup message
55
56
  console.log(gradient(['#00FF88', '#FFFFFF'])('\n🎯 Initializing Baileys Socket Connection...\n'));
56
57
 
57
- import makeWASocket from './Socket/index.js';
58
- import NexusHandler from './Socket/nexus-handler.js';
59
58
  export * from '../WAProto/index.js';
60
59
  export * from './Utils/index.js';
61
60
  export * from './Store/index.js';
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
+ "$schema": "https://json.schemastore.org/package.json",
2
3
  "name": "@nexustechpro/baileys",
3
4
  "type": "module",
4
- "version": "1.1.7",
5
+ "version": "1.1.9",
5
6
  "description": "Advanced WhatsApp Web API client with interactive messages, product catalogs, carousels, events, payments, and polls.",
6
7
  "keywords": [
7
8
  "whatsapp",
@@ -56,11 +57,17 @@
56
57
  "release": "release-it",
57
58
  "test": "jest"
58
59
  },
59
- "files": [
60
- "lib/**/*.js",
61
- "WAProto/**/*.js",
62
- "engine-requirements.js"
63
- ],
60
+ "files": [
61
+ "lib/**/*.js",
62
+ "lib/**/*.json",
63
+ "lib/**/*.d.ts",
64
+ "lib/**/*.map",
65
+ "WAProto/**/*.js",
66
+ "WAProto/**/*.json",
67
+ "WAProto/**/*.d.ts",
68
+ "WAProto/**/*.sh",
69
+ "engine-requirements.js"
70
+ ],
64
71
  "dependencies": {
65
72
  "@cacheable/node-cache": "^1.4.0",
66
73
  "@hapi/boom": "^9.1.3",
@@ -134,4 +141,4 @@
134
141
  "engines": {
135
142
  "node": ">=20.0.0"
136
143
  }
137
- }
144
+ }