whatsapp-web.js 1.21.0 → 1.21.1-alpha.1

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.
package/example.js CHANGED
@@ -140,6 +140,12 @@ client.on('message', async msg => {
140
140
  const attachmentData = await quotedMsg.downloadMedia();
141
141
  client.sendMessage(msg.from, attachmentData, { caption: 'Here\'s your requested media.' });
142
142
  }
143
+ } else if (msg.body === '!isviewonce' && msg.hasQuotedMsg) {
144
+ const quotedMsg = await msg.getQuotedMessage();
145
+ if (quotedMsg.hasMedia) {
146
+ const media = await quotedMsg.downloadMedia();
147
+ await client.sendMessage(msg.from, media, { isViewOnce: true });
148
+ }
143
149
  } else if (msg.body === '!location') {
144
150
  msg.reply(new Location(37.422, -122.084, 'Googleplex\nGoogle Headquarters'));
145
151
  } else if (msg.location) {
@@ -201,6 +207,27 @@ client.on('message', async msg => {
201
207
  client.sendMessage(msg.from, list);
202
208
  } else if (msg.body === '!reaction') {
203
209
  msg.react('👍');
210
+ } else if (msg.body === '!edit') {
211
+ if (msg.hasQuotedMsg) {
212
+ const quotedMsg = await msg.getQuotedMessage();
213
+ if (quotedMsg.fromMe) {
214
+ quotedMsg.edit(msg.body.replace('!edit', ''));
215
+ } else {
216
+ msg.reply('I can only edit my own messages');
217
+ }
218
+ }
219
+ } else if (msg.body === '!updatelabels') {
220
+ const chat = await msg.getChat();
221
+ await chat.changeLabels([0, 1]);
222
+ } else if (msg.body === '!addlabels') {
223
+ const chat = await msg.getChat();
224
+ let labels = (await chat.getLabels()).map(l => l.id);
225
+ labels.push('0');
226
+ labels.push('1');
227
+ await chat.changeLabels(labels);
228
+ } else if (msg.body === '!removelabels') {
229
+ const chat = await msg.getChat();
230
+ await chat.changeLabels([]);
204
231
  }
205
232
  });
206
233
 
@@ -286,28 +313,28 @@ client.on('contact_changed', async (message, oldId, newId, isContact) => {
286
313
  `Their new phone number is ${newId.slice(0, -5)}.\n`);
287
314
 
288
315
  /**
289
- * Information about the {@name message}:
316
+ * Information about the @param {message}:
290
317
  *
291
318
  * 1. If a notification was emitted due to a group participant changing their phone number:
292
- * {@name message.author} is a participant's id before the change.
293
- * {@name message.recipients[0]} is a participant's id after the change (a new one).
319
+ * @param {message.author} is a participant's id before the change.
320
+ * @param {message.recipients[0]} is a participant's id after the change (a new one).
294
321
  *
295
322
  * 1.1 If the contact who changed their number WAS in the current user's contact list at the time of the change:
296
- * {@name message.to} is a group chat id the event was emitted in.
297
- * {@name message.from} is a current user's id that got an notification message in the group.
298
- * Also the {@name message.fromMe} is TRUE.
323
+ * @param {message.to} is a group chat id the event was emitted in.
324
+ * @param {message.from} is a current user's id that got an notification message in the group.
325
+ * Also the @param {message.fromMe} is TRUE.
299
326
  *
300
327
  * 1.2 Otherwise:
301
- * {@name message.from} is a group chat id the event was emitted in.
302
- * {@name message.to} is @type {undefined}.
303
- * Also {@name message.fromMe} is FALSE.
328
+ * @param {message.from} is a group chat id the event was emitted in.
329
+ * @param {message.to} is @type {undefined}.
330
+ * Also @param {message.fromMe} is FALSE.
304
331
  *
305
332
  * 2. If a notification was emitted due to a contact changing their phone number:
306
- * {@name message.templateParams} is an array of two user's ids:
333
+ * @param {message.templateParams} is an array of two user's ids:
307
334
  * the old (before the change) and a new one, stored in alphabetical order.
308
- * {@name message.from} is a current user's id that has a chat with a user,
335
+ * @param {message.from} is a current user's id that has a chat with a user,
309
336
  * whos phone number was changed.
310
- * {@name message.to} is a user's id (after the change), the current user has a chat with.
337
+ * @param {message.to} is a user's id (after the change), the current user has a chat with.
311
338
  */
312
339
  });
313
340
 
