whatsapp-web.js 1.27.0 → 1.28.1-alpha.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.
package/example.js CHANGED
@@ -470,6 +470,10 @@ client.on('message', async msg => {
470
470
  console.log(statuses);
471
471
  const chat = await statuses[0]?.getChat(); // Get user chat of a first status
472
472
  console.log(chat);
473
+ } else if (msg.body === '!changeSync') {
474
+ // NOTE: this action will take effect after you restart the client.
475
+ const backgroundSync = await client.setBackgroundSync(true);
476
+ console.log(backgroundSync);
473
477
  }
474
478
  });
475
479
 
package/index.d.ts CHANGED
@@ -116,7 +116,7 @@ declare namespace WAWebJS {
116
116
  * @param chatId ID of the chat that will be muted
117
117
  * @param unmuteDate Date when the chat will be unmuted, leave as is to mute forever
118
118
  */
119
- muteChat(chatId: string, unmuteDate?: Date): Promise<void>
119
+ muteChat(chatId: string, unmuteDate?: Date): Promise<{ isMuted: boolean, muteExpiration: number }>
120
120
 
121
121
  /**
122
122
  * Request authentication via pairing code instead of QR code
@@ -180,6 +180,13 @@ declare namespace WAWebJS {
180
180
  */
181
181
  setAutoDownloadVideos(flag: boolean): Promise<void>
182
182
 
183
+ /**
184
+ * Changing the background synchronization setting.
185
+ * NOTE: this action will take effect after you restart the client.
186
+ * @param flag true/false on or off
187
+ */
188
+ setBackgroundSync(flag: boolean): Promise<void>
189
+
183
190
  /**
184
191
  * Get user device count by ID
185
192
  * Each WaWeb Connection counts as one device, and the phone (if exists) counts as one
@@ -190,12 +197,18 @@ declare namespace WAWebJS {
190
197
 
191
198
  /** Sync history conversation of the Chat */
192
199
  syncHistory(chatId: string): Promise<boolean>
200
+
201
+ /** Save new contact to user's addressbook or edit the existing one */
202
+ saveOrEditAddressbookContact(phoneNumber: string, firstName: string, lastName: string, syncToAddressbook?: boolean): Promise<ChatId>
203
+
204
+ /** Deletes the contact from user's addressbook */
205
+ deleteAddressbookContact(honeNumber: string): Promise<void>
193
206
 
194
207
  /** Changes and returns the archive state of the Chat */
195
208
  unarchiveChat(chatId: string): Promise<boolean>
196
209
 
197
210
  /** Unmutes the Chat */
198
- unmuteChat(chatId: string): Promise<void>
211
+ unmuteChat(chatId: string): Promise<{ isMuted: boolean, muteExpiration: number }>
199
212
 
200
213
  /** Sets the current user's profile picture */
201
214
  setProfilePicture(media: MessageMedia): Promise<boolean>
@@ -953,7 +966,7 @@ declare namespace WAWebJS {
953
966
  /** Accept the Group V4 Invite in message */
954
967
  acceptGroupV4Invite: () => Promise<{status: number}>,
955
968
  /** Deletes the message from the chat */
956
- delete: (everyone?: boolean) => Promise<void>,
969
+ delete: (everyone?: boolean, clearMedia?: boolean) => Promise<void>,
957
970
  /** Downloads and returns the attached message media */
958
971
  downloadMedia: () => Promise<MessageMedia>,
959
972
  /** Returns the Chat this message was sent in */
@@ -1026,7 +1039,10 @@ declare namespace WAWebJS {
1026
1039
  export class Location {
1027
1040
  latitude: string;
1028
1041
  longitude: string;
1029
- options?: LocationSendOptions;
1042
+ name?: string;
1043
+ address?: string;
1044
+ url?: string;
1045
+ description?: string;
1030
1046
 
1031
1047
  constructor(latitude: number, longitude: number, options?: LocationSendOptions)
1032
1048
  }
@@ -1158,7 +1174,10 @@ declare namespace WAWebJS {
1158
1174
  /** Sticker author, if sendMediaAsSticker is true */
1159
1175
  stickerAuthor?: string
1160
1176
  /** Sticker categories, if sendMediaAsSticker is true */
1161
- stickerCategories?: string[]
1177
+ stickerCategories?: string[],
1178
+ /** Should the bot send a quoted message without the quoted message if it fails to get the quote?
1179
+ * @default false (disabled) */
1180
+ ignoreQuoteErrors?: boolean
1162
1181
  }
1163
1182
 
1164
1183
  /** Options for editing a message */
@@ -1449,10 +1468,10 @@ declare namespace WAWebJS {
1449
1468
  /** Loads chat messages, sorted from earliest to latest. */
1450
1469
  fetchMessages: (searchOptions: MessageSearchOptions) => Promise<Message[]>,
1451
1470
  /** Mutes this chat forever, unless a date is specified */
1452
- mute: (unmuteDate?: Date) => Promise<void>,
1471
+ mute: (unmuteDate?: Date) => Promise<{ isMuted: boolean, muteExpiration: number }>,
1453
1472
  /** Send a message to this chat */
1454
1473
  sendMessage: (content: MessageContent, options?: MessageSendOptions) => Promise<Message>,
1455
- /** Set the message as seen */
1474
+ /** Set the chat as seen */
1456
1475
  sendSeen: () => Promise<void>,
1457
1476
  /** Simulate recording audio in chat. This will last for 25 seconds */
1458
1477
  sendStateRecording: () => Promise<void>,
@@ -1461,7 +1480,7 @@ declare namespace WAWebJS {
1461
1480
  /** un-archives this chat */
1462
1481
  unarchive: () => Promise<void>,
1463
1482
  /** Unmutes this chat */
1464
- unmute: () => Promise<void>,
1483
+ unmute: () => Promise<{ isMuted: boolean, muteExpiration: number }>,
1465
1484
  /** Returns the Contact that corresponds to this Chat. */
1466
1485
  getContact: () => Promise<Contact>,
1467
1486
  /** Marks this Chat as unread */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whatsapp-web.js",
3
- "version": "1.27.0",
3
+ "version": "1.28.1-alpha.0",
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
@@ -278,7 +278,7 @@ class Client extends EventEmitter {
278
278
  await this.authStrategy.beforeBrowserInitialized();
279
279
 
280
280
  const puppeteerOpts = this.options.puppeteer;
281
- if (puppeteerOpts && puppeteerOpts.browserWSEndpoint) {
281
+ if (puppeteerOpts && (puppeteerOpts.browserWSEndpoint || puppeteerOpts.browserURL)) {
282
282
  browser = await puppeteer.connect(puppeteerOpts);
283
283
  page = await browser.newPage();
284
284
  } else {
@@ -1193,25 +1193,38 @@ class Client extends EventEmitter {
1193
1193
  /**
1194
1194
  * Mutes this chat forever, unless a date is specified
1195
1195
  * @param {string} chatId ID of the chat that will be muted
1196
- * @param {?Date} unmuteDate Date when the chat will be unmuted, leave as is to mute forever
1196
+ * @param {?Date} unmuteDate Date when the chat will be unmuted, don't provide a value to mute forever
1197
+ * @returns {Promise<{isMuted: boolean, muteExpiration: number}>}
1197
1198
  */
1198
1199
  async muteChat(chatId, unmuteDate) {
1199
- unmuteDate = unmuteDate ? unmuteDate.getTime() / 1000 : -1;
1200
- await this.pupPage.evaluate(async (chatId, timestamp) => {
1201
- let chat = await window.Store.Chat.get(chatId);
1202
- await chat.mute.mute({expiration: timestamp, sendDevice:!0});
1203
- }, chatId, unmuteDate || -1);
1200
+ unmuteDate = unmuteDate ? Math.floor(unmuteDate.getTime() / 1000) : -1;
1201
+ return this._muteUnmuteChat(chatId, 'MUTE', unmuteDate);
1204
1202
  }
1205
1203
 
1206
1204
  /**
1207
1205
  * Unmutes the Chat
1208
1206
  * @param {string} chatId ID of the chat that will be unmuted
1207
+ * @returns {Promise<{isMuted: boolean, muteExpiration: number}>}
1209
1208
  */
1210
1209
  async unmuteChat(chatId) {
1211
- await this.pupPage.evaluate(async chatId => {
1212
- let chat = await window.Store.Chat.get(chatId);
1213
- await window.Store.Cmd.muteChat(chat, false);
1214
- }, chatId);
1210
+ return this._muteUnmuteChat(chatId, 'UNMUTE');
1211
+ }
1212
+
1213
+ /**
1214
+ * Internal method to mute or unmute the chat
1215
+ * @param {string} chatId ID of the chat that will be muted/unmuted
1216
+ * @param {string} action The action: 'MUTE' or 'UNMUTE'
1217
+ * @param {number} unmuteDateTs Timestamp at which the chat will be unmuted
1218
+ * @returns {Promise<{isMuted: boolean, muteExpiration: number}>}
1219
+ */
1220
+ async _muteUnmuteChat (chatId, action, unmuteDateTs) {
1221
+ return this.pupPage.evaluate(async (chatId, action, unmuteDateTs) => {
1222
+ const chat = window.Store.Chat.get(chatId) ?? await window.Store.Chat.find(chatId);
1223
+ action === 'MUTE'
1224
+ ? await chat.mute.mute({ expiration: unmuteDateTs, sendDevice: true })
1225
+ : await chat.mute.unmute({ sendDevice: true });
1226
+ return { isMuted: chat.mute.expiration !== 0, muteExpiration: chat.mute.expiration };
1227
+ }, chatId, action, unmuteDateTs || -1);
1215
1228
  }
1216
1229
 
1217
1230
  /**
@@ -1281,7 +1294,7 @@ class Client extends EventEmitter {
1281
1294
  */
1282
1295
  async resetState() {
1283
1296
  await this.pupPage.evaluate(() => {
1284
- window.Store.AppState.phoneWatchdog.shiftTimer.forceRunNow();
1297
+ window.Store.AppState.reconnect();
1285
1298
  });
1286
1299
  }
1287
1300
 
@@ -1721,6 +1734,23 @@ class Client extends EventEmitter {
1721
1734
  }, flag);
1722
1735
  }
1723
1736
 
1737
+ /**
1738
+ * Setting background synchronization.
1739
+ * NOTE: this action will take effect after you restart the client.
1740
+ * @param {boolean} flag true/false
1741
+ * @returns {Promise<boolean>}
1742
+ */
1743
+ async setBackgroundSync(flag) {
1744
+ return await this.pupPage.evaluate(async flag => {
1745
+ const backSync = window.Store.Settings.getGlobalOfflineNotifications();
1746
+ if (backSync === flag) {
1747
+ return flag;
1748
+ }
1749
+ await window.Store.Settings.setGlobalOfflineNotifications(flag);
1750
+ return flag;
1751
+ }, flag);
1752
+ }
1753
+
1724
1754
  /**
1725
1755
  * Get user device count by ID
1726
1756
  * Each WaWeb Connection counts as one device, and the phone (if exists) counts as one
@@ -1745,8 +1775,9 @@ class Client extends EventEmitter {
1745
1775
  */
1746
1776
  async syncHistory(chatId) {
1747
1777
  return await this.pupPage.evaluate(async (chatId) => {
1748
- const chat = await window.WWebJS.getChat(chatId);
1749
- if (chat.endOfHistoryTransferType === 0) {
1778
+ const chatWid = window.Store.WidFactory.createWid(chatId);
1779
+ const chat = window.Store.Chat.get(chatWid) ?? (await window.Store.Chat.find(chatWid));
1780
+ if (chat?.endOfHistoryTransferType === 0) {
1750
1781
  await window.Store.HistorySync.sendPeerDataOperationRequest(3, {
1751
1782
  chatId: chat.id
1752
1783
  });
@@ -1755,6 +1786,39 @@ class Client extends EventEmitter {
1755
1786
  return false;
1756
1787
  }, chatId);
1757
1788
  }
1789
+
1790
+ /**
1791
+ * Save new contact to user's addressbook or edit the existing one
1792
+ * @param {string} phoneNumber The contact's phone number in a format "17182222222", where "1" is a country code
1793
+ * @param {string} firstName
1794
+ * @param {string} lastName
1795
+ * @param {boolean} [syncToAddressbook = false] If set to true, the contact will also be saved to the user's address book on their phone. False by default
1796
+ * @returns {Promise<import('..').ChatId>} Object in a wid format
1797
+ */
1798
+ async saveOrEditAddressbookContact(phoneNumber, firstName, lastName, syncToAddressbook = false)
1799
+ {
1800
+ return await this.pupPage.evaluate(async (phoneNumber, firstName, lastName, syncToAddressbook) => {
1801
+ return await window.Store.AddressbookContactUtils.saveContactAction(
1802
+ phoneNumber,
1803
+ null,
1804
+ firstName,
1805
+ lastName,
1806
+ syncToAddressbook
1807
+ );
1808
+ }, phoneNumber, firstName, lastName, syncToAddressbook);
1809
+ }
1810
+
1811
+ /**
1812
+ * Deletes the contact from user's addressbook
1813
+ * @param {string} phoneNumber The contact's phone number in a format "17182222222", where "1" is a country code
1814
+ * @returns {Promise<void>}
1815
+ */
1816
+ async deleteAddressbookContact(phoneNumber)
1817
+ {
1818
+ return await this.pupPage.evaluate(async (phoneNumber) => {
1819
+ return await window.Store.AddressbookContactUtils.deleteContactAction(phoneNumber);
1820
+ }, phoneNumber);
1821
+ }
1758
1822
  }
1759
1823
 
1760
1824
  module.exports = Client;
@@ -43,7 +43,7 @@ class Broadcast extends Base {
43
43
  * Messages statuses
44
44
  * @type {Message[]}
45
45
  */
46
- this.msgs = data.msgs.map(msg => new Message(this.client, msg));
46
+ this.msgs = data.msgs?.map(msg => new Message(this.client, msg));
47
47
 
48
48
  return super._patch(data);
49
49
  }
@@ -95,7 +95,7 @@ class Chat extends Base {
95
95
  }
96
96
 
97
97
  /**
98
- * Set the message as seen
98
+ * Set the chat as seen
99
99
  * @returns {Promise<Boolean>} result
100
100
  */
101
101
  async sendSeen() {
@@ -154,17 +154,25 @@ class Chat extends Base {
154
154
 
155
155
  /**
156
156
  * Mutes this chat forever, unless a date is specified
157
- * @param {?Date} unmuteDate Date at which the Chat will be unmuted, leave as is to mute forever
157
+ * @param {?Date} unmuteDate Date when the chat will be unmuted, don't provide a value to mute forever
158
+ * @returns {Promise<{isMuted: boolean, muteExpiration: number}>}
158
159
  */
159
160
  async mute(unmuteDate) {
160
- return this.client.muteChat(this.id._serialized, unmuteDate);
161
+ const result = await this.client.muteChat(this.id._serialized, unmuteDate);
162
+ this.isMuted = result.isMuted;
163
+ this.muteExpiration = result.muteExpiration;
164
+ return result;
161
165
  }
162
166
 
163
167
  /**
164
168
  * Unmutes this chat
169
+ * @returns {Promise<{isMuted: boolean, muteExpiration: number}>}
165
170
  */
166
171
  async unmute() {
167
- return this.client.unmuteChat(this.id._serialized);
172
+ const result = await this.client.unmuteChat(this.id._serialized);
173
+ this.isMuted = result.isMuted;
174
+ this.muteExpiration = result.muteExpiration;
175
+ return result;
168
176
  }
169
177
 
170
178
  /**
@@ -98,7 +98,7 @@ class GroupChat extends Chat {
98
98
  419: 'The participant can\'t be added because the group is full'
99
99
  };
100
100
 
101
- await window.Store.GroupQueryAndUpdate(groupWid);
101
+ await window.Store.GroupQueryAndUpdate({ id: groupId });
102
102
  const groupMetadata = group.groupMetadata;
103
103
  const groupParticipants = groupMetadata?.participants;
104
104
 
@@ -6,6 +6,7 @@
6
6
  * @property {string} [name] Location name
7
7
  * @property {string} [address] Location address
8
8
  * @property {string} [url] URL address to be shown within a location message
9
+ * @property {string} [description] Location full description
9
10
  */
10
11
 
11
12
  /**
@@ -498,23 +498,26 @@ class Message extends Base {
498
498
  /**
499
499
  * Deletes a message from the chat
500
500
  * @param {?boolean} everyone If true and the message is sent by the current user or the user is an admin, will delete it for everyone in the chat.
501
+ * @param {?boolean} [clearMedia = true] If true, any associated media will also be deleted from a device.
501
502
  */
502
- async delete(everyone) {
503
- await this.client.pupPage.evaluate(async (msgId, everyone) => {
503
+ async delete(everyone, clearMedia = true) {
504
+ await this.client.pupPage.evaluate(async (msgId, everyone, clearMedia) => {
504
505
  const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
505
- let chat = await window.Store.Chat.find(msg.id.remote);
506
+ const chat = window.Store.Chat.get(msg.id.remote) || (await window.Store.Chat.find(msg.id.remote));
506
507
 
507
- const canRevoke = window.Store.MsgActionChecks.canSenderRevokeMsg(msg) || window.Store.MsgActionChecks.canAdminRevokeMsg(msg);
508
+ const canRevoke =
509
+ window.Store.MsgActionChecks.canSenderRevokeMsg(msg) || window.Store.MsgActionChecks.canAdminRevokeMsg(msg);
510
+
508
511
  if (everyone && canRevoke) {
509
- if (window.compareWwebVersions(window.Debug.VERSION, '>=', '2.3000.0')) {
510
- return window.Store.Cmd.sendRevokeMsgs(chat, { list: [msg], type: 'message' }, { clearMedia: true });
511
- } else {
512
- return window.Store.Cmd.sendRevokeMsgs(chat, [msg], { clearMedia: true, type: msg.id.fromMe ? 'Sender' : 'Admin' });
513
- }
512
+ return window.compareWwebVersions(window.Debug.VERSION, '>=', '2.3000.0')
513
+ ? window.Store.Cmd.sendRevokeMsgs(chat, { list: [msg], type: 'message' }, { clearMedia: clearMedia })
514
+ : window.Store.Cmd.sendRevokeMsgs(chat, [msg], { clearMedia: true, type: msg.id.fromMe ? 'Sender' : 'Admin' });
514
515
  }
515
516
 
516
- return window.Store.Cmd.sendDeleteMsgs(chat, [msg], true);
517
- }, this.id._serialized, everyone);
517
+ return window.compareWwebVersions(window.Debug.VERSION, '>=', '2.3000.0')
518
+ ? window.Store.Cmd.sendDeleteMsgs(chat, { list: [msg], type: 'message' }, clearMedia)
519
+ : window.Store.Cmd.sendDeleteMsgs(chat, [msg], clearMedia);
520
+ }, this.id._serialized, everyone, clearMedia);
518
521
  }
519
522
 
520
523
  /**
@@ -55,7 +55,6 @@ exports.ExposeStore = () => {
55
55
  window.Store.MediaTypes = window.require('WAWebMmsMediaTypes');
56
56
  window.Store.MediaUpload = window.require('WAWebMediaMmsV4Upload');
57
57
  window.Store.MsgKey = window.require('WAWebMsgKey');
58
- window.Store.NumberInfo = window.require('WAPhoneUtils');
59
58
  window.Store.OpaqueData = window.require('WAWebMediaOpaqueData');
60
59
  window.Store.QueryProduct = window.require('WAWebBizProductCatalogBridge');
61
60
  window.Store.QueryOrder = window.require('WAWebBizOrderBridge');
@@ -85,7 +84,7 @@ exports.ExposeStore = () => {
85
84
  window.Store.LinkPreview = window.require('WAWebLinkPreviewChatAction');
86
85
  window.Store.Socket = window.require('WADeprecatedSendIq');
87
86
  window.Store.SocketWap = window.require('WAWap');
88
- window.Store.SearchContext = window.require('WAWebChatMessageSearch').getSearchContext;
87
+ window.Store.SearchContext = window.require('WAWebChatMessageSearch');
89
88
  window.Store.DrawerManager = window.require('WAWebDrawerManager').DrawerManager;
90
89
  window.Store.LidUtils = window.require('WAWebApiContact');
91
90
  window.Store.WidToJid = window.require('WAWebWidToJid');
@@ -94,18 +93,27 @@ exports.ExposeStore = () => {
94
93
  window.Store.pinUnpinMsg = window.require('WAWebSendPinMessageAction').sendPinInChatMsg;
95
94
  window.Store.QueryExist = window.require('WAWebQueryExistsJob').queryWidExists;
96
95
  window.Store.ReplyUtils = window.require('WAWebMsgReply');
97
- window.Store.Settings = window.require('WAWebUserPrefsGeneral');
98
96
  window.Store.BotSecret = window.require('WAWebBotMessageSecret');
99
97
  window.Store.BotProfiles = window.require('WAWebBotProfileCollection');
100
98
  window.Store.DeviceList = window.require('WAWebApiDeviceList');
101
99
  window.Store.HistorySync = window.require('WAWebSendNonMessageDataRequest');
102
- if (window.compareWwebVersions(window.Debug.VERSION, '>=', '2.3000.1014111620'))
100
+ if (window.compareWwebVersions(window.Debug.VERSION, '>=', '2.3000.1014111620'))
103
101
  window.Store.AddonReactionTable = window.require('WAWebAddonReactionTableMode').reactionTableMode;
104
102
 
103
+ window.Store.Settings = {
104
+ ...window.require('WAWebUserPrefsGeneral'),
105
+ ...window.require('WAWebUserPrefsNotifications'),
106
+ setPushname: window.require('WAWebSetPushnameConnAction').setPushname
107
+ };
108
+
109
+ window.Store.NumberInfo = {
110
+ ...window.require('WAPhoneUtils'),
111
+ ...window.require('WAPhoneFindCC')
112
+ };
113
+
105
114
  window.Store.ForwardUtils = {
106
115
  ...window.require('WAWebForwardMessagesToChat')
107
116
  };
108
-
109
117
  window.Store.StickerTools = {
110
118
  ...window.require('WAWebImageUtils'),
111
119
  ...window.require('WAWebAddWebpMetadata')
@@ -133,6 +141,10 @@ exports.ExposeStore = () => {
133
141
  ...window.require('WAWebApiMembershipApprovalRequestStore'),
134
142
  ...window.require('WASmaxGroupsMembershipRequestsActionRPC')
135
143
  };
144
+ window.Store.AddressbookContactUtils = {
145
+ ...window.require('WAWebSaveContactAction'),
146
+ ...window.require('WAWebDeleteContactAction')
147
+ };
136
148
 
137
149
  if (!window.Store.Chat._find || !window.Store.Chat.findImpl) {
138
150
  window.Store.Chat._find = e => {
@@ -8,7 +8,7 @@ exports.LoadUtils = () => {
8
8
  let chat = window.Store.Chat.get(chatId);
9
9
 
10
10
  if (window.compareWwebVersions(window.Debug.VERSION, '>', '2.3000.0')) {
11
- return window.Store.ForwardUtils.forwardMessagesToChats([msg], [chat], false);
11
+ return window.Store.ForwardUtils.forwardMessagesToChats([msg], [chat], true);
12
12
  } else {
13
13
  return chat.forwardMessages([msg]);
14
14
  }
@@ -46,20 +46,24 @@ exports.LoadUtils = () => {
46
46
  if (options.quotedMessageId) {
47
47
  let quotedMessage = await window.Store.Msg.getMessagesById([options.quotedMessageId]);
48
48
 
49
- if (quotedMessage['messages'].length != 1) {
50
- throw new Error('Could not get the quoted message.');
51
- }
52
-
53
- quotedMessage = quotedMessage['messages'][0];
49
+ if (quotedMessage['messages'].length == 1) {
50
+ quotedMessage = quotedMessage['messages'][0];
54
51
 
55
- // TODO remove .canReply() once all clients are updated to >= v2.2241.6
56
- const canReply = window.Store.ReplyUtils ?
57
- window.Store.ReplyUtils.canReplyMsg(quotedMessage.unsafe()) :
58
- quotedMessage.canReply();
52
+ // TODO remove .canReply() once all clients are updated to >= v2.2241.6
53
+ const canReply = window.Store.ReplyUtils ?
54
+ window.Store.ReplyUtils.canReplyMsg(quotedMessage.unsafe()) :
55
+ quotedMessage.canReply();
59
56
 
60
- if (canReply) {
61
- quotedMsgOptions = quotedMessage.msgContextInfo(chat);
57
+ if (canReply) {
58
+ quotedMsgOptions = quotedMessage.msgContextInfo(chat);
59
+ }
60
+ }else{
61
+ if(!options.ignoreQuoteErrors) {
62
+ throw new Error('Could not get the quoted message.');
63
+ }
62
64
  }
65
+
66
+ delete options.ignoreQuoteErrors;
63
67
  delete options.quotedMessageId;
64
68
  }
65
69
 
@@ -210,8 +214,12 @@ exports.LoadUtils = () => {
210
214
  delete options.invokedBotWid;
211
215
  }
212
216
 
213
- const meUser = window.Store.User.getMaybeMeUser();
217
+ let meUser = window.Store.User.getMaybeMeUser();
214
218
  const newId = await window.Store.MsgKey.newId();
219
+
220
+ if (chat.id.isGroup() && chat.groupMetadata.isLidAddressingMode) {
221
+ meUser = window.Store.User.getMaybeMeLidUser();
222
+ }
215
223
 
216
224
  const newMsgId = new window.Store.MsgKey({
217
225
  from: meUser,
@@ -453,13 +461,14 @@ exports.LoadUtils = () => {
453
461
  let res = chat.serialize();
454
462
  res.isGroup = false;
455
463
  res.formattedTitle = chat.formattedTitle;
456
- res.isMuted = chat.muteExpiration == 0 ? false : true;
464
+ res.isMuted = chat.mute?.expiration !== 0;
457
465
 
458
466
  if (chat.groupMetadata) {
459
467
  res.isGroup = true;
460
468
  const chatWid = window.Store.WidFactory.createWid((chat.id._serialized));
461
469
  await window.Store.GroupMetadata.update(chatWid);
462
470
  res.groupMetadata = chat.groupMetadata.serialize();
471
+ res.isReadOnly = chat.groupMetadata.announce;
463
472
  }
464
473
 
465
474
  res.lastMessage = null;
@@ -921,7 +930,7 @@ exports.LoadUtils = () => {
921
930
  let response;
922
931
  let result = [];
923
932
 
924
- await window.Store.GroupQueryAndUpdate(groupWid);
933
+ await window.Store.GroupQueryAndUpdate({ id: groupId });
925
934
 
926
935
  if (!requesterIds?.length) {
927
936
  membershipRequests = group.groupMetadata.membershipApprovalRequests._models.map(({ id }) => id);
@@ -1016,9 +1025,8 @@ exports.LoadUtils = () => {
1016
1025
  };
1017
1026
 
1018
1027
  window.WWebJS.getStatusModel = status => {
1019
- let res = status.serialize();
1028
+ const res = status.serialize();
1020
1029
  delete res._msgs;
1021
- res.msgs = status._msgs.map(msg => window.WWebJS.getMessageModel(msg));
1022
1030
  return res;
1023
1031
  };
1024
1032
 
@@ -48,11 +48,11 @@ class InterfaceController {
48
48
  * @param {string} msgId ID of the message that will be scrolled to
49
49
  */
50
50
  async openChatWindowAt(msgId) {
51
- await this.pupPage.evaluate(async msgId => {
51
+ await this.pupPage.evaluate(async (msgId) => {
52
52
  const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
53
- let chat = await window.Store.Chat.find(msg.id.remote);
54
- let searchContext = await window.Store.SearchContext(chat,msg);
55
- await window.Store.Cmd.openChatAt(chat, searchContext);
53
+ const chat = window.Store.Chat.get(msg.id.remote) ?? await window.Store.Chat.find(msg.id.remote);
54
+ const searchContext = await window.Store.SearchContext.getSearchContext(chat, msg.id);
55
+ await window.Store.Cmd.openChatAt({ chat: chat, msgContext: searchContext });
56
56
  }, msgId);
57
57
  }
58
58