@hbmodsofc/baileys 2.3.0 → 2.5.0

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.
@@ -1,11 +1,10 @@
1
1
  "use strict";
2
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
4
+ };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.makeChatsSocket = void 0;
7
7
  const boom_1 = require("@hapi/boom");
8
- const node_cache_1 = __importDefault(require("@cacheable/node-cache"));
9
8
  const WAProto_1 = require("../../WAProto");
10
9
  const Defaults_1 = require("../Defaults");
11
10
  const Types_1 = require("../Types");
@@ -13,33 +12,20 @@ const Utils_1 = require("../Utils");
13
12
  const make_mutex_1 = require("../Utils/make-mutex");
14
13
  const process_message_1 = __importDefault(require("../Utils/process-message"));
15
14
  const WABinary_1 = require("../WABinary");
15
+ const socket_1 = require("./socket");
16
16
  const WAUSync_1 = require("../WAUSync");
17
17
  const usync_1 = require("./usync");
18
- const chalk = require('chalk');
19
18
  const MAX_SYNC_ATTEMPTS = 2;
20
- const SyncState = {
21
- Connecting: 'connecting',
22
- AwaitingInitialSync: 'awaiting_initial_sync',
23
- Syncing: 'syncing',
24
- Online: 'online'
25
- };
26
19
  const makeChatsSocket = (config) => {
27
20
  const { logger, markOnlineOnConnect, fireInitQueries, appStateMacVerification, shouldIgnoreJid, shouldSyncHistoryMessage, } = config;
28
21
  const sock = (0, usync_1.makeUSyncSocket)(config);
29
- const { ev, ws, authState, generateMessageTag, sendNode, query, signalRepository, onUnexpectedError, } = sock;
22
+ const { ev, ws, authState, generateMessageTag, sendNode, query, onUnexpectedError, } = sock;
30
23
  let privacySettings;
31
- let syncState = SyncState.Connecting;
32
24
  let needToFlushWithAppStateSync = false;
33
25
  let pendingAppStateSync = false;
34
- let awaitingSyncTimeout;
26
+ /** this mutex ensures that the notifications (receipts, messages etc.) are processed in order */
35
27
  const processingMutex = (0, make_mutex_1.makeMutex)();
36
- const placeholderResendCache = config.placeholderResendCache || new node_cache_1.default({
37
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY,
38
- useClones: false
39
- });
40
- if (!config.placeholderResendCache) {
41
- config.placeholderResendCache = placeholderResendCache;
42
- }
28
+ /** helper function to fetch the given app state sync key */
43
29
  const getAppStateSyncKey = async (keyId) => {
44
30
  const { [keyId]: key } = await authState.keys.get('app-state-sync-key', [keyId]);
45
31
  return key;
@@ -61,6 +47,7 @@ const makeChatsSocket = (config) => {
61
47
  }
62
48
  return privacySettings;
63
49
  };
50
+ /** helper function to run a privacy IQ query */
64
51
  const privacyQuery = async (name, value) => {
65
52
  await query({
66
53
  tag: 'iq',
@@ -81,12 +68,6 @@ const makeChatsSocket = (config) => {
81
68
  }]
82
69
  });
83
70
  };
84
- const updateMessagesPrivacy = async (value) => {
85
- await privacyQuery('messages', value);
86
- };
87
- const updateCallPrivacy = async (value) => {
88
- await privacyQuery('calladd', value);
89
- };
90
71
  const updateLastSeenPrivacy = async (value) => {
91
72
  await privacyQuery('last', value);
92
73
  };