package/index.d.ts CHANGED
@@ -60,6 +60,9 @@ declare namespace WAWebJS {
60
60
  /** Get contact instance by ID */
61
61
  getContactById(contactId: string): Promise<Contact>
62
62
 
63
+ /** Get message by ID */
64
+ getMessageById(messageId: string): Promise<Message>
65
+
63
66
  /** Get all current contact instances */
64
67
  getContacts(): Promise<Contact[]>
65
68
 
@@ -71,6 +74,9 @@ declare namespace WAWebJS {
71
74
 
72
75
  /** Get all current Labels */
73
76
  getLabels(): Promise<Label[]>
77
+
78
+ /** Change labels in chats */
79
+ addOrRemoveLabels(labelIds: Array<number|string>, chatIds: Array<string>): Promise<void>
74
80
 
75
81
  /** Get Label instance by ID */
76
82
  getLabelById(labelId: string): Promise<Label>
@@ -242,6 +248,16 @@ declare namespace WAWebJS {
242
248
  ack: MessageAck
243
249
  ) => void): this
244
250
 
251
+ /** Emitted when an ack event occurrs on message type */
252
+ on(event: 'message_edit', listener: (
253
+ /** The message that was affected */
254
+ message: Message,
255
+ /** New text message */
256
+ newBody: String,
257
+ /** Prev text message */
258
+ prevBody: String
259
+ ) => void): this
260
+
245
261
  /** Emitted when a chat unread count changes */
246
262
  on(event: 'unread_count', listener: (
247
263
  /** The chat that was affected */
@@ -567,6 +583,7 @@ declare namespace WAWebJS {
567
583
  MESSAGE_REVOKED_EVERYONE = 'message_revoke_everyone',
568
584
  MESSAGE_REVOKED_ME = 'message_revoke_me',
569
585
  MESSAGE_ACK = 'message_ack',
586
+ MESSAGE_EDIT = 'message_edit',
570
587
  MEDIA_UPLOADED = 'media_uploaded',
571
588
  CONTACT_CHANGED = 'contact_changed',
572
589
  GROUP_JOIN = 'group_join',
@@ -789,6 +806,10 @@ declare namespace WAWebJS {
789
806
  businessOwnerJid?: string,
790
807
  /** Product JID */
791
808
  productId?: string,
809
+ /** Last edit time */
810
+ latestEditSenderTimestampMs?: number,
811
+ /** Last edit message author */
812
+ latestEditMsgKey?: MessageId,
792
813
  /** Message buttons */
793
814
  dynamicReplyButtons?: object,
794
815
  /** Selected button ID */
@@ -846,6 +867,8 @@ declare namespace WAWebJS {
846
867
  * Gets the reactions associated with the given message
847
868
  */
848
869
  getReactions: () => Promise<ReactionList[]>,
870
+ /** Edits the current message */
871
+ edit: (content: MessageContent, options?: MessageEditOptions) => Promise<Message | null>,
849
872
  }
850
873
 
851
874
  /** ID that represents a message */
@@ -889,6 +912,8 @@ declare namespace WAWebJS {
889
912
  sendMediaAsSticker?: boolean
890
913
  /** Send media as document */
891
914
  sendMediaAsDocument?: boolean
915
+ /** Send photo/video as a view once message */
916
+ isViewOnce?: boolean
892
917
  /** Automatically parse vCards and send them as contacts */
893
918
  parseVCards?: boolean
894
919
  /** Image or videos caption */
@@ -911,6 +936,16 @@ declare namespace WAWebJS {
911
936
  stickerCategories?: string[]
912
937
  }
913
938
 
939
+ /** Options for editing a message */
940
+ export interface MessageEditOptions {
941
+ /** Show links preview. Has no effect on multi-device accounts. */
942
+ linkPreview?: boolean
943
+ /** Contacts that are being mentioned in the message */
944
+ mentions?: Contact[]
945
+ /** Extra options */
946
+ extra?: any
947
+ }
948
+
914
949
  export interface MediaFromURLOptions {
915
950
  client?: Client
916
951
  filename?: string
@@ -1135,6 +1170,8 @@ declare namespace WAWebJS {
1135
1170
  markUnread: () => Promise<void>
1136
1171
  /** Returns array of all Labels assigned to this Chat */
1137
1172
  getLabels: () => Promise<Label[]>
1173
+ /** Add or remove labels to this Chat */
1174
+ changeLabels: (labelIds: Array<string | number>) => Promise<void>
1138
1175
  }
1139
1176
 
1140
1177
  export interface MessageSearchOptions {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whatsapp-web.js",
3
- "version": "1.21.0",
3
+ "version": "1.21.1-alpha.1",
4
4
  "description": "Library for interacting with the WhatsApp Web API ",
5
5
  "main": "./index.js",
6
6
  "typings": "./index.d.ts",
package/src/Client.js CHANGED
@@ -238,9 +238,9 @@ class Client extends EventEmitter {
238
238
  // Listens to qr token change
239
239
  if (mut.type === 'attributes' && mut.attributeName === 'data-ref') {
240
240
  window.qrChanged(mut.target.dataset.ref);
241
- } else
241
+ }
242
242
  // Listens to retry button, when found, click it
243
- if (mut.type === 'childList') {
243
+ else if (mut.type === 'childList') {
244
244
  const retry_button = document.querySelector(selectors.QR_RETRY_BUTTON);
245
245
  if (retry_button) retry_button.click();
246
246
  }
@@ -275,6 +275,50 @@ class Client extends EventEmitter {
275
275
 
276
276
  }
277
277
 
278
+ await page.evaluate(() => {
279
+ /**
280
+ * Helper function that compares between two WWeb versions. Its purpose is to help the developer to choose the correct code implementation depending on the comparison value and the WWeb version.
281
+ * @param {string} lOperand The left operand for the WWeb version string to compare with
282
+ * @param {string} operator The comparison operator
283
+ * @param {string} rOperand The right operand for the WWeb version string to compare with
284
+ * @returns {boolean} Boolean value that indicates the result of the comparison
285
+ */
286
+ window.compareWwebVersions = (lOperand, operator, rOperand) => {
287
+ if (!['>', '>=', '<', '<=', '='].includes(operator)) {
288
+ throw class _ extends Error {
289
+ constructor(m) { super(m); this.name = 'CompareWwebVersionsError'; }
290
+ }('Invalid comparison operator is provided');
291
+
292
+ }
293
+ if (typeof lOperand !== 'string' || typeof rOperand !== 'string') {
294
+ throw class _ extends Error {
295
+ constructor(m) { super(m); this.name = 'CompareWwebVersionsError'; }
296
+ }('A non-string WWeb version type is provided');
297
+ }
298
+
299
+ lOperand = lOperand.replace(/-beta$/, '');
300
+ rOperand = rOperand.replace(/-beta$/, '');
301
+
302
+ while (lOperand.length !== rOperand.length) {
303
+ lOperand.length > rOperand.length
304
+ ? rOperand = rOperand.concat('0')
305
+ : lOperand = lOperand.concat('0');
306
+ }
307
+
308
+ lOperand = Number(lOperand.replace(/\./g, ''));
309
+ rOperand = Number(rOperand.replace(/\./g, ''));
310
+
311
+ return (
312
+ operator === '>' ? lOperand > rOperand :
313
+ operator === '>=' ? lOperand >= rOperand :
314
+ operator === '<' ? lOperand < rOperand :
315
+ operator === '<=' ? lOperand <= rOperand :
316
+ operator === '=' ? lOperand === rOperand :
317
+ false
318
+ );
319
+ };
320
+ });
321
+
278
322
  await page.evaluate(ExposeStore, moduleRaid.toString());
279
323
  const authEventPayload = await this.authStrategy.getAuthEventPayload();
280
324
 
@@ -314,7 +358,7 @@ class Client extends EventEmitter {
314
358
  await page.exposeFunction('onAddMessageEvent', msg => {
315
359
  if (msg.type === 'gp2') {
316
360
  const notification = new GroupNotification(this, msg);
317
- if (msg.subtype === 'add' || msg.subtype === 'invite') {
361
+ if (['add', 'invite', 'linked_group_join'].includes(msg.subtype)) {
318
362
  /**
319
363
  * Emitted when a user joins the chat via invite link or is added by an admin.
320
364
  * @event Client#group_join
@@ -396,18 +440,18 @@ class Client extends EventEmitter {
396
440
 
397
441
  /**
398
442
  * The event notification that is received when one of
399
- * the group participants changes thier phone number.
443
+ * the group participants changes their phone number.
400
444
  */
401
445
  const isParticipant = msg.type === 'gp2' && msg.subtype === 'modify';
402
446
 
403
447
  /**
404
448
  * The event notification that is received when one of
405
- * the contacts changes thier phone number.
449
+ * the contacts changes their phone number.
406
450
  */
407
451
  const isContact = msg.type === 'notification_template' && msg.subtype === 'change_number';
408
452
 
409
453
  if (isParticipant || isContact) {
410
- /** {@link GroupNotification} object does not provide enough information about this event, so a {@link Message} object is used. */
454
+ /** @type {GroupNotification} object does not provide enough information about this event, so a @type {Message} object is used. */
411
455
  const message = new Message(this, msg);
412
456
 
413
457
  const newId = isParticipant ? msg.recipients[0] : msg.to;
@@ -584,12 +628,28 @@ class Client extends EventEmitter {
584
628
  this.emit(Events.CHAT_ARCHIVED, new Chat(this, chat), currState, prevState);
585
629
  });
586
630
 
631
+ await page.exposeFunction('onEditMessageEvent', (msg, newBody, prevBody) => {
632
+
633
+ if(msg.type === 'revoked'){
634
+ return;
635
+ }
636
+ /**
637
+ * Emitted when messages are edited
638
+ * @event Client#message_edit
639
+ * @param {Message} message
640
+ * @param {string} newBody
641
+ * @param {string} prevBody
642
+ */
643
+ this.emit(Events.MESSAGE_EDIT, new Message(this, msg), newBody, prevBody);
644
+ });
645
+
587
646
  await page.evaluate(() => {
588
647
  window.Store.Msg.on('change', (msg) => { window.onChangeMessageEvent(window.WWebJS.getMessageModel(msg)); });
589
648
  window.Store.Msg.on('change:type', (msg) => { window.onChangeMessageTypeEvent(window.WWebJS.getMessageModel(msg)); });
590
649
  window.Store.Msg.on('change:ack', (msg, ack) => { window.onMessageAckEvent(window.WWebJS.getMessageModel(msg), ack); });
591
650
  window.Store.Msg.on('change:isUnsentMedia', (msg, unsent) => { if (msg.id.fromMe && !unsent) window.onMessageMediaUploadedEvent(window.WWebJS.getMessageModel(msg)); });
592
651
  window.Store.Msg.on('remove', (msg) => { if (msg.isNewMsg) window.onRemoveMessageEvent(window.WWebJS.getMessageModel(msg)); });
652
+ window.Store.Msg.on('change:body', (msg, newBody, prevBody) => { window.onEditMessageEvent(window.WWebJS.getMessageModel(msg), newBody, prevBody); });
593
653
  window.Store.AppState.on('change:state', (_AppState, state) => { window.onAppStateChangedEvent(state); });
594
654
  window.Store.Conn.on('change:battery', (state) => { window.onBatteryStateChangedEvent(state); });
595
655
  window.Store.Call.on('add', (call) => { window.onIncomingCall(call); });
@@ -686,7 +746,14 @@ class Client extends EventEmitter {
686
746
  await this.pupPage.evaluate(() => {
687
747
  return window.Store.AppState.logout();
688
748
  });
689
-
749
+ await this.pupBrowser.close();
750
+
751
+ let maxDelay = 0;
752
+ while (this.pupBrowser.isConnected() && (maxDelay < 10)) { // waits a maximum of 1 second before calling the AuthStrategy
753
+ await new Promise(resolve => setTimeout(resolve, 100));
754
+ maxDelay++;
755
+ }
756
+
690
757
  await this.authStrategy.logout();
691
758
  }
692
759
 
@@ -722,6 +789,7 @@ class Client extends EventEmitter {
722
789
  * @property {boolean} [sendVideoAsGif=false] - Send video as gif
723
790
  * @property {boolean} [sendMediaAsSticker=false] - Send media as a sticker
724
791
  * @property {boolean} [sendMediaAsDocument=false] - Send media as a document
792
+ * @property {boolean} [isViewOnce=false] - Send photo/video as a view once message
725
793
  * @property {boolean} [parseVCards=true] - Automatically parse vCards and send them as contacts
726
794
  * @property {string} [caption] - Image or video caption
727
795
  * @property {string} [quotedMessageId] - Id of the message that is being quoted (or replied to)
@@ -732,7 +800,7 @@ class Client extends EventEmitter {
732
800
  * @property {string[]} [stickerCategories=undefined] - Sets the categories of the sticker, (if sendMediaAsSticker is true). Provide emoji char array, can be null.
733
801
  * @property {MessageMedia} [media] - Media to be sent
734
802
  */
735
-
803
+
736
804
  /**
737
805
  * Send a message to a specific chatId
738
806
  * @param {string} chatId
@@ -742,6 +810,10 @@ class Client extends EventEmitter {
742
810
  * @returns {Promise<Message>} Message that was just sent
743
811
  */
744
812
  async sendMessage(chatId, content, options = {}) {
813
+ if (options.mentions && options.mentions.some(possiblyContact => possiblyContact instanceof Contact)) {
814
+ console.warn('Mentions with an array of Contact are now deprecated. See more at https://github.com/pedroslopez/whatsapp-web.js/pull/2166.');
815
+ options.mentions = options.mentions.map(a => a.id._serialized);
816
+ }
745
817
  let internalOptions = {
746
818
  linkPreview: options.linkPreview === false ? undefined : true,
747
819
  sendAudioAsVoice: options.sendAudioAsVoice,
@@ -751,7 +823,7 @@ class Client extends EventEmitter {
751
823
  caption: options.caption,
752
824
  quotedMessageId: options.quotedMessageId,
753
825
  parseVCards: options.parseVCards === false ? false : true,
754
- mentionedJidList: Array.isArray(options.mentions) ? options.mentions.map(contact => contact.id._serialized) : [],
826
+ mentionedJidList: Array.isArray(options.mentions) ? options.mentions : [],
755
827
  extraOptions: options.extra
756
828
  };
757
829
 
@@ -759,10 +831,12 @@ class Client extends EventEmitter {
759
831
 
760
832
  if (content instanceof MessageMedia) {
761
833
  internalOptions.attachment = content;
834
+ internalOptions.isViewOnce = options.isViewOnce,
762
835
  content = '';
763
836
  } else if (options.media instanceof MessageMedia) {
764
837
  internalOptions.attachment = options.media;
765
838
  internalOptions.caption = content;
839
+ internalOptions.isViewOnce = options.isViewOnce,
766
840
  content = '';
767
841
  } else if (content instanceof Location) {
768
842
  internalOptions.location = content;
@@ -781,7 +855,7 @@ class Client extends EventEmitter {
781
855
  internalOptions.list = content;
782
856
  content = '';
783
857
  }
784
-
858
+
785
859
  if (internalOptions.sendMediaAsSticker && internalOptions.attachment) {
786
860
  internalOptions.attachment = await Util.formatToWebpSticker(
787
861
  internalOptions.attachment, {
@@ -807,7 +881,7 @@ class Client extends EventEmitter {
807
881
 
808
882
  return new Message(this, newMessage);
809
883
  }
810
-
884
+
811
885
  /**
812
886
  * Searches for messages
813
887
  * @param {string} query
@@ -875,6 +949,24 @@ class Client extends EventEmitter {
875
949
 
876
950
  return ContactFactory.create(this, contact);
877
951
  }
952
+
953
+ async getMessageById(messageId) {
954
+ const msg = await this.pupPage.evaluate(async messageId => {
955
+ let msg = window.Store.Msg.get(messageId);
956
+ if(msg) return window.WWebJS.getMessageModel(msg);
957
+
958
+ const params = messageId.split('_');
959
+ if(params.length !== 3) throw new Error('Invalid serialized message id specified');
960
+
961
+ let messagesObject = await window.Store.Msg.getMessagesById([messageId]);
962
+ if (messagesObject && messagesObject.messages.length) msg = messagesObject.messages[0];
963
+
964
+ if(msg) return window.WWebJS.getMessageModel(msg);
965
+ }, messageId);
966
+
967
+ if(msg) return new Message(this, msg);
968
+ return null;
969
+ }
878
970
 
879
971
  /**
880
972
  * Returns an object with information about the invite code's group
@@ -910,7 +1002,8 @@ class Client extends EventEmitter {
910
1002
  if (inviteInfo.inviteCodeExp == 0) throw 'Expired invite code';
911
1003
  return this.pupPage.evaluate(async inviteInfo => {
912
1004
  let { groupId, fromId, inviteCode, inviteCodeExp } = inviteInfo;
913
- return await window.Store.JoinInviteV4.sendJoinGroupViaInviteV4(inviteCode, String(inviteCodeExp), groupId, fromId);
1005
+ let userWid = window.Store.WidFactory.createWid(fromId);
1006
+ return await window.Store.JoinInviteV4.joinGroupViaInviteV4(inviteCode, String(inviteCodeExp), groupId, userWid);
914
1007
  }, inviteInfo);
915
1008
  }
916
1009
 
@@ -1312,6 +1405,35 @@ class Client extends EventEmitter {
1312
1405
 
1313
1406
  return success;
1314
1407
  }
1408
+
1409
+ /**
1410
+ * Change labels in chats
1411
+ * @param {Array<number|string>} labelIds
1412
+ * @param {Array<string>} chatIds
1413
+ * @returns {Promise<void>}
1414
+ */
1415
+ async addOrRemoveLabels(labelIds, chatIds) {
1416
+
1417
+ return this.pupPage.evaluate(async (labelIds, chatIds) => {
1418
+ if (['smba', 'smbi'].indexOf(window.Store.Conn.platform) === -1) {
1419
+ throw '[LT01] Only Whatsapp business';
1420
+ }
1421
+ const labels = window.WWebJS.getLabels().filter(e => labelIds.find(l => l == e.id) !== undefined);
1422
+ const chats = window.Store.Chat.filter(e => chatIds.includes(e.id._serialized));
1423
+
1424
+ let actions = labels.map(label => ({id: label.id, type: 'add'}));
1425
+
1426
+ chats.forEach(chat => {
1427
+ (chat.labels || []).forEach(n => {
1428
+ if (!actions.find(e => e.id == n)) {
1429
+ actions.push({id: n, type: 'remove'});
1430
+ }
1431
+ });
1432
+ });
1433
+
1434
+ return await window.Store.Label.addOrRemoveLabels(actions, chats);
1435
+ }, labelIds, chatIds);
1436
+ }
1315
1437
  }
1316
1438
 
1317
1439
  module.exports = Client;
@@ -44,10 +44,10 @@ class LocalAuth extends BaseAuthStrategy {
44
44
 
45
45
  async logout() {
46
46
  if (this.userDataDir) {
47
- return (fs.rmSync ? fs.rmSync : fs.rmdirSync).call(this, this.userDataDir, { recursive: true });
47
+ return (fs.rmSync ? fs.rmSync : fs.rmdirSync).call(this, this.userDataDir, { recursive: true, force: true });
48
48
  }
49
49
  }
50
50
 
51
51
  }
52
52
 
53
- module.exports = LocalAuth;
53
+ module.exports = LocalAuth;
@@ -187,7 +187,7 @@ class Chat extends Base {
187
187
  if (m.isNotification) {
188
188
  return false; // dont include notification messages
189
189
  }
190
- if (searchOptions && searchOptions.fromMe && m.id.fromMe !== searchOptions.fromMe) {
190
+ if (searchOptions && searchOptions.fromMe !== undefined && m.id.fromMe !== searchOptions.fromMe) {
191
191
  return false;
192
192
  }
193
193
  return true;
@@ -261,6 +261,15 @@ class Chat extends Base {
261
261
  async getLabels() {
262
262
  return this.client.getChatLabels(this.id._serialized);
263
263
  }
264
+
265
+ /**
266
+ * Add or remove labels to this Chat
267
+ * @param {Array<number|string>} labelIds
268
+ * @returns {Promise<void>}
269
+ */
270
+ async changeLabels(labelIds) {
271
+ return this.client.addOrRemoveLabels(labelIds, [this.id._serialized]);
272
+ }
264
273
  }
265
274
 
266
275
  module.exports = Chat;
@@ -156,9 +156,10 @@ class Contact extends Base {
156
156
 
157
157
  await this.client.pupPage.evaluate(async (contactId) => {
158
158
  const contact = window.Store.Contact.get(contactId);
159
- await window.Store.BlockContact.blockContact(contact);
159
+ await window.Store.BlockContact.blockContact({contact});
160
160
  }, this.id._serialized);
161
161
 
162
+ this.isBlocked = true;
162
163
  return true;
163
164
  }
164
165
 
@@ -174,6 +175,7 @@ class Contact extends Base {
174
175
  await window.Store.BlockContact.unblockContact(contact);
175
176
  }, this.id._serialized);
176
177
 
178
+ this.isBlocked = false;
177
179
  return true;
178
180
  }
179
181
 
@@ -153,8 +153,9 @@ class GroupChat extends Chat {
153
153
  const success = await this.client.pupPage.evaluate(async (chatId, description) => {
154
154
  const chatWid = window.Store.WidFactory.createWid(chatId);
155
155
  let descId = window.Store.GroupMetadata.get(chatWid).descId;
156
+ let newId = await window.Store.MsgKey.newId();
156
157
  try {
157
- await window.Store.GroupUtils.setGroupDescription(chatWid, description, window.Store.MsgKey.newId(), descId);
158
+ await window.Store.GroupUtils.setGroupDescription(chatWid, description, newId, descId);
158
159
  return true;
159
160
  } catch (err) {
160
161
  if(err.name === 'ServerStatusCodeError') return false;
@@ -278,4 +279,4 @@ class GroupChat extends Chat {
278
279
 
279
280
  }
280
281
 
281
- module.exports = GroupChat;
282
+ module.exports = GroupChat;
@@ -7,6 +7,7 @@ const Order = require('./Order');
7
7
  const Payment = require('./Payment');
8
8
  const Reaction = require('./Reaction');
9
9
  const {MessageTypes} = require('../util/Constants');
10
+ const {Contact} = require('./Contact');
10
11
 
11
12
  /**
12
13
  * Represents a Message on WhatsApp
@@ -167,8 +168,8 @@ class Message extends Base {
167
168
  inviteCodeExp: data.inviteCodeExp,
168
169
  groupId: data.inviteGrp,
169
170
  groupName: data.inviteGrpName,
170
- fromId: data.from._serialized,
171
- toId: data.to._serialized
171
+ fromId: data.from?._serialized ? data.from._serialized : data.from,
172
+ toId: data.to?._serialized ? data.to._serialized : data.to
172
173
  } : undefined;
173
174
 
174
175
  /**
@@ -224,6 +225,16 @@ class Message extends Base {
224
225
  this.productId = data.productId;
225
226
  }
226
227
 
228
+ /** Last edit time */
229
+ if (data.latestEditSenderTimestampMs) {
230
+ this.latestEditSenderTimestampMs = data.latestEditSenderTimestampMs;
231
+ }
232
+
233
+ /** Last edit message author */
234
+ if (data.latestEditMsgKey) {
235
+ this.latestEditMsgKey = data.latestEditMsgKey;
236
+ }
237
+
227
238
  /**
228
239
  * Links included in the message.
229
240
  * @type {Array<{link: string, isSuspicious: boolean}>}
@@ -576,6 +587,42 @@ class Message extends Base {
576
587
  return reaction;
577
588
  });
578
589
  }
590
+
591
+ /**
592
+ * Edits the current message.
593
+ * @param {string} content
594
+ * @param {MessageEditOptions} [options] - Options used when editing the message
595
+ * @returns {Promise<?Message>}
596
+ */
597
+ async edit(content, options = {}) {
598
+ if (options.mentions && options.mentions.some(possiblyContact => possiblyContact instanceof Contact)) {
599
+ options.mentions = options.mentions.map(a => a.id._serialized);
600
+ }
601
+ let internalOptions = {
602
+ linkPreview: options.linkPreview === false ? undefined : true,
603
+ mentionedJidList: Array.isArray(options.mentions) ? options.mentions : [],
604
+ extraOptions: options.extra
605
+ };
606
+
607
+ if (!this.fromMe) {
608
+ return null;
609
+ }
610
+ const messageEdit = await this.client.pupPage.evaluate(async (msgId, message, options) => {
611
+ let msg = window.Store.Msg.get(msgId);
612
+ if (!msg) return null;
613
+
614
+ let catEdit = (msg.type === 'chat' && window.Store.MsgActionChecks.canEditText(msg));
615
+ if (catEdit) {
616
+ const msgEdit = await window.WWebJS.editMessage(msg, message, options);
617
+ return msgEdit.serialize();
618
+ }
619
+ return null;
620
+ }, this.id._serialized, content, internalOptions);
621
+ if (messageEdit) {
622
+ return new Message(this.client, messageEdit);
623
+ }
624
+ return null;
625
+ }
579
626
  }
580
627
 
581
628
  module.exports = Message;
@@ -48,6 +48,7 @@ exports.Events = {
48
48
  MESSAGE_REVOKED_EVERYONE: 'message_revoke_everyone',
49
49
  MESSAGE_REVOKED_ME: 'message_revoke_me',
50
50
  MESSAGE_ACK: 'message_ack',
51
+ MESSAGE_EDIT: 'message_edit',
51
52
  UNREAD_COUNT: 'unread_count',
52
53
  MESSAGE_REACTION: 'message_reaction',
53
54
  MEDIA_UPLOADED: 'media_uploaded',
@@ -9,7 +9,7 @@ exports.ExposeStore = (moduleRaidStr) => {
9
9
  window.Store.AppState = window.mR.findModule('Socket')[0].Socket;
10
10
  window.Store.Conn = window.mR.findModule('Conn')[0].Conn;
11
11
  window.Store.BlockContact = window.mR.findModule('blockContact')[0];
12
- window.Store.Call = window.mR.findModule('CallCollection')[0].CallCollection;
12
+ window.Store.Call = window.mR.findModule((module) => module.default && module.default.Call)[0].default.Call;
13
13
  window.Store.Cmd = window.mR.findModule('Cmd')[0].Cmd;
14
14
  window.Store.CryptoLib = window.mR.findModule('decryptE2EMedia')[0];
15
15
  window.Store.DownloadManager = window.mR.findModule('downloadManager')[0].downloadManager;
@@ -31,8 +31,11 @@ exports.ExposeStore = (moduleRaidStr) => {
31
31
  window.Store.SendClear = window.mR.findModule('sendClear')[0];
32
32
  window.Store.SendDelete = window.mR.findModule('sendDelete')[0];
33
33
  window.Store.SendMessage = window.mR.findModule('addAndSendMsgToChat')[0];
34
+ window.Store.EditMessage = window.mR.findModule('addAndSendMessageEdit')[0];
34
35
  window.Store.SendSeen = window.mR.findModule('sendSeen')[0];
35
36
  window.Store.User = window.mR.findModule('getMaybeMeUser')[0];
37
+ window.Store.ContactMethods = window.mR.findModule('getUserid')[0];
38
+ window.Store.BusinessProfileCollection = window.mR.findModule('BusinessProfileCollection')[0].BusinessProfileCollection;
36
39
  window.Store.UploadUtils = window.mR.findModule((module) => (module.default && module.default.encryptAndUpload) ? module.default : null)[0].default;
37
40
  window.Store.UserConstructor = window.mR.findModule((module) => (module.default && module.default.prototype && module.default.prototype.isServer && module.default.prototype.isUser) ? module.default : null)[0].default;
38
41
  window.Store.Validators = window.mR.findModule('findLinks')[0];
@@ -42,7 +45,7 @@ exports.ExposeStore = (moduleRaidStr) => {
42
45
  window.Store.PresenceUtils = window.mR.findModule('sendPresenceAvailable')[0];
43
46
  window.Store.ChatState = window.mR.findModule('sendChatStateComposing')[0];
44
47
  window.Store.GroupParticipants = window.mR.findModule('promoteParticipants')[0];
45
- window.Store.JoinInviteV4 = window.mR.findModule('sendJoinGroupViaInviteV4')[0];
48
+ window.Store.JoinInviteV4 = window.mR.findModule('queryGroupInviteV4')[0];
46
49
  window.Store.findCommonGroups = window.mR.findModule('findCommonGroups')[0].findCommonGroups;
47
50
  window.Store.StatusUtils = window.mR.findModule('setMyStatus')[0];
48
51
  window.Store.ConversationMsgs = window.mR.findModule('loadEarlierMsgs')[0];
@@ -124,6 +127,7 @@ exports.LoadUtils = () => {
124
127
  attOptions.caption = options.caption;
125
128
  }
126
129
  content = options.sendMediaAsSticker ? undefined : attOptions.preview;
130
+ attOptions.isViewOnce = options.isViewOnce;
127
131
 
128
132
  delete options.attachment;
129
133
  delete options.sendMediaAsSticker;
@@ -229,8 +233,8 @@ exports.LoadUtils = () => {
229
233
  }
230
234
 
231
235
  let listOptions = {};
232
- if(options.list){
233
- if(window.Store.Conn.platform === 'smba' || window.Store.Conn.platform === 'smbi'){
236
+ if (options.list) {
237
+ if (window.Store.Conn.platform === 'smba' || window.Store.Conn.platform === 'smbi') {
234
238
  throw '[LT01] Whatsapp business can\'t send this yet';
235
239
  }
236
240
  listOptions = {
@@ -289,6 +293,40 @@ exports.LoadUtils = () => {
289
293
  await window.Store.SendMessage.addAndSendMsgToChat(chat, message);
290
294
  return window.Store.Msg.get(newMsgId._serialized);
291
295
  };
296
+
297
+ window.WWebJS.editMessage = async (msg, content, options = {}) => {
298
+
299
+ const extraOptions = options.extraOptions || {};
300
+ delete options.extraOptions;
301
+
302
+ if (options.mentionedJidList) {
303
+ options.mentionedJidList = options.mentionedJidList.map(cId => window.Store.Contact.get(cId).id);
304
+ }
305
+
306
+ if (options.linkPreview) {
307
+ options.linkPreview = null;
308
+
309
+ // Not supported yet by WhatsApp Web on MD
310
+ if(!window.Store.MDBackend) {
311
+ const link = window.Store.Validators.findLink(content);
312
+ if (link) {
313
+ const preview = await window.Store.Wap.queryLinkPreview(link.url);
314
+ preview.preview = true;
315
+ preview.subtype = 'url';
316
+ options = { ...options, ...preview };
317
+ }
318
+ }
319
+ }
320
+
321
+
322
+ const internalOptions = {
323
+ ...options,
324
+ ...extraOptions
325
+ };
326
+
327
+ await window.Store.EditMessage.sendMessageEdit(msg, content, internalOptions);
328
+ return window.Store.Msg.get(msg.id._serialized);
329
+ };
292
330
 
293
331
  window.WWebJS.toStickerData = async (mediaInfo) => {
294
332
  if (mediaInfo.mimetype == 'image/webp') return mediaInfo;
@@ -437,7 +475,7 @@ exports.LoadUtils = () => {
437
475
 
438
476
  res.lastMessage = null;
439
477
  if (res.msgs && res.msgs.length) {
440
- const lastMessage = window.Store.Msg.get(chat.lastReceivedKey._serialized);
478
+ const lastMessage = chat.lastReceivedKey ? window.Store.Msg.get(chat.lastReceivedKey._serialized) : null;
441
479
  if (lastMessage) {
442
480
  res.lastMessage = window.WWebJS.getMessageModel(lastMessage);
443
481
  }
@@ -465,19 +503,56 @@ exports.LoadUtils = () => {
465
503
 
466
504
  window.WWebJS.getContactModel = contact => {
467
505
  let res = contact.serialize();
468
- res.isBusiness = contact.isBusiness;
506
+ res.isBusiness = contact.isBusiness === undefined ? false : contact.isBusiness;
469
507
 
470
508
  if (contact.businessProfile) {
471
509
  res.businessProfile = contact.businessProfile.serialize();
472
510
  }
473
511
 
474
- res.isMe = contact.isMe;
475
- res.isUser = contact.isUser;
476
- res.isGroup = contact.isGroup;
477
- res.isWAContact = contact.isWAContact;
478
- res.isMyContact = contact.isMyContact;
512
+ // TODO: remove useOldImplementation and its checks once all clients are updated to >= v2.2327.4
513
+ const useOldImplementation
514
+ = window.compareWwebVersions(window.Debug.VERSION, '<', '2.2327.4');
515
+
516
+ res.isMe = useOldImplementation
517
+ ? contact.isMe
518
+ : window.Store.ContactMethods.getIsMe(contact);
519
+ res.isUser = useOldImplementation
520
+ ? contact.isUser
521
+ : window.Store.ContactMethods.getIsUser(contact);
522
+ res.isGroup = useOldImplementation
523
+ ? contact.isGroup
524
+ : window.Store.ContactMethods.getIsGroup(contact);
525
+ res.isWAContact = useOldImplementation
526
+ ? contact.isWAContact
527
+ : window.Store.ContactMethods.getIsWAContact(contact);
528
+ res.isMyContact = useOldImplementation
529
+ ? contact.isMyContact
530
+ : window.Store.ContactMethods.getIsMyContact(contact);
479
531
  res.isBlocked = contact.isContactBlocked;
480
- res.userid = contact.userid;
532
+ res.userid = useOldImplementation
533
+ ? contact.userid
534
+ : window.Store.ContactMethods.getUserid(contact);
535
+ res.isEnterprise = useOldImplementation
536
+ ? contact.isEnterprise
537
+ : window.Store.ContactMethods.getIsEnterprise(contact);
538
+ res.verifiedName = useOldImplementation
539
+ ? contact.verifiedName
540
+ : window.Store.ContactMethods.getVerifiedName(contact);
541
+ res.verifiedLevel = useOldImplementation
542
+ ? contact.verifiedLevel
543
+ : window.Store.ContactMethods.getVerifiedLevel(contact);
544
+ res.statusMute = useOldImplementation
545
+ ? contact.statusMute
546
+ : window.Store.ContactMethods.getStatusMute(contact);
547
+ res.name = useOldImplementation
548
+ ? contact.name
549
+ : window.Store.ContactMethods.getName(contact);
550
+ res.shortName = useOldImplementation
551
+ ? contact.shortName
552
+ : window.Store.ContactMethods.getShortName(contact);
553
+ res.pushname = useOldImplementation
554
+ ? contact.pushname
555
+ : window.Store.ContactMethods.getPushname(contact);
481
556
 
482
557
  return res;
483
558
  };
@@ -485,6 +560,8 @@ exports.LoadUtils = () => {
485
560
  window.WWebJS.getContact = async contactId => {
486
561
  const wid = window.Store.WidFactory.createWid(contactId);
487
562
  const contact = await window.Store.Contact.find(wid);
563
+ const bizProfile = await window.Store.BusinessProfileCollection.fetchBizProfile(wid);
564
+ bizProfile.profileOptions && (contact.businessProfile = bizProfile);
488
565
  return window.WWebJS.getContactModel(contact);
489
566
  };
490
567
 
@@ -1,2 +0,0 @@
1
- <!DOCTYPE html><html class="no-js" dir="ltr" loc="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><title>WhatsApp Web</title><meta name="viewport" content="width=device-width"><meta name="google" content="notranslate"><meta name="format-detection" content="telephone=no"><meta name="description" content="Quickly send and receive WhatsApp messages right from your computer."><meta name="og:description" content="Quickly send and receive WhatsApp messages right from your computer."><meta name="og:url" content="https://web.whatsapp.com/"><meta name="og:title" content="WhatsApp Web"><meta name="og:image" content="https://static.facebook.com/images/whatsapp/www/whatsapp-promo.png"><link id="favicon" rel="shortcut icon" href="/img/favicon/1x/favicon.png" type="image/png"><link rel="apple-touch-icon" sizes="194x194" href="/apple-touch-icon.png" type="image/png"><meta name="theme-color" content="#111b21" media="(prefers-color-scheme: dark)"><meta name="theme-color" content="#f0f2f5"><link id="whatsapp-pwa-manifest-link" rel="manifest" href="/manifest.json" crossorigin="use-credentials"><style>#initial_startup{--startup-background:#f0f2f5;--startup-background-rgb:240,242,245;--startup-icon:#bbc5cb;--secondary-lighter:#8696a0;--primary-title:#41525d;--progress-primary:#00c298;--progress-background:#e9edef}.dark #initial_startup{--startup-background:#111b21;--startup-background-rgb:17,27,33;--startup-icon:#676f73;--primary-title:rgba(233, 237, 239, 0.88);--secondary-lighter:#667781;--progress-primary:#0b846d;--progress-background:#233138}#app,body,html{width:100%;height:100%;padding:0;margin:0;overflow:hidden}#app{position:absolute;top:0;left:0}#initial_startup{position:fixed;top:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%;user-select:none;background-color:var(--startup-background)}#initial_startup .graphic{margin-top:-40px;color:var(--startup-icon)}#initial_startup .graphic .resume-logo{transform:translateX(calc(50% - 52px / 2))}#initial_startup .graphic::after{position:relative;top:-100%;left:calc(50% - 72px * 2 - 72px / 2);display:block;width:calc(72px * 3);height:100%;content:'';background:linear-gradient(to right,rgba(var(--startup-background-rgb),.5) 0,rgba(var(--startup-background-rgb),.5) 33.33%,rgba(var(--startup-background-rgb),0) 44.1%,rgba(var(--startup-background-rgb),0) 55.8%,rgba(var(--startup-background-rgb),.5) 66.66%,rgba(var(--startup-background-rgb),.5) 100%);opacity:1;animation:shimmer 1.5s linear .6s infinite}html[dir=rtl] #initial_startup .graphic::after{animation-direction:reverse}@keyframes shimmer{from{left:calc(50% - 72px * 2 - 72px / 2)}to{left:calc(50% - 72px / 2)}}#initial_startup .progress{position:relative;width:420px;height:3px;margin-top:40px}#initial_startup .progress progress{vertical-align:top}#initial_startup .main{margin-top:40px;font-size:17px;color:var(--primary-title)}#initial_startup .secondary{margin-top:12px;font-size:14px;color:var(--secondary-lighter)}#initial_startup .secondary span{display:inline-block;margin-bottom:2px;vertical-align:middle}progress{-webkit-appearance:none;appearance:none;width:100%;height:3px;margin:0;color:var(--progress-primary);background-color:var(--progress-background);border:none}progress[value]::-webkit-progress-bar{background-color:var(--progress-background)}progress[value]::-moz-progress-bar,progress[value]::-webkit-progress-value{background-color:var(--progress-primary);transition:width .45s ease}</style><link href="/stylex-4a088306e44f3215558b4ef8b78657c5.css" rel="stylesheet"><link href="/app-a2c2cd1b2aea3ab61005.css" rel="stylesheet"></head><body class="web"><script data-binary-transparency-hash-key="inline-js-4b79b6dc91a7ee33373b115991c3eb287ed710cfb6708421b4cab682eddbfcbd">try{var systemThemeDark,theme=window.localStorage.getItem(""),systemThemeMode=window.localStorage.getItem("system-theme-mode");if(("true"===systemThemeMode||!theme)&&window.matchMedia){var systemTheme=window.matchMedia("(prefers-color-scheme: dark)");systemThemeDark=systemTheme&&systemTheme.matches}var darkTheme='"dark"'===theme||Boolean(systemThemeDark);darkTheme&&document.body.classList.add("dark")}catch(e){}</script><div id="app"></div><div id="hard_expire_time" data-time="1699300794.986"></div><div id="initial_startup"><div class="graphic"><span><svg width="250" height="52" xmlns="http://www.w3.org/2000/svg"><path class="resume-logo" d="M37.7 31.2c-.6-.4-3.8-2-4.4-2.1-.6-.2-1-.4-1.4.3l-2 2.5c-.4.4-.8.5-1.5.2-.6-.3-2.7-1-5.1-3.2-2-1.7-3.2-3.8-3.6-4.5-.4-.6 0-1 .3-1.3l1-1.1.6-1.1c.2-.4 0-.8 0-1.1l-2-4.8c-.6-1.3-1.1-1-1.5-1.1h-1.2c-.5 0-1.2.1-1.8.8-.5.6-2.2 2.2-2.2 5.3 0 3.2 2.3 6.3 2.6 6.7.3.4 4.6 7 11 9.7l3.7 1.4c1.5.5 3 .4 4 .2 1.3-.1 3.9-1.5 4.4-3 .5-1.5.5-2.8.4-3-.2-.4-.6-.5-1.3-.8M26 47.2c-3.9 0-7.6-1-11-3l-.7-.4-8.1 2L8.4 38l-.6-.8A21.4 21.4 0 0126 4.4a21.3 21.3 0 0121.4 21.4c0 11.8-9.6 21.4-21.4 21.4M44.2 7.6a25.8 25.8 0 00-40.6 31L0 52l13.7-3.6A25.8 25.8 0 0044.3 7.5" fill="currentColor"></path></svg></span></div><div class="progress"><progress value="0" max="100" dir="ltr"></progress></div><div class="main">WhatsApp</div><div class="secondary"><span><svg width="10" height="12" xmlns="http://www.w3.org/2000/svg"><path d="M5 1.6c1.4 0 2.5 1 2.6 2.4v1.5h.2c.5 0 1 .4 1 1V10c0 .6-.5 1-1 1H2.3a1 1 0 01-1.1-1V6.5c0-.6.5-1 1-1h.2V4.2c0-1.4 1-2.5 2.4-2.6H5zm0 1.2c-.7 0-1.3.6-1.3 1.3v1.4h2.6V4.2c0-.7-.4-1.2-1-1.3H5z" fill="currentColor"></path></svg> </span>&nbsp;End-to-end encrypted</div></div><link rel="preload" crossorigin="anonymous" as="fetch" href="/binary-transparency-manifest-2.2320.10.json" id="binary-transparency-manifest-preload"><script src="/libsignal-protocol-ee5b8ba.min.js"></script><script defer="defer" src="/runtime.48c50558556d819fec57.js"></script><script data-binary-transparency-hash-key="inline-js-026e63eb49dc1ea304d8d5b3073c120b618f17c45d3e4186fc3a06527b75bc4a">/*! Copyright (c) 2023 WhatsApp Inc. All Rights Reserved. */
2
- (self.webpackChunkwhatsapp_web_client=self.webpackChunkwhatsapp_web_client||[]).push([[5617],{307914:e=>{e.exports=function(e){return e&&e.__esModule?e:{default:e}}},595318:e=>{e.exports=function(e){return e&&e.__esModule?e:{default:e}},e.exports.default=e.exports,e.exports.__esModule=!0},415227:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){const t=new Error(e);if(void 0===t.stack)try{throw t}catch(e){}return t}},670983:(e,t,r)=>{"use strict";var n=r(307914);Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"?";if(null==e)throw(0,o.default)("Unexpected null or undefined: "+t);return e};var o=n(r(415227))},801506:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TICKET_URL=t.CLB_URL=t.CLB_TOKEN=t.CLB_CHECK_URL=void 0,t.CLB_CHECK_URL="https://crashlogs.whatsapp.net/wa_fls_upload_check",t.CLB_TOKEN="1063127757113399|745146ffa34413f9dbb5469f5370b7af",t.CLB_URL="https://crashlogs.whatsapp.net/wa_clb_data",t.TICKET_URL="https://web.whatsapp.com/web-contact-us"},207024:(e,t,r)=>{"use strict";var n=r(595318);Object.defineProperty(t,"__esModule",{value:!0}),t.getDistribution=function(){let e="unknown";return e="prod","web_prod"},t.getLogUserAgent=function(e){let t,{appVersion:r,browser:n,device:o}=e;return t="Web/"+n,`WhatsApp/${r} ${t} Device/${o}`},n(r(556869))},794858:(e,t,r)=>{"use strict";var n=r(595318),o=n(r(670983)),a=r(801506),s=r(207024),c=n(r(174285)),u=r(425017);function i(e){!function(e,t){const r=window.navigator.userAgent;if(r===p&&e.includes("getElementsByTagName"))return;const n=new FormData,i=new Blob([e],{type:"text/plain"});n.append("from_jid",function(){if(f)return f;try{f=JSON.parse((0,o.default)(c.default,"localStorage").getItem(d)),f&&(f=f.replace("-",""))}catch(e){}if(!f){f="unknown"+Math.floor(1e10*Math.random());const e=f;try{(0,o.default)(c.default,"localStorage").setItem(d,JSON.stringify(e))}catch(e){}}return(0,o.default)(f,"id")}()),n.append("agent",(0,s.getLogUserAgent)((0,u.parseUASimple)(r,"2.2320.10"))),n.append("file",i,"logs.txt"),n.append("tags","load");const l=new XMLHttpRequest,_=a.CLB_URL+"?access_token="+encodeURIComponent(a.CLB_TOKEN);l.open("POST",_,!0),l.send(n)}(e)}function l(e){let{error:t,reason:r,stack:n}=e;const o=(new Date).toISOString();return`${o}: error: ${t}\n${o}: reason for logs: ${r}\n${o}: userAgent: ${window.navigator.userAgent}\n${n}`}null==window.onerror&&(window.onerror=function(e,t,r){const n=t.split("?")[0];return"Uncaught SyntaxError: Unexpected token '<'"===e?(function(e){i(l({error:"failed to load a js or css bundle",reason:`failed to load [${e.split("/")[3].replace(/^\//,"")}]`,stack:""}))}(n),!0):(i(l({error:e,reason:`Error at [${n}:${r}]`,stack:""})),!1)});const d="WAUnknownID",p="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36";let f},425017:(e,t)=>{"use strict";function r(e){return e.includes("windows")?"Windows":e.includes("mac")?"Mac OS":e.includes("linux")?"Linux":"Unparsed"}Object.defineProperty(t,"__esModule",{value:!0}),t.parseUASimple=function(e,t){const n=e.toLowerCase();return{browser:s(n),device:r(n),appVersion:t}};const n=/(chrome|firefox)\/([\w\.]+)/i,o=/(edge|opr)\/([\w\.]+)/i,a={chrome:"Chrome",edge:"Edge",opr:"Opera",firefox:"Firefox"};function s(e){const t=e.match(o)||e.match(n);return null==t?"Unparsed":`${a[t[1]]} ${t[2]}`}},174285:(e,t)=>{"use strict";let r;Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;try{r=window.localStorage}catch(e){}var n=r;t.default=n},556869:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function e(t){const r=new Error(t);if(void 0===r.stack)try{throw e}catch(e){}return r}}},e=>{"use strict";e(e.s=794858)}])</script><script defer="defer" src="/vendor1~app.a91035d81a749b3d5627.js"></script><script defer="defer" src="/app.e77d49e02fab96b93f06.js"></script><script data-binary-transparency-hash-key="inline-js-9c8cd3d0f4d5af8c7f5cd1c45208edd308bfe472e353a50e4cbacbf6cb58627c">(i => {const l = document.getElementById(i); l &&fetch(l.href).then(b => b.text()).then(code => {const script = document.createElement('script');script.id = 'binary-transparency-manifest';script.type = 'application/json';script.innerHTML = code;document.body.append(script);});})('binary-transparency-manifest-preload');</script></body></html>
@@ -1,2 +0,0 @@
1
- <!DOCTYPE html><html class="no-js" dir="ltr" loc="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><title>WhatsAppX Web</title><meta name="viewport" content="width=device-width"><meta name="google" content="notranslate"><meta name="format-detection" content="telephone=no"><meta name="description" content="Quickly send and receive WhatsApp messages right from your computer."><meta name="og:description" content="Quickly send and receive WhatsApp messages right from your computer."><meta name="og:url" content="https://web.whatsapp.com/"><meta name="og:title" content="WhatsApp Web"><meta name="og:image" content="https://static.facebook.com/images/whatsapp/www/whatsapp-promo.png"><link id="favicon" rel="shortcut icon" href="/img/favicon/1x/favicon.png" type="image/png"><link rel="apple-touch-icon" sizes="194x194" href="/apple-touch-icon.png" type="image/png"><meta name="theme-color" content="#111b21" media="(prefers-color-scheme: dark)"><meta name="theme-color" content="#f0f2f5"><link id="whatsapp-pwa-manifest-link" rel="manifest" href="/manifest.json" crossorigin="use-credentials"><style>#initial_startup{--startup-background:#f0f2f5;--startup-background-rgb:240,242,245;--startup-icon:#bbc5cb;--secondary-lighter:#8696a0;--primary-title:#41525d;--progress-primary:#00c298;--progress-background:#e9edef}.dark #initial_startup{--startup-background:#111b21;--startup-background-rgb:17,27,33;--startup-icon:#676f73;--primary-title:rgba(233, 237, 239, 0.88);--secondary-lighter:#667781;--progress-primary:#0b846d;--progress-background:#233138}#app,body,html{width:100%;height:100%;padding:0;margin:0;overflow:hidden}#app{position:absolute;top:0;left:0}#initial_startup{position:fixed;top:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%;user-select:none;background-color:var(--startup-background)}#initial_startup .graphic{margin-top:-40px;color:var(--startup-icon)}#initial_startup .graphic .resume-logo{transform:translateX(calc(50% - 52px / 2))}#initial_startup .graphic::after{position:relative;top:-100%;left:calc(50% - 72px * 2 - 72px / 2);display:block;width:calc(72px * 3);height:100%;content:'';background:linear-gradient(to right,rgba(var(--startup-background-rgb),.5) 0,rgba(var(--startup-background-rgb),.5) 33.33%,rgba(var(--startup-background-rgb),0) 44.1%,rgba(var(--startup-background-rgb),0) 55.8%,rgba(var(--startup-background-rgb),.5) 66.66%,rgba(var(--startup-background-rgb),.5) 100%);opacity:1;animation:shimmer 1.5s linear .6s infinite}html[dir=rtl] #initial_startup .graphic::after{animation-direction:reverse}@keyframes shimmer{from{left:calc(50% - 72px * 2 - 72px / 2)}to{left:calc(50% - 72px / 2)}}#initial_startup .progress{position:relative;width:420px;height:3px;margin-top:40px}#initial_startup .progress progress{vertical-align:top}#initial_startup .main{margin-top:40px;font-size:17px;color:var(--primary-title)}#initial_startup .secondary{margin-top:12px;font-size:14px;color:var(--secondary-lighter)}#initial_startup .secondary span{display:inline-block;margin-bottom:2px;vertical-align:middle}progress{-webkit-appearance:none;appearance:none;width:100%;height:3px;margin:0;color:var(--progress-primary);background-color:var(--progress-background);border:none}progress[value]::-webkit-progress-bar{background-color:var(--progress-background)}progress[value]::-moz-progress-bar,progress[value]::-webkit-progress-value{background-color:var(--progress-primary);transition:width .45s ease}</style><link href="/stylex-534e186735a7216f8166323ac4f40ec0.css" rel="stylesheet"><link href="/app-397dc77d692df7ff99b6.css" rel="stylesheet"></head><body class="web"><script data-binary-transparency-hash-key="inline-js-4b79b6dc91a7ee33373b115991c3eb287ed710cfb6708421b4cab682eddbfcbd">try{var systemThemeDark,theme=window.localStorage.getItem(""),systemThemeMode=window.localStorage.getItem("system-theme-mode");if(("true"===systemThemeMode||!theme)&&window.matchMedia){var systemTheme=window.matchMedia("(prefers-color-scheme: dark)");systemThemeDark=systemTheme&&systemTheme.matches}var darkTheme='"dark"'===theme||Boolean(systemThemeDark);darkTheme&&document.body.classList.add("dark")}catch(e){}</script><div id="app"></div><div id="hard_expire_time" data-time="1700350311.621"></div><div id="initial_startup"><div class="graphic"><span><svg width="250" height="52" xmlns="http://www.w3.org/2000/svg"><path class="resume-logo" d="M37.7 31.2c-.6-.4-3.8-2-4.4-2.1-.6-.2-1-.4-1.4.3l-2 2.5c-.4.4-.8.5-1.5.2-.6-.3-2.7-1-5.1-3.2-2-1.7-3.2-3.8-3.6-4.5-.4-.6 0-1 .3-1.3l1-1.1.6-1.1c.2-.4 0-.8 0-1.1l-2-4.8c-.6-1.3-1.1-1-1.5-1.1h-1.2c-.5 0-1.2.1-1.8.8-.5.6-2.2 2.2-2.2 5.3 0 3.2 2.3 6.3 2.6 6.7.3.4 4.6 7 11 9.7l3.7 1.4c1.5.5 3 .4 4 .2 1.3-.1 3.9-1.5 4.4-3 .5-1.5.5-2.8.4-3-.2-.4-.6-.5-1.3-.8M26 47.2c-3.9 0-7.6-1-11-3l-.7-.4-8.1 2L8.4 38l-.6-.8A21.4 21.4 0 0126 4.4a21.3 21.3 0 0121.4 21.4c0 11.8-9.6 21.4-21.4 21.4M44.2 7.6a25.8 25.8 0 00-40.6 31L0 52l13.7-3.6A25.8 25.8 0 0044.3 7.5" fill="currentColor"></path></svg></span></div><div class="progress"><progress value="0" max="100" dir="ltr"></progress></div><div class="main">WhatsApp</div><div class="secondary"><span><svg width="10" height="12" xmlns="http://www.w3.org/2000/svg"><path d="M5 1.6c1.4 0 2.5 1 2.6 2.4v1.5h.2c.5 0 1 .4 1 1V10c0 .6-.5 1-1 1H2.3a1 1 0 01-1.1-1V6.5c0-.6.5-1 1-1h.2V4.2c0-1.4 1-2.5 2.4-2.6H5zm0 1.2c-.7 0-1.3.6-1.3 1.3v1.4h2.6V4.2c0-.7-.4-1.2-1-1.3H5z" fill="currentColor"></path></svg> </span>&nbsp;End-to-end encrypted</div></div><link rel="preload" crossorigin="anonymous" as="fetch" href="/binary-transparency-manifest-2.2322.15.json" id="binary-transparency-manifest-preload"><script src="/libsignal-protocol-ee5b8ba.min.js"></script><script defer="defer" src="/runtime.d9a06bd6a7a484d6e04e.js"></script><script data-binary-transparency-hash-key="inline-js-fa16de51ee7511dd7a3e11537a929d8433d81c4653032c11129c2f55dd563575">/*! Copyright (c) 2023 WhatsApp Inc. All Rights Reserved. */
2
- (self.webpackChunkwhatsapp_web_client=self.webpackChunkwhatsapp_web_client||[]).push([[5617],{307914:e=>{e.exports=function(e){return e&&e.__esModule?e:{default:e}}},595318:e=>{e.exports=function(e){return e&&e.__esModule?e:{default:e}},e.exports.default=e.exports,e.exports.__esModule=!0},415227:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){const t=new Error(e);if(void 0===t.stack)try{throw t}catch(e){}return t}},670983:(e,t,r)=>{"use strict";var n=r(307914);Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"?";if(null==e)throw(0,o.default)("Unexpected null or undefined: "+t);return e};var o=n(r(415227))},801506:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TICKET_URL=t.CLB_URL=t.CLB_TOKEN=t.CLB_CHECK_URL=void 0,t.CLB_CHECK_URL="https://crashlogs.whatsapp.net/wa_fls_upload_check",t.CLB_TOKEN="1063127757113399|745146ffa34413f9dbb5469f5370b7af",t.CLB_URL="https://crashlogs.whatsapp.net/wa_clb_data",t.TICKET_URL="https://web.whatsapp.com/web-contact-us"},207024:(e,t,r)=>{"use strict";var n=r(595318);Object.defineProperty(t,"__esModule",{value:!0}),t.getDistribution=function(){let e="unknown";return e="prod","web_prod"},t.getLogUserAgent=function(e){let t,{appVersion:r,browser:n,device:o}=e;return t="Web/"+n,`WhatsApp/${r} ${t} Device/${o}`},n(r(97359)),n(r(556869))},794858:(e,t,r)=>{"use strict";var n=r(595318),o=n(r(670983)),a=r(801506),s=r(207024),u=n(r(174285)),c=r(425017);function i(e){!function(e,t){const r=window.navigator.userAgent;if(r===f&&e.includes("getElementsByTagName"))return;const n=new FormData,i=new Blob([e],{type:"text/plain"});n.append("from_jid",function(){if(p)return p;try{p=JSON.parse((0,o.default)(u.default,"localStorage").getItem(d)),p&&(p=p.replace("-",""))}catch(e){}if(!p){p="unknown"+Math.floor(1e10*Math.random());const e=p;try{(0,o.default)(u.default,"localStorage").setItem(d,JSON.stringify(e))}catch(e){}}return(0,o.default)(p,"id")}()),n.append("agent",(0,s.getLogUserAgent)((0,c.parseUASimple)(r,"2.2322.15"))),n.append("file",i,"logs.txt"),n.append("tags","load");const l=new XMLHttpRequest,_=a.CLB_URL+"?access_token="+encodeURIComponent(a.CLB_TOKEN);l.open("POST",_,!0),l.send(n)}(e)}function l(e){let{error:t,reason:r,stack:n}=e;const o=(new Date).toISOString();return`${o}: error: ${t}\n${o}: reason for logs: ${r}\n${o}: userAgent: ${window.navigator.userAgent}\n${n}`}null==window.onerror&&(window.onerror=function(e,t,r){const n=t.split("?")[0];return"Uncaught SyntaxError: Unexpected token '<'"===e?(function(e){i(l({error:"failed to load a js or css bundle",reason:`failed to load [${e.split("/")[3].replace(/^\//,"")}]`,stack:""}))}(n),!0):(i(l({error:e,reason:`Error at [${n}:${r}]`,stack:""})),!1)});const d="WAUnknownID",f="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36";let p},425017:(e,t)=>{"use strict";function r(e){return e.includes("windows")?"Windows":e.includes("mac")?"Mac OS":e.includes("linux")?"Linux":"Unparsed"}Object.defineProperty(t,"__esModule",{value:!0}),t.parseUASimple=function(e,t){const n=e.toLowerCase();return{browser:s(n),device:r(n),appVersion:t}};const n=/(chrome|firefox)\/([\w\.]+)/i,o=/(edge|opr)\/([\w\.]+)/i,a={chrome:"Chrome",edge:"Edge",opr:"Opera",firefox:"Firefox"};function s(e){const t=e.match(o)||e.match(n);return null==t?"Unparsed":`${a[t[1]]} ${t[2]}`}},174285:(e,t)=>{"use strict";let r;Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;try{r=window.localStorage}catch(e){}var n=r;t.default=n},97359:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){return e.default}},556869:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function e(t){const r=new Error(t);if(void 0===r.stack)try{throw e}catch(e){}return r}}},e=>{"use strict";e(e.s=794858)}])</script><script defer="defer" src="/vendor1~app.a91035d81a749b3d5627.js"></script><script defer="defer" src="/app.df22dc4b1b984dc87f36.js"></script><script data-binary-transparency-hash-key="inline-js-9c8cd3d0f4d5af8c7f5cd1c45208edd308bfe472e353a50e4cbacbf6cb58627c">(i => {const l = document.getElementById(i); l &&fetch(l.href).then(b => b.text()).then(code => {const script = document.createElement('script');script.id = 'binary-transparency-manifest';script.type = 'application/json';script.innerHTML = code;document.body.append(script);});})('binary-transparency-manifest-preload');</script></body></html>