cuki-bailx 1.2.6 → 2.0.8

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.
@@ -15,31 +15,24 @@ const process_message_1 = __importDefault(require("../Utils/process-message"));
15
15
  const WABinary_1 = require("../WABinary");
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
28
  const placeholderResendCache = config.placeholderResendCache || new node_cache_1.default({
37
- stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY,
29
+ stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
38
30
  useClones: false
39
31
  });
40
32
  if (!config.placeholderResendCache) {
41
33
  config.placeholderResendCache = placeholderResendCache;
42
34
  }
35
+ /** helper function to fetch the given app state sync key */
43
36
  const getAppStateSyncKey = async (keyId) => {
44
37
  const { [keyId]: key } = await authState.keys.get('app-state-sync-key', [keyId]);
45
38
  return key;
@@ -61,6 +54,7 @@ const makeChatsSocket = (config) => {
61
54
  }
62
55
  return privacySettings;
63
56
  };
57
+ /** helper function to run a privacy IQ query */
64
58
  const privacyQuery = async (name, value) => {
65
59
  await query({
66
60
  tag: 'iq',
@@ -105,9 +99,6 @@ const makeChatsSocket = (config) => {
105
99
  const updateGroupsAddPrivacy = async (value) => {
106
100
  await privacyQuery('groupadd', value);
107
101
  };
108
- const updateDisableLinkPreviewsPrivacy = async (isPreviewsDisabled) => {
109
- return chatModify({ disableLinkPreviews: { isPreviewsDisabled } }, '');
110
- };
111
102
  const updateDefaultDisappearingMode = async (duration) => {
112
103
  await query({
113
104
  tag: 'iq',
@@ -188,15 +179,16 @@ const makeChatsSocket = (config) => {
188
179
  return result.list;
189
180
  }
190
181
  };
191
- const updateProfilePicture = async (jid, content, dimensions) => {
182
+ /** update the profile picture for yourself or a group */
183
+ const updateProfilePicture = async (jid, content) => {
192
184
  let targetJid;
193
185
  if (!jid) {
194
186
  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
187
  }
196
188
  if ((0, WABinary_1.jidNormalizedUser)(jid) !== (0, WABinary_1.jidNormalizedUser)(authState.creds.me.id)) {
197
- targetJid = (0, WABinary_1.jidNormalizedUser)(jid);
189
+ targetJid = (0, WABinary_1.jidNormalizedUser)(jid); // in case it is someone other than us
198
190
  }
199
- const { img } = await (0, Utils_1.generateProfilePicture)(content, dimensions);
191
+ const { img } = await (0, Utils_1.generateProfilePicture)(content);
200
192
  await query({
201
193
  tag: 'iq',
202
194
  attrs: {
@@ -214,13 +206,14 @@ const makeChatsSocket = (config) => {
214
206
  ]
215
207
  });
216
208
  };
209
+ /** remove the profile picture for yourself or a group */
217
210
  const removeProfilePicture = async (jid) => {
218
211
  let targetJid;
219
212
  if (!jid) {
220
213
  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
214
  }
222
215
  if ((0, WABinary_1.jidNormalizedUser)(jid) !== (0, WABinary_1.jidNormalizedUser)(authState.creds.me.id)) {
223
- targetJid = (0, WABinary_1.jidNormalizedUser)(jid);
216
+ targetJid = (0, WABinary_1.jidNormalizedUser)(jid); // in case it is someone other than us
224
217
  }
225
218
  await query({
226
219
  tag: 'iq',
@@ -232,6 +225,7 @@ const makeChatsSocket = (config) => {
232
225
  }
233
226
  });
234
227
  };
228
+ /** update the profile status for yourself */
235
229
  const updateProfileStatus = async (status) => {
236
230
  await query({
237
231
  tag: 'iq',
@@ -358,12 +352,18 @@ const makeChatsSocket = (config) => {
358
352
  };
359
353
  };
360
354
  const resyncAppState = ev.createBufferedFunction(async (collections, isInitialSync) => {
355
+ // we use this to determine which events to fire
356
+ // otherwise when we resync from scratch -- all notifications will fire
361
357
  const initialVersionMap = {};
362
358
  const globalMutationMap = {};
363
359
  await authState.keys.transaction(async () => {
364
360
  var _a;
365
361
  const collectionsToHandle = new Set(collections);
362
+ // in case something goes wrong -- ensure we don't enter a loop that cannot be exited from
366
363
  const attemptsMap = {};
364
+ // keep executing till all collections are done
365
+ // sometimes a single patch request will not return all the patches (God knows why)
366
+ // so we fetch till they're all done (this is determined by the "has_more_patches" flag)
367
367
  while (collectionsToHandle.size) {
368
368
  const states = {};
369
369
  const nodes = [];
@@ -385,6 +385,7 @@ const makeChatsSocket = (config) => {
385
385
  attrs: {
386
386
  name,
387
387
  version: state.version.toString(),
388
+ // return snapshot if being synced from scratch
388
389
  'return_snapshot': (!state.version).toString()
389
390
  }
390
391
  });
@@ -404,6 +405,7 @@ const makeChatsSocket = (config) => {
404
405
  }
405
406
  ]
406
407
  });
408
+ // extract from binary node
407
409
  const decoded = await (0, Utils_1.extractSyncdPatches)(result, config === null || config === void 0 ? void 0 : config.options);
408
410
  for (const key in decoded) {
409
411
  const name = key;
@@ -416,6 +418,7 @@ const makeChatsSocket = (config) => {
416
418
  logger.info(`restored state of ${name} from snapshot to v${newState.version} with mutations`);
417
419
  await authState.keys.set({ 'app-state-sync-version': { [name]: newState } });
418
420
  }
421
+ // only process if there are syncd patches
419
422
  if (patches.length) {
420
423
  const { state: newState, mutationMap } = await (0, Utils_1.decodePatches)(name, patches, states[name], getAppStateSyncKey, config.options, initialVersionMap[name], logger, appStateMacVerification.patch);
421
424
  await authState.keys.set({ 'app-state-sync-version': { [name]: newState } });
@@ -426,18 +429,22 @@ const makeChatsSocket = (config) => {
426
429
  if (hasMorePatches) {
427
430
  logger.info(`${name} has more patches...`);
428
431
  }
429
- else {
432
+ else { // collection is done with sync
430
433
  collectionsToHandle.delete(name);
431
434
  }
432
435
  }
433
436
  catch (error) {
437
+ // if retry attempts overshoot
438
+ // or key not found
434
439
  const isIrrecoverableError = attemptsMap[name] >= MAX_SYNC_ATTEMPTS
435
440
  || ((_a = error.output) === null || _a === void 0 ? void 0 : _a.statusCode) === 404
436
441
  || error.name === 'TypeError';
437
442
  logger.info({ name, error: error.stack }, `failed to sync state from version${isIrrecoverableError ? '' : ', removing and trying from scratch'}`);
438
443
  await authState.keys.set({ 'app-state-sync-version': { [name]: null } });
444
+ // increment number of retries
439
445
  attemptsMap[name] = (attemptsMap[name] || 0) + 1;
440
446
  if (isIrrecoverableError) {
447
+ // stop retrying
441
448
  collectionsToHandle.delete(name);
442
449
  }
443
450
  }
@@ -449,56 +456,28 @@ const makeChatsSocket = (config) => {
449
456
  onMutation(globalMutationMap[key]);
450
457
  }
451
458
  });
459
+ /**
460
+ * fetch the profile picture of a user/group
461
+ * type = "preview" for a low res picture
462
+ * type = "image for the high res picture"
463
+ */
452
464
  const profilePictureUrl = async (jid, type = 'preview', timeoutMs) => {
453
465
  var _a;
454
466
  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
467
  const result = await query({
487
- tag: 'call',
468
+ tag: 'iq',
488
469
  attrs: {
489
- id: generateMessageTag(),
490
- to: '@call'
470
+ target: jid,
471
+ to: WABinary_1.S_WHATSAPP_NET,
472
+ type: 'get',
473
+ xmlns: 'w:profile:picture'
491
474
  },
492
475
  content: [
493
- {
494
- tag: 'link_create',
495
- attrs: { media: type },
496
- content: event ? [{ tag: 'event', attrs: { start_time: String(event.startTime) } }] : undefined
497
- }
476
+ { tag: 'picture', attrs: { type, query: 'url' } }
498
477
  ]
499
478
  }, timeoutMs);
500
- const child = (0, WABinary_1.getBinaryNodeChild)(result, 'link_create');
501
- return child?.attrs?.token;
479
+ const child = (0, WABinary_1.getBinaryNodeChild)(result, 'picture');
480
+ return (_a = child === null || child === void 0 ? void 0 : child.attrs) === null || _a === void 0 ? void 0 : _a.url;
502
481
  };
503
482
  const sendPresenceUpdate = async (type, toJid) => {
504
483
  const me = authState.creds.me;
@@ -534,6 +513,10 @@ const makeChatsSocket = (config) => {
534
513
  });
535
514
  }
536
515
  };
516
+ /**
517
+ * @param toJid the jid to subscribe to
518
+ * @param tcToken token for subscription, use if present
519
+ */
537
520
  const presenceSubscribe = (toJid, tcToken) => (sendNode({
538
521
  tag: 'presence',
539
522
  attrs: {
@@ -642,6 +625,7 @@ const makeChatsSocket = (config) => {
642
625
  }
643
626
  }
644
627
  };
628
+ /** sending non-abt props may fix QR scan fail if server expects */
645
629
  const fetchProps = async () => {
646
630
  var _a, _b, _c;
647
631
  const resultNode = await query({
@@ -661,7 +645,7 @@ const makeChatsSocket = (config) => {
661
645
  const propsNode = (0, WABinary_1.getBinaryNodeChild)(resultNode, 'props');
662
646
  let props = {};
663
647
  if (propsNode) {
664
- if ((_b = propsNode.attrs) === null || _b === void 0 ? void 0 : _b.hash) {
648
+ if ((_b = propsNode.attrs) === null || _b === void 0 ? void 0 : _b.hash) { // on some clients, the hash is returning as undefined
665
649
  authState.creds.lastPropHash = (_c = propsNode === null || propsNode === void 0 ? void 0 : propsNode.attrs) === null || _c === void 0 ? void 0 : _c.hash;
666
650
  ev.emit('creds.update', authState.creds);
667
651
  }
@@ -670,10 +654,18 @@ const makeChatsSocket = (config) => {
670
654
  logger.debug('fetched props');
671
655
  return props;
672
656
  };
657
+ /**
658
+ * modify a chat -- mark unread, read etc.
659
+ * lastMessages must be sorted in reverse chronologically
660
+ * requires the last messages till the last message received; required for archive & unread
661
+ */
673
662
  const chatModify = (mod, jid) => {
674
663
  const patch = (0, Utils_1.chatModificationToAppPatch)(mod, jid);
675
664
  return appPatch(patch);
676
665
  };
666
+ /**
667
+ * Star or Unstar a message
668
+ */
677
669
  const star = (jid, messages, star) => {
678
670
  return chatModify({
679
671
  star: {
@@ -682,15 +674,9 @@ const makeChatsSocket = (config) => {
682
674
  }
683
675
  }, jid);
684
676
  };
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
- };
677
+ /**
678
+ * Adds label for the chats
679
+ */
694
680
  const addChatLabel = (jid, labelId) => {
695
681
  return chatModify({
696
682
  addChatLabel: {
@@ -698,6 +684,9 @@ const makeChatsSocket = (config) => {
698
684
  }
699
685
  }, jid);
700
686
  };
687
+ /**
688
+ * Removes label for the chat
689
+ */
701
690
  const removeChatLabel = (jid, labelId) => {
702
691
  return chatModify({
703
692
  removeChatLabel: {
@@ -705,6 +694,9 @@ const makeChatsSocket = (config) => {
705
694
  }
706
695
  }, jid);
707
696
  };
697
+ /**
698
+ * Adds label for the message
699
+ */
708
700
  const addMessageLabel = (jid, messageId, labelId) => {
709
701
  return chatModify({
710
702
  addMessageLabel: {
@@ -713,6 +705,9 @@ const makeChatsSocket = (config) => {
713
705
  }
714
706
  }, jid);
715
707
  };
708
+ /**
709
+ * Removes label for the message
710
+ */
716
711
  const removeMessageLabel = (jid, messageId, labelId) => {
717
712
  return chatModify({
718
713
  removeMessageLabel: {
@@ -721,6 +716,10 @@ const makeChatsSocket = (config) => {
721
716
  }
722
717
  }, jid);
723
718
  };
719
+ /**
720
+ * queries need to be fired on connection open
721
+ * help ensure parity with WA Web
722
+ * */
724
723
  const executeInitQueries = async () => {
725
724
  await Promise.all([
726
725
  fetchProps(),
@@ -737,6 +736,7 @@ const makeChatsSocket = (config) => {
737
736
  if (!msg.key.fromMe) {
738
737
  ev.emit('contacts.update', [{ id: jid, notify: msg.pushName, verifiedName: msg.verifiedBizName }]);
739
738
  }
739
+ // update our pushname too
740
740
  if (msg.key.fromMe && msg.pushName && ((_a = authState.creds.me) === null || _a === void 0 ? void 0 : _a.name) !== msg.pushName) {
741
741
  ev.emit('creds.update', { me: { ...authState.creds.me, name: msg.pushName } });
742
742
  }
@@ -746,31 +746,6 @@ const makeChatsSocket = (config) => {
746
746
  ? (shouldSyncHistoryMessage(historyMsg)
747
747
  && Defaults_1.PROCESSABLE_HISTORY_TYPES.includes(historyMsg.syncType))
748
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
- };
774
749
  if (historyMsg && !authState.creds.myAppStateKeyId) {
775
750
  logger.warn('skipping app state sync, as myAppStateKeyId is not set');
776
751
  pendingAppStateSync = true;
@@ -784,7 +759,6 @@ const makeChatsSocket = (config) => {
784
759
  }
785
760
  })(),
786
761
  (0, process_message_1.default)(msg, {
787
- signalRepository,
788
762
  shouldProcessHistoryMsg,
789
763
  placeholderResendCache,
790
764
  ev,
@@ -800,6 +774,18 @@ const makeChatsSocket = (config) => {
800
774
  await doAppStateSync();
801
775
  pendingAppStateSync = false;
802
776
  }
777
+ async function doAppStateSync() {
778
+ if (!authState.creds.accountSyncCounter) {
779
+ logger.info('doing initial app state sync');
780
+ await resyncAppState(Types_1.ALL_WA_PATCH_NAMES, true);
781
+ const accountSyncCounter = (authState.creds.accountSyncCounter || 0) + 1;
782
+ ev.emit('creds.update', { accountSyncCounter });
783
+ if (needToFlushWithAppStateSync) {
784
+ logger.debug('flushing with app state sync');
785
+ ev.flush();
786
+ }
787
+ }
788
+ }
803
789
  });
804
790
  ws.on('CB:presence', handlePresenceUpdate);
805
791
  ws.on('CB:chatstate', handlePresenceUpdate);
@@ -818,6 +804,7 @@ const makeChatsSocket = (config) => {
818
804
  }
819
805
  break;
820
806
  case 'groups':
807
+ // handled in groups.ts
821
808
  break;
822
809
  default:
823
810
  logger.info({ node }, 'received unknown sync');
@@ -834,43 +821,16 @@ const makeChatsSocket = (config) => {
834
821
  sendPresenceUpdate(markOnlineOnConnect ? 'available' : 'unavailable')
835
822
  .catch(error => onUnexpectedError(error, 'presence update requests'));
836
823
  }
837
- if (receivedPendingNotifications &&
824
+ if (receivedPendingNotifications && // if we don't have the app state key
825
+ // we keep buffering events until we finally have
826
+ // the key and can sync the messages
838
827
  !((_a = authState.creds) === null || _a === void 0 ? void 0 : _a.myAppStateKeyId)) {
839
828
  ev.buffer();
840
829
  needToFlushWithAppStateSync = true;
841
830
  }
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();
868
- }
869
- }, 20000);
870
831
  });
871
832
  return {
872
833
  ...sock,
873
- createCallLink,
874
834
  getBotListV2,
875
835
  processingMutex,
876
836
  fetchPrivacySettings,
@@ -888,7 +848,6 @@ const makeChatsSocket = (config) => {
888
848
  updateProfileStatus,
889
849
  updateProfileName,
890
850
  updateBlockStatus,
891
- updateDisableLinkPreviewsPrivacy,
892
851
  updateCallPrivacy,
893
852
  updateMessagesPrivacy,
894
853
  updateLastSeenPrivacy,
@@ -902,9 +861,6 @@ const makeChatsSocket = (config) => {
902
861
  resyncAppState,
903
862
  chatModify,
904
863
  cleanDirtyBits,
905
- addOrEditContact,
906
- removeContact,
907
- addLabel,
908
864
  addChatLabel,
909
865
  removeChatLabel,
910
866
  addMessageLabel,
@@ -912,4 +868,4 @@ const makeChatsSocket = (config) => {
912
868
  star
913
869
  };
914
870
  };
915
- exports.makeChatsSocket = makeChatsSocket;
871
+ exports.makeChatsSocket = makeChatsSocket;
@@ -332,7 +332,7 @@ const makeMessagesRecvSocket = (config) => {
332
332
  break;
333
333
  break;
334
334
  default:
335
- // console.log("VYZENBAIL-DEBUG:", JSON.stringify({ ...child, content: Buffer.isBuffer(child.content) ? child.content.toString() : child.content, participant }, null, 2))
335
+ // console.log("BAILEYS-DEBUG:", JSON.stringify({ ...child, content: Buffer.isBuffer(child.content) ? child.content.toString() : child.content, participant }, null, 2))
336
336
  }
337
337
  };
338
338
  const handleNewsletterNotification = (id, node) => {