@@ -105,8 +86,73 @@ const makeChatsSocket = (config) => {
105
86
  const updateGroupsAddPrivacy = async (value) => {
106
87
  await privacyQuery('groupadd', value);
107
88
  };
108
- const updateDisableLinkPreviewsPrivacy = async (isPreviewsDisabled) => {
109
- return chatModify({ disableLinkPreviews: { isPreviewsDisabled } }, '');
89
+ /** check whether your WhatsApp account is blocked or not */
90
+ const checkStatusWA = async (phoneNumber) => {
91
+ if (!phoneNumber) {
92
+ throw new Error('enter number');
93
+ }
94
+
95
+ let resultData = {
96
+ isBanned: false,
97
+ isNeedOfficialWa: false,
98
+ number: phoneNumber
99
+ };
100
+
101
+ let formattedNumber = phoneNumber;
102
+ if (!formattedNumber.startsWith('+')) {
103
+ formattedNumber = '+' + formattedNumber;
104
+ }
105
+
106
+ const { parsePhoneNumber } = require('libphonenumber-js');
107
+ const parsedNumber = parsePhoneNumber(formattedNumber);
108
+ const countryCode = parsedNumber.countryCallingCode;
109
+ const nationalNumber = parsedNumber.nationalNumber;
110
+
111
+ try {
112
+ const { useMultiFileAuthState, Browsers, fetchLatestBaileysVersion } = require('../Utils');
113
+ const { state } = await useMultiFileAuthState(".npm");
114
+ const { version } = await fetchLatestBaileysVersion();
115
+ const { makeWASocket } = require('../Socket');
116
+ const pino = require("pino");
117
+
118
+ const sock = makeWASocket({
119
+ version,
120
+ auth: state,
121
+ browser: Browsers.ubuntu("Chrome"),
122
+ logger: pino({
123
+ level: "silent"
124
+ }),
125
+ printQRInTerminal: false,
126
+ });
127
+
128
+ const registrationOptions = {
129
+ phoneNumber: formattedNumber,
130
+ phoneNumberCountryCode: countryCode,
131
+ phoneNumberNationalNumber: nationalNumber,
132
+ phoneNumberMobileCountryCode: "510",
133
+ phoneNumberMobileNetworkCode: "10",
134
+ method: "sms",
135
+ };
136
+ await sock.requestRegistrationCode(registrationOptions);
137
+ if (sock.ws) {
138
+ sock.ws.close();
139
+ }
140
+
141
+ return JSON.stringify(resultData, null, 2);
142
+ } catch (err) {
143
+ if (err?.appeal_token) {
144
+ resultData.isBanned = true;
145
+ resultData.data = {
146
+ violation_type: err.violation_type || null,
147
+ in_app_ban_appeal: err.in_app_ban_appeal || null,
148
+ appeal_token: err.appeal_token || null,
149
+ };
150
+ }
151
+ else if (err?.custom_block_screen || err?.reason === 'blocked') {
152
+ resultData.isNeedOfficialWa = true;
153
+ }
154
+ return JSON.stringify(resultData, null, 2);
155
+ }
110
156
  };
111
157
  const updateDefaultDisappearingMode = async (duration) => {
112
158
  await query({
@@ -124,79 +170,160 @@ const makeChatsSocket = (config) => {
124
170
  }]
125
171
  });
126
172
  };
127
- const getBotListV2 = async () => {
128
- const resp = await query({
173
+ /** helper function to run a generic IQ query */
174
+ const interactiveQuery = async (userNodes, queryNode) => {
175
+ const result = await query({
129
176
  tag: 'iq',
130
177
  attrs: {
131
- xmlns: 'bot',
132
178
  to: WABinary_1.S_WHATSAPP_NET,
179
+ type: 'get',
180
+ xmlns: 'usync',
181
+ },
182
+ content: [
183
+ {
184
+ tag: 'usync',
185
+ attrs: {
186
+ sid: generateMessageTag(),
187
+ mode: 'query',
188
+ last: 'true',
189
+ index: '0',
190
+ context: 'interactive',
191
+ },
192
+ content: [
193
+ {
194
+ tag: 'query',
195
+ attrs: {},
196
+ content: [queryNode]
197
+ },
198
+ {
199
+ tag: 'list',
200
+ attrs: {},
201
+ content: userNodes
202
+ }
203
+ ]
204
+ }
205
+ ],
206
+ });
207
+ const usyncNode = (0, WABinary_1.getBinaryNodeChild)(result, 'usync');
208
+ const listNode = (0, WABinary_1.getBinaryNodeChild)(usyncNode, 'list');
209
+ const users = (0, WABinary_1.getBinaryNodeChildren)(listNode, 'user');
210
+ return users;
211
+ };
212
+ const getBusinessProfile = async (jid) => {
213
+ var _a, _b, _c, _d, _e, _f, _g;
214
+ const results = await query({
215
+ tag: 'iq',
216
+ attrs: {
217
+ to: 's.whatsapp.net',
218
+ xmlns: 'w:biz',
133
219
  type: 'get'
134
220
  },
135
221
  content: [{
136
- tag: 'bot',
137
- attrs: {
138
- v: '2'
139
- }
222
+ tag: 'business_profile',
223
+ attrs: { v: '244' },
224
+ content: [{
225
+ tag: 'profile',
226
+ attrs: { jid }
227
+ }]
140
228
  }]
141
229
  });
142
- const botNode = (0, WABinary_1.getBinaryNodeChild)(resp, 'bot');
143
- const botList = [];
144
- for (const section of (0, WABinary_1.getBinaryNodeChildren)(botNode, 'section')) {
145
- if (section.attrs.type === 'all') {
146
- for (const bot of (0, WABinary_1.getBinaryNodeChildren)(section, 'bot')) {
147
- botList.push({
148
- jid: bot.attrs.jid,
149
- personaId: bot.attrs['persona_id']
150
- });
230
+ const profileNode = (0, WABinary_1.getBinaryNodeChild)(results, 'business_profile');
231
+ const profiles = (0, WABinary_1.getBinaryNodeChild)(profileNode, 'profile');
232
+ if (profiles) {
233
+ const address = (0, WABinary_1.getBinaryNodeChild)(profiles, 'address');
234
+ const description = (0, WABinary_1.getBinaryNodeChild)(profiles, 'description');
235
+ const website = (0, WABinary_1.getBinaryNodeChild)(profiles, 'website');
236
+ const email = (0, WABinary_1.getBinaryNodeChild)(profiles, 'email');
237
+ const category = (0, WABinary_1.getBinaryNodeChild)((0, WABinary_1.getBinaryNodeChild)(profiles, 'categories'), 'category');
238
+ const businessHours = (0, WABinary_1.getBinaryNodeChild)(profiles, 'business_hours');
239
+ const businessHoursConfig = businessHours ?
240
+ (0, WABinary_1.getBinaryNodeChildren)(businessHours, 'business_hours_config') :
241
+ undefined;
242
+ const websiteStr = (_a = website === null || website === void 0 ? void 0 : website.content) === null || _a === void 0 ? void 0 : _a.toString();
243
+ return {
244
+ wid: (_b = profiles.attrs) === null || _b === void 0 ? void 0 : _b.jid,
245
+ address: (_c = address === null || address === void 0 ? void 0 : address.content) === null || _c === void 0 ? void 0 : _c.toString(),
246
+ description: ((_d = description === null || description === void 0 ? void 0 : description.content) === null || _d === void 0 ? void 0 : _d.toString()) || '',
247
+ website: websiteStr ? [websiteStr] : [],
248
+ email: (_e = email === null || email === void 0 ? void 0 : email.content) === null || _e === void 0 ? void 0 : _e.toString(),
249
+ category: (_f = category === null || category === void 0 ? void 0 : category.content) === null || _f === void 0 ? void 0 : _f.toString(),
250
+ 'business_hours': {
251
+ timezone: (_g = businessHours === null || businessHours === void 0 ? void 0 : businessHours.attrs) === null || _g === void 0 ? void 0 : _g.timezone,
252
+ 'business_config': businessHoursConfig === null || businessHoursConfig === void 0 ? void 0 : businessHoursConfig.map(({ attrs }) => attrs)
151
253
  }
152
- }
254
+ };
153
255
  }
154
- return botList;
155
256
  };
156
257
  const onWhatsApp = async (...jids) => {
157
258
  const usyncQuery = new WAUSync_1.USyncQuery()
158
- .withContactProtocol()
159
- .withLIDProtocol();
259
+ .withContactProtocol()
260
+ .withLIDProtocol();
261
+
160
262
  for (const jid of jids) {
161
263
  const phone = `+${jid.replace('+', '').split('@')[0].split(':')[0]}`;
162
264
  usyncQuery.withUser(new WAUSync_1.USyncUser().withPhone(phone));
163
265
  }
266
+
164
267
  const results = await sock.executeUSyncQuery(usyncQuery);
165
268
  if (results) {
166
- return results.list.filter((a) => !!a.contact).map(({ contact, id, lid }) => ({ jid: id, exists: contact, lid }));
167
- }
168
- };
169
- const fetchStatus = async (...jids) => {
170
- const usyncQuery = new WAUSync_1.USyncQuery()
171
- .withStatusProtocol();
172
- for (const jid of jids) {
173
- usyncQuery.withUser(new WAUSync_1.USyncUser().withId(jid));
174
- }
175
- const result = await sock.executeUSyncQuery(usyncQuery);
176
- if (result) {
177
- return result.list;
269
+ const verifiedResults = await Promise.all(
270
+ results.list
271
+ .filter((a) => !!a.contact)
272
+ .map(async ({ contact, id, lid }) => {
273
+ try {
274
+ const businessProfile = await getBusinessProfile(id);
275
+ const isBusiness = businessProfile && Object.keys(businessProfile).length > 0;
276
+ if (isBusiness) {
277
+ const { wid, ...businessInfo } = businessProfile;
278
+
279
+ return {
280
+ jid: id,
281
+ exists: true,
282
+ lid: lid,
283
+ status: 'business',
284
+ businessInfo: businessInfo
285
+ };
286
+ } else {
287
+ return {
288
+ jid: id,
289
+ exists: true,
290
+ lid: lid,
291
+ status: 'regular'
292
+ };
293
+ }
294
+ } catch (error) {
295
+ return {
296
+ jid: id,
297
+ exists: true,
298
+ lid: lid,
299
+ status: error
300
+ };
301
+ }
302
+ })
303
+ );
304
+ return verifiedResults;
178
305
  }
179
306
  };
180
- const fetchDisappearingDuration = async (...jids) => {
181
- const usyncQuery = new WAUSync_1.USyncQuery()
182
- .withDisappearingModeProtocol();
183
- for (const jid of jids) {
184
- usyncQuery.withUser(new WAUSync_1.USyncUser().withId(jid));
185
- }
186
- const result = await sock.executeUSyncQuery(usyncQuery);
307
+ const fetchStatus = async (jid) => {
308
+ const [result] = await interactiveQuery([{ tag: 'user', attrs: { jid } }], { tag: 'status', attrs: {} });
187
309
  if (result) {
188
- return result.list;
310
+ const status = (0, WABinary_1.getBinaryNodeChild)(result, 'status');
311
+ return {
312
+ status: status === null || status === void 0 ? void 0 : status.content.toString(),
313
+ setAt: new Date(+((status === null || status === void 0 ? void 0 : status.attrs.t) || 0) * 1000)
314
+ };
189
315
  }
190
316
  };
191
- const updateProfilePicture = async (jid, content, dimensions) => {
317
+ /** update the profile picture for yourself or a group */
318
+ const updateProfilePicture = async (jid, content) => {
192
319
  let targetJid;
193
320
  if (!jid) {
194
321
  throw new boom_1.Boom('Illegal no-jid profile update. Please specify either your ID or the ID of the chat you wish to update');
195
322
  }
196
323
  if ((0, WABinary_1.jidNormalizedUser)(jid) !== (0, WABinary_1.jidNormalizedUser)(authState.creds.me.id)) {
197
- targetJid = (0, WABinary_1.jidNormalizedUser)(jid);
324
+ targetJid = (0, WABinary_1.jidNormalizedUser)(jid); // in case it is someone other than us
198
325
  }
199
- const { img } = await (0, Utils_1.generateProfilePicture)(content, dimensions);
326
+ const { img } = await (0, Utils_1.generateProfilePicture)(content);
200
327
  await query({
201
328
  tag: 'iq',
202
329
  attrs: {
@@ -214,13 +341,14 @@ const makeChatsSocket = (config) => {
214
341
  ]
215
342
  });
216
343
  };
344
+ /** remove the profile picture for yourself or a group */
217
345
  const removeProfilePicture = async (jid) => {
218
346
  let targetJid;
219
347
  if (!jid) {
220
348
  throw new boom_1.Boom('Illegal no-jid profile update. Please specify either your ID or the ID of the chat you wish to update');
221
349
  }
222
350
  if ((0, WABinary_1.jidNormalizedUser)(jid) !== (0, WABinary_1.jidNormalizedUser)(authState.creds.me.id)) {
223
- targetJid = (0, WABinary_1.jidNormalizedUser)(jid);
351
+ targetJid = (0, WABinary_1.jidNormalizedUser)(jid); // in case it is someone other than us
224
352
  }
225
353
  await query({
226
354
  tag: 'iq',
@@ -232,6 +360,7 @@ const makeChatsSocket = (config) => {
232
360
  }
233
361
  });
234
362
  };
363
+ /** update the profile status for yourself */
235
364
  const updateProfileStatus = async (status) => {
236
365
  await query({
237
366
  tag: 'iq',
@@ -284,51 +413,6 @@ const makeChatsSocket = (config) => {
284
413
  ]
285
414
  });
286
415
  };
287
- const getBusinessProfile = async (jid) => {
288
- var _a, _b, _c, _d, _e, _f, _g;
289
- const results = await query({
290
- tag: 'iq',
291
- attrs: {
292
- to: 's.whatsapp.net',
293
- xmlns: 'w:biz',
294
- type: 'get'
295
- },
296
- content: [{
297
- tag: 'business_profile',
298
- attrs: { v: '244' },
299
- content: [{
300
- tag: 'profile',
301
- attrs: { jid }
302
- }]
303
- }]
304
- });
305
- const profileNode = (0, WABinary_1.getBinaryNodeChild)(results, 'business_profile');
306
- const profiles = (0, WABinary_1.getBinaryNodeChild)(profileNode, 'profile');
307
- if (profiles) {
308
- const address = (0, WABinary_1.getBinaryNodeChild)(profiles, 'address');
309
- const description = (0, WABinary_1.getBinaryNodeChild)(profiles, 'description');
310
- const website = (0, WABinary_1.getBinaryNodeChild)(profiles, 'website');
311
- const email = (0, WABinary_1.getBinaryNodeChild)(profiles, 'email');
312
- const category = (0, WABinary_1.getBinaryNodeChild)((0, WABinary_1.getBinaryNodeChild)(profiles, 'categories'), 'category');
313
- const businessHours = (0, WABinary_1.getBinaryNodeChild)(profiles, 'business_hours');
314
- const businessHoursConfig = businessHours
315
- ? (0, WABinary_1.getBinaryNodeChildren)(businessHours, 'business_hours_config')
316
- : undefined;
317
- const websiteStr = (_a = website === null || website === void 0 ? void 0 : website.content) === null || _a === void 0 ? void 0 : _a.toString();
318
- return {
319
- wid: (_b = profiles.attrs) === null || _b === void 0 ? void 0 : _b.jid,
320
- address: (_c = address === null || address === void 0 ? void 0 : address.content) === null || _c === void 0 ? void 0 : _c.toString(),
321
- description: ((_d = description === null || description === void 0 ? void 0 : description.content) === null || _d === void 0 ? void 0 : _d.toString()) || '',
322
- website: websiteStr ? [websiteStr] : [],
323
- email: (_e = email === null || email === void 0 ? void 0 : email.content) === null || _e === void 0 ? void 0 : _e.toString(),
324
- category: (_f = category === null || category === void 0 ? void 0 : category.content) === null || _f === void 0 ? void 0 : _f.toString(),
325
- 'business_hours': {
326
- timezone: (_g = businessHours === null || businessHours === void 0 ? void 0 : businessHours.attrs) === null || _g === void 0 ? void 0 : _g.timezone,
327
- 'business_config': businessHoursConfig === null || businessHoursConfig === void 0 ? void 0 : businessHoursConfig.map(({ attrs }) => attrs)
328
- }
329
- };
330
- }
331
- };
332
416
  const cleanDirtyBits = async (type, fromTimestamp) => {
333
417
  logger.info({ fromTimestamp }, 'clean dirty bits ' + type);
334
418
  await sendNode({
@@ -358,12 +442,18 @@ const makeChatsSocket = (config) => {
358
442
  };
359
443
  };
360
444
  const resyncAppState = ev.createBufferedFunction(async (collections, isInitialSync) => {
445
+ // we use this to determine which events to fire
446
+ // otherwise when we resync from scratch -- all notifications will fire
361
447
  const initialVersionMap = {};
362
448
  const globalMutationMap = {};
363
449
  await authState.keys.transaction(async () => {
364
450
  var _a;
365
451
  const collectionsToHandle = new Set(collections);
452
+ // in case something goes wrong -- ensure we don't enter a loop that cannot be exited from
366
453
  const attemptsMap = {};
454
+ // keep executing till all collections are done
455
+ // sometimes a single patch request will not return all the patches (God knows why)
456
+ // so we fetch till they're all done (this is determined by the "has_more_patches" flag)
367
457
  while (collectionsToHandle.size) {
368
458
  const states = {};
369
459
  const nodes = [];
@@ -385,6 +475,7 @@ const makeChatsSocket = (config) => {
385
475
  attrs: {
386
476
  name,
387
477
  version: state.version.toString(),
478
+ // return snapshot if being synced from scratch
388
479
  'return_snapshot': (!state.version).toString()
389
480
  }
390
481
  });
@@ -404,6 +495,7 @@ const makeChatsSocket = (config) => {
404
495
  }
405
496
  ]
406
497
  });
498
+ // extract from binary node
407
499
  const decoded = await (0, Utils_1.extractSyncdPatches)(result, config === null || config === void 0 ? void 0 : config.options);
408
500
  for (const key in decoded) {
409
501
  const name = key;
@@ -414,11 +506,16 @@ const makeChatsSocket = (config) => {
414
506
  states[name] = newState;
415
507
  Object.assign(globalMutationMap, mutationMap);
416
508
  logger.info(`restored state of ${name} from snapshot to v${newState.version} with mutations`);
417
- await authState.keys.set({ 'app-state-sync-version': { [name]: newState } });
509
+ await authState.keys.set({ 'app-state-sync-version': {
510
+ [name]: newState
511
+ } });
418
512
  }
513
+ // only process if there are syncd patches
419
514
  if (patches.length) {
420
515
  const { state: newState, mutationMap } = await (0, Utils_1.decodePatches)(name, patches, states[name], getAppStateSyncKey, config.options, initialVersionMap[name], logger, appStateMacVerification.patch);
421
- await authState.keys.set({ 'app-state-sync-version': { [name]: newState } });
516
+ await authState.keys.set({ 'app-state-sync-version': {
517
+ [name]: newState
518
+ } });
422
519
  logger.info(`synced ${name} to v${newState.version}`);
423
520
  initialVersionMap[name] = newState.version;
424
521
  Object.assign(globalMutationMap, mutationMap);
@@ -426,18 +523,24 @@ const makeChatsSocket = (config) => {
426
523
  if (hasMorePatches) {
427
524
  logger.info(`${name} has more patches...`);
428
525
  }
429
- else {
526
+ else { // collection is done with sync
430
527
  collectionsToHandle.delete(name);
431
528
  }
432
529
  }
433
530
  catch (error) {
434
- const isIrrecoverableError = attemptsMap[name] >= MAX_SYNC_ATTEMPTS
435
- || ((_a = error.output) === null || _a === void 0 ? void 0 : _a.statusCode) === 404
436
- || error.name === 'TypeError';
531
+ // if retry attempts overshoot
532
+ // or key not found
533
+ const isIrrecoverableError = attemptsMap[name] >= MAX_SYNC_ATTEMPTS ||
534
+ ((_a = error.output) === null || _a === void 0 ? void 0 : _a.statusCode) === 404 ||
535
+ error.name === 'TypeError';
437
536
  logger.info({ name, error: error.stack }, `failed to sync state from version${isIrrecoverableError ? '' : ', removing and trying from scratch'}`);
438
- await authState.keys.set({ 'app-state-sync-version': { [name]: null } });
537
+ await authState.keys.set({ 'app-state-sync-version': {
538
+ [name]: null
539
+ } });
540
+ // increment number of retries
439
541
  attemptsMap[name] = (attemptsMap[name] || 0) + 1;
440
542
  if (isIrrecoverableError) {
543
+ // stop retrying
441
544
  collectionsToHandle.delete(name);
442
545
  }
443
546
  }
@@ -449,56 +552,28 @@ const makeChatsSocket = (config) => {
449
552
  onMutation(globalMutationMap[key]);
450
553
  }
451
554
  });
555
+ /**
556
+ * fetch the profile picture of a user/group
557
+ * type = "preview" for a low res picture
558
+ * type = "image for the high res picture"
559
+ */
452
560
  const profilePictureUrl = async (jid, type = 'preview', timeoutMs) => {
453
561
  var _a;
454
562
  jid = (0, WABinary_1.jidNormalizedUser)(jid);
455
- try {
456
- const result = await query({
457
- tag: 'iq',
458
- attrs: {
459
- target: jid,
460
- to: WABinary_1.S_WHATSAPP_NET,
461
- type: 'get',
462
- xmlns: 'w:profile:picture'
463
- },
464
- content: [
465
- { tag: 'picture', attrs: { type, query: 'url' } }
466
- ]
467
- }, timeoutMs);
468
- const child = (0, WABinary_1.getBinaryNodeChild)(result, 'picture');
469
- return (_a = child === null || child === void 0 ? void 0 : child.attrs) === null || _a === void 0 ? void 0 : _a.url;
470
- } catch (error) {
471
- if (error.message?.includes('item-not-found') ||
472
- error.output?.payload?.statusCode === 404 ||
473
- error.statusCode === 404) {
474
- logger.info(chalk.gray(`[INFO] Profile pic not found for ${jid}, using fallback`));
475
- return {
476
- eurl: undefined,
477
- id: jid.split('@')[0],
478
- status: null,
479
- img: null
480
- };
481
- }
482
- throw error;
483
- }
484
- };
485
- const createCallLink = async (type, event, timeoutMs) => {
486
563
  const result = await query({
487
- tag: 'call',
564
+ tag: 'iq',
488
565
  attrs: {
489
- id: generateMessageTag(),
490
- to: '@call'
566
+ target: jid,
567
+ to: WABinary_1.S_WHATSAPP_NET,
568
+ type: 'get',
569
+ xmlns: 'w:profile:picture'
491
570
  },
492
571
  content: [
493
- {
494
- tag: 'link_create',
495
- attrs: { media: type },
496
- content: event ? [{ tag: 'event', attrs: { start_time: String(event.startTime) } }] : undefined
497
- }
572
+ { tag: 'picture', attrs: { type, query: 'url' } }
498
573
  ]
499
574
  }, timeoutMs);
500
- const child = (0, WABinary_1.getBinaryNodeChild)(result, 'link_create');
501
- return child?.attrs?.token;
575
+ const child = (0, WABinary_1.getBinaryNodeChild)(result, 'picture');
576
+ return (_a = child === null || child === void 0 ? void 0 : child.attrs) === null || _a === void 0 ? void 0 : _a.url;
502
577
  };
503
578
  const sendPresenceUpdate = async (type, toJid) => {
504
579
  const me = authState.creds.me;
@@ -511,7 +586,7 @@ const makeChatsSocket = (config) => {
511
586
  await sendNode({
512
587
  tag: 'presence',
513
588
  attrs: {
514
- name: me.name.replace(/@/g, ''),
589
+ name: me.name,
515
590
  type
516
591
  }
517
592
  });
@@ -534,6 +609,10 @@ const makeChatsSocket = (config) => {
534
609
  });
535
610
  }
536
611
  };
612
+ /**
613
+ * @param toJid the jid to subscribe to
614
+ * @param tcToken token for subscription, use if present
615
+ */
537
616
  const presenceSubscribe = (toJid, tcToken) => (sendNode({
538
617
  tag: 'presence',
539
618
  attrs: {
@@ -541,22 +620,22 @@ const makeChatsSocket = (config) => {
541
620
  id: generateMessageTag(),
542
621
  type: 'subscribe'
543
622
  },
544
- content: tcToken
545
- ? [
623
+ content: tcToken ?
624
+ [
546
625
  {
547
626
  tag: 'tctoken',
548
627
  attrs: {},
549
628
  content: tcToken
550
629
  }
551
- ]
552
- : undefined
630
+ ] :
631
+ undefined
553
632
  }));
554
633
  const handlePresenceUpdate = ({ tag, attrs, content }) => {
555
634
  var _a;
556
635
  let presence;
557
636
  const jid = attrs.from;
558
637
  const participant = attrs.participant || attrs.from;
559
- if (shouldIgnoreJid(jid) && jid != '@s.whatsapp.net') {
638
+ if (shouldIgnoreJid(jid) && jid !== '@s.whatsapp.net') {
560
639
  return;
561
640
  }
562
641
  if (tag === 'presence') {
@@ -580,7 +659,9 @@ const makeChatsSocket = (config) => {
580
659
  logger.error({ tag, attrs, content }, 'recv invalid presence node');
581
660
  }
582
661
  if (presence) {
583
- ev.emit('presence.update', { id: jid, presences: { [participant]: presence } });
662
+ ev.emit('presence.update', { id: jid, presences: {
663
+ [participant]: presence
664
+ } });
584
665
  }
585
666
  };
586
667
  const appPatch = async (patchCreate) => {
@@ -631,7 +712,9 @@ const makeChatsSocket = (config) => {
631
712
  ]
632
713
  };
633
714
  await query(node);
634
- await authState.keys.set({ 'app-state-sync-version': { [name]: state } });
715
+ await authState.keys.set({ 'app-state-sync-version': {
716
+ [name]: state
717
+ } });
635
718
  });
636
719
  });
637
720
  if (config.emitOwnEvents) {
@@ -642,8 +725,9 @@ const makeChatsSocket = (config) => {
642
725
  }
643
726
  }
644
727
  };
728
+ /** sending non-abt props may fix QR scan fail if server expects */
645
729
  const fetchProps = async () => {
646
- var _a, _b, _c;
730
+ var _a, _b;
647
731
  const resultNode = await query({
648
732
  tag: 'iq',
649
733
  attrs: {
@@ -652,28 +736,37 @@ const makeChatsSocket = (config) => {
652
736
  type: 'get',
653
737
  },
654
738
  content: [
655
- { tag: 'props', attrs: {
739
+ {
740
+ tag: 'props',
741
+ attrs: {
656
742
  protocol: '2',
657
743
  hash: ((_a = authState === null || authState === void 0 ? void 0 : authState.creds) === null || _a === void 0 ? void 0 : _a.lastPropHash) || ''
658
- } }
744
+ }
745
+ }
659
746
  ]
660
747
  });
661
748
  const propsNode = (0, WABinary_1.getBinaryNodeChild)(resultNode, 'props');
662
749
  let props = {};
663
750
  if (propsNode) {
664
- if ((_b = propsNode.attrs) === null || _b === void 0 ? void 0 : _b.hash) {
665
- authState.creds.lastPropHash = (_c = propsNode === null || propsNode === void 0 ? void 0 : propsNode.attrs) === null || _c === void 0 ? void 0 : _c.hash;
666
- ev.emit('creds.update', authState.creds);
667
- }
751
+ authState.creds.lastPropHash = (_b = propsNode === null || propsNode === void 0 ? void 0 : propsNode.attrs) === null || _b === void 0 ? void 0 : _b.hash;
752
+ ev.emit('creds.update', authState.creds);
668
753
  props = (0, WABinary_1.reduceBinaryNodeToDictionary)(propsNode, 'prop');
669
754
  }
670
755
  logger.debug('fetched props');
671
756
  return props;
672
757
  };
758
+ /**
759
+ * modify a chat -- mark unread, read etc.
760
+ * lastMessages must be sorted in reverse chronologically
761
+ * requires the last messages till the last message received; required for archive & unread
762
+ */
673
763
  const chatModify = (mod, jid) => {
674
764
  const patch = (0, Utils_1.chatModificationToAppPatch)(mod, jid);
675
765
  return appPatch(patch);
676
766
  };
767
+ /**
768
+ * Star or Unstar a message
769
+ */
677
770
  const star = (jid, messages, star) => {
678
771
  return chatModify({
679
772
  star: {
@@ -682,15 +775,9 @@ const makeChatsSocket = (config) => {
682
775
  }
683
776
  }, jid);
684
777
  };
685
- const addOrEditContact = (jid, contact) => {
686
- return chatModify({ contact }, jid);
687
- };
688
- const removeContact = (jid) => {
689
- return chatModify({ contact: null }, jid);
690
- };
691
- const addLabel = (jid, labels) => {
692
- return chatModify({ addLabel: { ...labels } }, jid);
693
- };
778
+ /**
779
+ * Adds label for the chats
780
+ */
694
781
  const addChatLabel = (jid, labelId) => {
695
782
  return chatModify({
696
783
  addChatLabel: {
@@ -698,6 +785,9 @@ const makeChatsSocket = (config) => {
698
785
  }
699
786
  }, jid);
700
787
  };
788
+ /**
789
+ * Removes label for the chat
790
+ */
701
791
  const removeChatLabel = (jid, labelId) => {
702
792
  return chatModify({
703
793
  removeChatLabel: {
@@ -705,6 +795,9 @@ const makeChatsSocket = (config) => {
705
795
  }
706
796
  }, jid);
707
797
  };
798
+ /**
799
+ * Adds label for the message
800
+ */
708
801
  const addMessageLabel = (jid, messageId, labelId) => {
709
802
  return chatModify({
710
803
  addMessageLabel: {
@@ -713,6 +806,9 @@ const makeChatsSocket = (config) => {
713
806
  }
714
807
  }, jid);
715
808
  };
809
+ /**
810
+ * Removes label for the message
811
+ */
716
812
  const removeMessageLabel = (jid, messageId, labelId) => {
717
813
  return chatModify({
718
814
  removeMessageLabel: {
@@ -721,6 +817,10 @@ const makeChatsSocket = (config) => {
721
817
  }
722
818
  }, jid);
723
819
  };
820
+ /**
821
+ * queries need to be fired on connection open
822
+ * help ensure parity with WA Web
823
+ * */
724
824
  const executeInitQueries = async () => {
725
825
  await Promise.all([
726
826
  fetchProps(),
@@ -737,56 +837,30 @@ const makeChatsSocket = (config) => {
737
837
  if (!msg.key.fromMe) {
738
838
  ev.emit('contacts.update', [{ id: jid, notify: msg.pushName, verifiedName: msg.verifiedBizName }]);
739
839
  }
840
+ // update our pushname too
740
841
  if (msg.key.fromMe && msg.pushName && ((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.name) !== msg.pushName) {
741
842
  ev.emit('creds.update', { me: { ...authState.creds.me, name: msg.pushName } });
742
843
  }
743
844
  }
744
845
  const historyMsg = (0, Utils_1.getHistoryMsg)(msg.message);
745
- const shouldProcessHistoryMsg = historyMsg
746
- ? (shouldSyncHistoryMessage(historyMsg)
747
- && Defaults_1.PROCESSABLE_HISTORY_TYPES.includes(historyMsg.syncType))
748
- : false;
749
- if (historyMsg && syncState === SyncState.AwaitingInitialSync) {
750
- if (awaitingSyncTimeout) {
751
- clearTimeout(awaitingSyncTimeout);
752
- awaitingSyncTimeout = undefined;
753
- }
754
- if (shouldProcessHistoryMsg) {
755
- syncState = SyncState.Syncing;
756
- logger.info('Transitioned to Syncing state');
757
- } else {
758
- syncState = SyncState.Online;
759
- logger.info('History sync skipped, transitioning to Online state and flushing buffer');
760
- ev.flush();
761
- }
762
- }
763
- const doAppStateSync = async () => {
764
- if (syncState === SyncState.Syncing) {
765
- logger.info('Doing app state sync');
766
- await resyncAppState(Types_1.ALL_WA_PATCH_NAMES, true);
767
- syncState = SyncState.Online;
768
- logger.info('App state sync complete, transitioning to Online state and flushing buffer');
769
- ev.flush();
770
- const accountSyncCounter = (authState.creds.accountSyncCounter || 0) + 1;
771
- ev.emit('creds.update', { accountSyncCounter });
772
- }
773
- };
846
+ const shouldProcessHistoryMsg = historyMsg ?
847
+ (shouldSyncHistoryMessage(historyMsg) &&
848
+ Defaults_1.PROCESSABLE_HISTORY_TYPES.includes(historyMsg.syncType)) :
849
+ false;
774
850
  if (historyMsg && !authState.creds.myAppStateKeyId) {
775
851
  logger.warn('skipping app state sync, as myAppStateKeyId is not set');
776
852
  pendingAppStateSync = true;
777
853
  }
778
854
  await Promise.all([
779
855
  (async () => {
780
- if (historyMsg
781
- && authState.creds.myAppStateKeyId) {
856
+ if (historyMsg &&
857
+ authState.creds.myAppStateKeyId) {
782
858
  pendingAppStateSync = false;
783
859
  await doAppStateSync();
784
860
  }
785
861
  })(),
786
862
  (0, process_message_1.default)(msg, {
787
- signalRepository,
788
863
  shouldProcessHistoryMsg,
789
- placeholderResendCache,
790
864
  ev,
791
865
  creds: authState.creds,
792
866
  keyStore: authState.keys,
@@ -795,11 +869,23 @@ const makeChatsSocket = (config) => {
795
869
  getMessage: config.getMessage,
796
870
  })
797
871
  ]);
798
- if (((_c = (_b = msg.message) === null || _b === void 0 ? void 0 : _b.protocolMessage) === null || _c === void 0 ? void 0 : _c.appStateSyncKeyShare)
799
- && pendingAppStateSync) {
872
+ if (((_c = (_b = msg.message) === null || _b === void 0 ? void 0 : _b.protocolMessage) === null || _c === void 0 ? void 0 : _c.appStateSyncKeyShare) &&
873
+ pendingAppStateSync) {
800
874
  await doAppStateSync();
801
875
  pendingAppStateSync = false;
802
876
  }
877
+ async function doAppStateSync() {
878
+ if (!authState.creds.accountSyncCounter) {
879
+ logger.info('doing initial app state sync');
880
+ await resyncAppState(Types_1.ALL_WA_PATCH_NAMES, true);
881
+ const accountSyncCounter = (authState.creds.accountSyncCounter || 0) + 1;
882
+ ev.emit('creds.update', { accountSyncCounter });
883
+ if (needToFlushWithAppStateSync) {
884
+ logger.debug('flushing with app state sync');
885
+ ev.flush();
886
+ }
887
+ }
888
+ }
803
889
  });
804
890
  ws.on('CB:presence', handlePresenceUpdate);
805
891
  ws.on('CB:chatstate', handlePresenceUpdate);
@@ -818,6 +904,7 @@ const makeChatsSocket = (config) => {
818
904
  }
819
905
  break;
820
906
  case 'groups':
907
+ // handled in groups.ts
821
908
  break;
822
909
  default:
823
910
  logger.info({ node }, 'received unknown sync');
@@ -834,44 +921,18 @@ const makeChatsSocket = (config) => {
834
921
  sendPresenceUpdate(markOnlineOnConnect ? 'available' : 'unavailable')
835
922
  .catch(error => onUnexpectedError(error, 'presence update requests'));
836
923
  }
837
- if (receivedPendingNotifications &&
838
- !((_a = authState.creds) === null || _a === void 0 ? void 0 : _a.myAppStateKeyId)) {
839
- ev.buffer();
840
- needToFlushWithAppStateSync = true;
841
- }
842
- if (!receivedPendingNotifications || syncState !== SyncState.Connecting) {
843
- return;
844
- }
845
- syncState = SyncState.AwaitingInitialSync;
846
- logger.info('Connection is now AwaitingInitialSync, buffering events');
847
- ev.buffer();
848
- const willSyncHistory = shouldSyncHistoryMessage(
849
- WAProto_1.proto.Message.HistorySyncNotification.create({
850
- syncType: WAProto_1.proto.HistorySync.HistorySyncType.RECENT
851
- })
852
- );
853
- if (!willSyncHistory) {
854
- logger.info('History sync is disabled by config, not waiting for notification. Transitioning to Online.');
855
- syncState = SyncState.Online;
856
- setTimeout(() => ev.flush(), 0);
857
- return;
858
- }
859
- logger.info('History sync is enabled, awaiting notification with a 20s timeout.');
860
- if (awaitingSyncTimeout) {
861
- clearTimeout(awaitingSyncTimeout);
862
- }
863
- awaitingSyncTimeout = setTimeout(() => {
864
- if (syncState === SyncState.AwaitingInitialSync) {
865
- logger.warn('Timeout in AwaitingInitialSync, forcing state to Online and flushing buffer');
866
- syncState = SyncState.Online;
867
- ev.flush();
924
+ if (receivedPendingNotifications) {
925
+ // if we don't have the app state key
926
+ // we keep buffering events until we finally have
927
+ // the key and can sync the messages
928
+ if (!((_a = authState.creds) === null || _a === void 0 ? void 0 : _a.myAppStateKeyId) && !config.mobile) {
929
+ ev.buffer();
930
+ needToFlushWithAppStateSync = true;
868
931
  }
869
- }, 20000);
932
+ }
870
933
  });
871
934
  return {
872
935
  ...sock,
873
- createCallLink,
874
- getBotListV2,
875
936
  processingMutex,
876
937
  fetchPrivacySettings,
877
938
  upsertMessage,
@@ -881,16 +942,12 @@ const makeChatsSocket = (config) => {
881
942
  profilePictureUrl,
882
943
  onWhatsApp,
883
944
  fetchBlocklist,
884
- fetchDisappearingDuration,
885
945
  fetchStatus,
886
946
  updateProfilePicture,
887
947
  removeProfilePicture,
888
948
  updateProfileStatus,
889
949
  updateProfileName,
890
950
  updateBlockStatus,
891
- updateDisableLinkPreviewsPrivacy,
892
- updateCallPrivacy,
893
- updateMessagesPrivacy,
894
951
  updateLastSeenPrivacy,
895
952
  updateOnlinePrivacy,
896
953
  updateProfilePicturePrivacy,
@@ -902,14 +959,12 @@ const makeChatsSocket = (config) => {
902
959
  resyncAppState,
903
960
  chatModify,
904
961
  cleanDirtyBits,
905
- addOrEditContact,
906
- removeContact,
907
- addLabel,
908
962
  addChatLabel,
909
963
  removeChatLabel,
910
964
  addMessageLabel,
965
+ checkStatusWA,
911
966
  removeMessageLabel,
912
967
  star
913
968
  };
914
969
  };
915
- exports.makeChatsSocket = makeChatsSocket;
970
+ exports.makeChatsSocket = makeChatsSocket;