whatsapp-web.js 1.34.0 → 1.34.2

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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <div align="center">
2
2
  <br />
3
3
  <p>
4
- <a href="https://wwebjs.dev"><img src="https://github.com/wwebjs/logos/blob/main/4_Full%20Logo%20Lockup_Small/small_banner_blue.png?raw=true" title="whatsapp-web.js" alt="WWebJS Website" width="500" /></a>
4
+ <a href="https://wwebjs.dev"><img src="https://github.com/wwebjs/assets/blob/main/Collection/GitHub/wwebjs.png?raw=true" title="whatsapp-web.js" alt="WWebJS Website" width="500" /></a>
5
5
  </p>
6
6
  <br />
7
7
  <p>
@@ -14,57 +14,28 @@
14
14
  </div>
15
15
 
16
16
  ## About
17
- **A WhatsApp API client that connects through the WhatsApp Web browser app**
17
+ **A WhatsApp API client that operates via the WhatsApp Web browser.**
18
18
 
19
- The library works by launching the WhatsApp Web browser application and managing it using Puppeteer to create an instance of WhatsApp Web, thereby mitigating the risk of being blocked. The WhatsApp API client connects through the WhatsApp Web browser app, accessing its internal functions. This grants you access to nearly all the features available on WhatsApp Web, enabling dynamic handling similar to any other Node.js application.
19
+ The library launches the WhatsApp Web browser app via Puppeteer, accessing its internal functions and creating a managed instance to reduce the risk of being blocked. This gives the API client nearly all WhatsApp Web features for dynamic use in a Node.js application.
20
20
 
21
21
  > [!IMPORTANT]
22
22
  > **It is not guaranteed you will not be blocked by using this method. WhatsApp does not allow bots or unofficial clients on their platform, so this shouldn't be considered totally safe.**
23
23
 
24
24
  ## Links
25
25
 
26
- * [Website][website]
27
- * [Guide][guide] ([source][guide-source]) _(work in progress)_
28
- * [Documentation][documentation] ([source][documentation-source])
29
- * [WWebJS Discord][discord]
30
26
  * [GitHub][gitHub]
27
+ * [Guide][guide] ([source][guide-source])
28
+ * [Documentation][documentation] ([source][documentation-source])
29
+ * [Discord Server][discord]
31
30
  * [npm][npm]
32
31
 
33
32
  ## Installation
34
33
 
35
- The module is now available on npm! `npm i whatsapp-web.js`
34
+ The module is available on [npm][npm] via `npm i whatsapp-web.js`!
36
35
 
37
36
  > [!NOTE]
38
- > **Node ``v18+`` is required.**
39
-
40
- ## QUICK STEPS TO UPGRADE NODE
41
-
42
- ### Windows
43
-
44
- #### Manual
45
- Just get the latest LTS from the [official node website][nodejs].
46
-
47
- #### npm
48
- ```powershell
49
- sudo npm install -g n
50
- sudo n stable
51
- ```
52
-
53
- #### Choco
54
- ```powershell
55
- choco install nodejs-lts
56
- ```
57
-
58
- #### Winget
59
- ```powershell
60
- winget install OpenJS.NodeJS.LTS
61
- ```
62
-
63
- ### Ubuntu / Debian
64
- ```bash
65
- curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - &&\
66
- sudo apt-get install -y nodejs
67
- ```
37
+ > **Node ``v18`` or higher, is required.**
38
+ > See the [Guide][guide] for quick upgrade instructions.
68
39
 
69
40
  ## Example usage
70
41
 
@@ -165,7 +136,6 @@ See the License for the specific language governing permissions and
165
136
  limitations under the License.
166
137
 
167
138
 
168
- [website]: https://wwebjs.dev
169
139
  [guide]: https://guide.wwebjs.dev/guide
170
140
  [guide-source]: https://github.com/wwebjs/wwebjs.dev/tree/main
171
141
  [documentation]: https://docs.wwebjs.dev/
package/index.d.ts CHANGED
@@ -242,7 +242,26 @@ declare namespace WAWebJS {
242
242
  syncHistory(chatId: string): Promise<boolean>
243
243
 
244
244
  /** Save new contact to user's addressbook or edit the existing one */
245
- saveOrEditAddressbookContact(phoneNumber: string, firstName: string, lastName: string, syncToAddressbook?: boolean): Promise<ChatId>
245
+ saveOrEditAddressbookContact(phoneNumber: string, firstName: string, lastName: string, syncToAddressbook?: boolean): Promise<void>
246
+
247
+ /**
248
+ * Add or edit a customer note
249
+ * @see https://faq.whatsapp.com/1433099287594476
250
+ */
251
+ addOrEditCustomerNote(userId: string, note: string): Promise<void>
252
+
253
+ /**
254
+ * Get a customer note
255
+ * @see https://faq.whatsapp.com/1433099287594476
256
+ */
257
+ getCustomerNote(userId: string): Promise<{
258
+ chatId: string;
259
+ content: string;
260
+ createdAt: number;
261
+ id: string;
262
+ modifiedAt: number;
263
+ type: string;
264
+ }>
246
265
 
247
266
  /** Deletes the contact from user's addressbook */
248
267
  deleteAddressbookContact(honeNumber: string): Promise<void>
@@ -287,6 +306,9 @@ declare namespace WAWebJS {
287
306
  */
288
307
  transferChannelOwnership(channelId: string, newOwnerId: string, options?: TransferChannelOwnershipOptions): Promise<boolean>;
289
308
 
309
+ /** Get Poll Votes */
310
+ getPollVotes(messageId: string): Promise<PollVote[]>
311
+
290
312
  /** Generic event */
291
313
  on(event: string, listener: (...args: any) => void): this
292
314
 
@@ -1173,6 +1195,10 @@ declare namespace WAWebJS {
1173
1195
  * Gets the payment details associated with a given message
1174
1196
  */
1175
1197
  getPayment: () => Promise<Payment>,
1198
+ /**
1199
+ * Get Poll Votes associated with the given message
1200
+ */
1201
+ getPollVotes: () => Promise<PollVote[]>,
1176
1202
  /**
1177
1203
  * Gets the reactions associated with the given message
1178
1204
  */
@@ -1707,6 +1733,17 @@ declare namespace WAWebJS {
1707
1733
  getPinnedMessages: () => Promise<[Message]|[]>
1708
1734
  /** Sync history conversation of the Chat */
1709
1735
  syncHistory: () => Promise<boolean>
1736
+ /** Add or edit a customer note */
1737
+ addOrEditCustomerNote: (note: string) => Promise<void>
1738
+ /** Get a customer note */
1739
+ getCustomerNote: () => Promise<{
1740
+ chatId: string;
1741
+ content: string;
1742
+ createdAt: number;
1743
+ id: string;
1744
+ modifiedAt: number;
1745
+ type: string;
1746
+ }>
1710
1747
  }
1711
1748
 
1712
1749
  export interface Channel {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whatsapp-web.js",
3
- "version": "1.34.0",
3
+ "version": "1.34.2",
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
@@ -1225,11 +1225,18 @@ class Client extends EventEmitter {
1225
1225
 
1226
1226
  const msgs = await window.Store.PinnedMsgUtils.getTable().equals(['chatId'], chatWid.toString());
1227
1227
 
1228
- const pinnedMsgs = msgs.map((msg) => window.Store.Msg.get(msg.parentMsgKey));
1228
+ const pinnedMsgs = (
1229
+ await Promise.all(
1230
+ msgs.filter(msg => msg.pinType == 1).map(async (msg) => {
1231
+ const res = await window.Store.Msg.getMessagesById([msg.parentMsgKey]);
1232
+ return res?.messages?.[0];
1233
+ })
1234
+ )
1235
+ ).filter(Boolean);
1229
1236
 
1230
1237
  return !pinnedMsgs.length
1231
1238
  ? []
1232
- : pinnedMsgs.map((msg) => window.WWebJS.getMessageModel(msg));
1239
+ : await Promise.all(pinnedMsgs.map((msg) => window.WWebJS.getMessageModel(msg)));
1233
1240
  }, chatId);
1234
1241
 
1235
1242
  return pinnedMsgs.map((msg) => new Message(this, msg));
@@ -1524,7 +1531,7 @@ class Client extends EventEmitter {
1524
1531
  const commonGroups = await this.pupPage.evaluate(async (contactId) => {
1525
1532
  let contact = window.Store.Contact.get(contactId);
1526
1533
  if (!contact) {
1527
- const wid = window.Store.WidFactory.createUserWid(contactId);
1534
+ const wid = window.Store.WidFactory.createWid(contactId);
1528
1535
  const chatConstructor = window.Store.Contact.getModelsArray().find(c=>!c.isGroup).constructor;
1529
1536
  contact = new chatConstructor({id: wid});
1530
1537
  }
@@ -2310,14 +2317,16 @@ class Client extends EventEmitter {
2310
2317
  * @param {string} firstName
2311
2318
  * @param {string} lastName
2312
2319
  * @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
2313
- * @returns {Promise<import('..').ChatId>} Object in a wid format
2320
+ * @returns {Promise<void>}
2314
2321
  */
2315
2322
  async saveOrEditAddressbookContact(phoneNumber, firstName, lastName, syncToAddressbook = false)
2316
2323
  {
2317
2324
  return await this.pupPage.evaluate(async (phoneNumber, firstName, lastName, syncToAddressbook) => {
2318
2325
  return await window.Store.AddressbookContactUtils.saveContactAction(
2326
+ phoneNumber,
2319
2327
  phoneNumber,
2320
2328
  null,
2329
+ null,
2321
2330
  firstName,
2322
2331
  lastName,
2323
2332
  syncToAddressbook
@@ -2356,6 +2365,83 @@ class Client extends EventEmitter {
2356
2365
  }));
2357
2366
  }, userIds);
2358
2367
  }
2368
+
2369
+ /**
2370
+ * Add or edit a customer note
2371
+ * @see https://faq.whatsapp.com/1433099287594476
2372
+ * @param {string} userId The ID of a customer to add a note to
2373
+ * @param {string} note The note to add
2374
+ * @returns {Promise<void>}
2375
+ */
2376
+ async addOrEditCustomerNote(userId, note) {
2377
+ return await this.pupPage.evaluate(async (userId, note) => {
2378
+ if (!window.Store.BusinessGatingUtils.smbNotesV1Enabled()) return;
2379
+
2380
+ return window.Store.CustomerNoteUtils.noteAddAction(
2381
+ 'unstructured',
2382
+ window.Store.WidToJid.widToUserJid(window.Store.WidFactory.createWid(userId)),
2383
+ note
2384
+ );
2385
+ }, userId, note);
2386
+ }
2387
+
2388
+ /**
2389
+ * Get a customer note
2390
+ * @see https://faq.whatsapp.com/1433099287594476
2391
+ * @param {string} userId The ID of a customer to get a note from
2392
+ * @returns {Promise<{
2393
+ * chatId: string,
2394
+ * content: string,
2395
+ * createdAt: number,
2396
+ * id: string,
2397
+ * modifiedAt: number,
2398
+ * type: string
2399
+ * }>}
2400
+ */
2401
+ async getCustomerNote(userId) {
2402
+ return await this.pupPage.evaluate(async (userId) => {
2403
+ if (!window.Store.BusinessGatingUtils.smbNotesV1Enabled()) return null;
2404
+
2405
+ const note = await window.Store.CustomerNoteUtils.retrieveOnlyNoteForChatJid(
2406
+ window.Store.WidToJid.widToUserJid(window.Store.WidFactory.createWid(userId))
2407
+ );
2408
+
2409
+ let serialized = note?.serialize();
2410
+
2411
+ if (!serialized) return null;
2412
+
2413
+ serialized.chatId = window.Store.JidToWid.userJidToUserWid(serialized.chatJid)._serialized;
2414
+ delete serialized.chatJid;
2415
+
2416
+ return serialized;
2417
+ }, userId);
2418
+ }
2419
+
2420
+ /**
2421
+ * Get Poll Votes
2422
+ * @param {string} messageId
2423
+ * @return {Promise<Array<PollVote>>}
2424
+ */
2425
+ async getPollVotes(messageId) {
2426
+ const msg = await this.getMessageById(messageId);
2427
+ if (!msg) return [];
2428
+ if (msg.type != 'poll_creation') throw 'Invalid usage! Can only be used with a pollCreation message';
2429
+
2430
+ const pollVotes = await this.pupPage.evaluate( async (msg) => {
2431
+ const msgKey = window.Store.MsgKey.fromString(msg.id._serialized);
2432
+ let pollVotes = await window.Store.PollsVotesSchema.getTable().equals(['parentMsgKey'], msgKey.toString());
2433
+
2434
+ return pollVotes.map(item => {
2435
+ const typedArray = new Uint8Array(item.selectedOptionLocalIds);
2436
+ return {
2437
+ ...item,
2438
+ selectedOptionLocalIds: Array.from(typedArray)
2439
+ };
2440
+ });
2441
+ }, msg);
2442
+
2443
+ return pollVotes.map((pollVote) => new PollVote(this.client, {...pollVote, parentMessage: msg}));
2444
+ }
2359
2445
  }
2360
2446
 
2361
2447
  module.exports = Client;
@@ -294,6 +294,36 @@ class Chat extends Base {
294
294
  async syncHistory() {
295
295
  return this.client.syncHistory(this.id._serialized);
296
296
  }
297
+
298
+ /**
299
+ * Add or edit a customer note
300
+ * @see https://faq.whatsapp.com/1433099287594476
301
+ * @param {string} note The note to add
302
+ * @returns {Promise<void>}
303
+ */
304
+ async addOrEditCustomerNote(note) {
305
+ if (this.isGroup || this.isChannel) return;
306
+
307
+ return this.client.addOrEditCustomerNote(this.id._serialized, note);
308
+ }
309
+
310
+ /**
311
+ * Get a customer note
312
+ * @see https://faq.whatsapp.com/1433099287594476
313
+ * @returns {Promise<{
314
+ * chatId: string,
315
+ * content: string,
316
+ * createdAt: number,
317
+ * id: string,
318
+ * modifiedAt: number,
319
+ * type: string
320
+ * }>}
321
+ */
322
+ async getCustomerNote() {
323
+ if (this.isGroup || this.isChannel) return null;
324
+
325
+ return this.client.getCustomerNote(this.id._serialized);
326
+ }
297
327
  }
298
328
 
299
329
  module.exports = Chat;
@@ -186,7 +186,7 @@ class Contact extends Base {
186
186
  async getAbout() {
187
187
  const about = await this.client.pupPage.evaluate(async (contactId) => {
188
188
  const wid = window.Store.WidFactory.createWid(contactId);
189
- return window.Store.StatusUtils.getStatus(wid);
189
+ return window.Store.StatusUtils.getStatus({'token':'', 'wid': wid});
190
190
  }, this.id._serialized);
191
191
 
192
192
  if (typeof about.status !== 'string')
@@ -742,6 +742,13 @@ class Message extends Base {
742
742
 
743
743
  return edittedEventMsg && new Message(this.client, edittedEventMsg);
744
744
  }
745
+ /**
746
+ * Returns the PollVote this poll message
747
+ * @returns {Promise<PollVote[]>}
748
+ */
749
+ async getPollVotes() {
750
+ return await this.client.getPollVotes(this.id._serialized);
751
+ }
745
752
  }
746
753
 
747
754
  module.exports = Message;
@@ -97,12 +97,13 @@ exports.ExposeStore = () => {
97
97
  window.Store.HistorySync = window.require('WAWebSendNonMessageDataRequest');
98
98
  window.Store.AddonReactionTable = window.require('WAWebAddonReactionTableMode').reactionTableMode;
99
99
  window.Store.AddonPollVoteTable = window.require('WAWebAddonPollVoteTableMode').pollVoteTableMode;
100
- window.Store.PinnedMsgUtils = window.require('WAWebPinInChatSchema');
101
100
  window.Store.ChatGetters = window.require('WAWebChatGetters');
102
- window.Store.PinnedMsgUtils = window.require('WAWebSendPinMessageAction');
103
101
  window.Store.UploadUtils = window.require('WAWebUploadManager');
104
102
  window.Store.WAWebStreamModel = window.require('WAWebStreamModel');
105
103
  window.Store.FindOrCreateChat = window.require('WAWebFindChatAction');
104
+ window.Store.CustomerNoteUtils = window.require('WAWebNoteAction');
105
+ window.Store.BusinessGatingUtils = window.require('WAWebBizGatingUtils');
106
+ window.Store.PollsVotesSchema = require('WAWebPollsVotesSchema');
106
107
 
107
108
  window.Store.Settings = {
108
109
  ...window.require('WAWebUserPrefsGeneral'),
@@ -116,6 +117,10 @@ exports.ExposeStore = () => {
116
117
  window.Store.ForwardUtils = {
117
118
  ...window.require('WAWebChatForwardMessage')
118
119
  };
120
+ window.Store.PinnedMsgUtils = {
121
+ ...window.require('WAWebPinInChatSchema'),
122
+ ...window.require('WAWebSendPinMessageAction')
123
+ };
119
124
  window.Store.ScheduledEventMsgUtils = {
120
125
  ...window.require('WAWebGenerateEventCallLink'),
121
126
  ...window.require('WAWebSendEventEditMsgAction'),
@@ -211,21 +216,35 @@ exports.ExposeStore = () => {
211
216
  * @param {Function} callback Modified function
212
217
  */
213
218
  window.injectToFunction = (target, callback) => {
214
- let module = window.require(target.module);
219
+ try {
220
+ let module = window.require(target.module);
221
+ if (!module) return;
215
222
 
216
- const path = target.function.split('.');
217
- const funcName = path.pop();
218
- for (const key of path) {
219
- module = module[key];
220
- }
223
+ const path = target.function.split('.');
224
+ const funcName = path.pop();
225
+
226
+ for (const key of path) {
227
+ if (!module[key]) return;
228
+ module = module[key];
229
+ }
230
+
231
+ const originalFunction = module[funcName];
232
+ if (typeof originalFunction !== 'function') return;
221
233
 
222
- const originalFunction = module[funcName];
223
- module[funcName] = (...args) => callback(originalFunction, ...args);
234
+ module[funcName] = (...args) => {
235
+ try {
236
+ return callback(originalFunction, ...args);
237
+ } catch {
238
+ return originalFunction(...args);
239
+ }
240
+ };
241
+
242
+ } catch {
243
+ return;
244
+ }
224
245
  };
225
246
 
226
247
  window.injectToFunction({ module: 'WAWebBackendJobsCommon', function: 'mediaTypeFromProtobuf' }, (func, ...args) => { const [proto] = args; return proto.locationMessage ? null : func(...args); });
227
248
 
228
249
  window.injectToFunction({ module: 'WAWebE2EProtoUtils', function: 'typeAttributeFromProtobuf' }, (func, ...args) => { const [proto] = args; return proto.locationMessage || proto.groupInviteMessage ? 'text' : func(...args); });
229
-
230
- window.injectToFunction({ module: 'WAWebLid1X1MigrationGating', function: 'Lid1X1MigrationUtils.isLidMigrated' }, () => false);
231
250
  };
@@ -6,7 +6,7 @@ exports.LoadUtils = () => {
6
6
  window.WWebJS.forwardMessage = async (chatId, msgId) => {
7
7
  const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
8
8
  const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
9
- return window.Store.ForwardUtils.forwardMessages(chat, [msg], true, true);
9
+ return await window.Store.ForwardUtils.forwardMessages({'chat': chat, 'msgs' : [msg], 'multicast': true, 'includeCaption': true, 'appendedText' : undefined});
10
10
  };
11
11
 
12
12
  window.WWebJS.sendSeen = async (chatId) => {
@@ -14,6 +14,7 @@ exports.LoadUtils = () => {
14
14
  if (chat) {
15
15
  window.Store.WAWebStreamModel.Stream.markAvailable();
16
16
  await window.Store.SendSeen.sendSeen(chat);
17
+ window.Store.WAWebStreamModel.Stream.markUnavailable();
17
18
  return true;
18
19
  }
19
20
  return false;
@@ -65,14 +66,7 @@ exports.LoadUtils = () => {
65
66
  }
66
67
 
67
68
  if (options.mentionedJidList) {
68
- options.mentionedJidList = await Promise.all(
69
- options.mentionedJidList.map(async (id) => {
70
- const wid = window.Store.WidFactory.createWid(id);
71
- if (await window.Store.QueryExist(wid)) {
72
- return wid;
73
- }
74
- })
75
- );
69
+ options.mentionedJidList = options.mentionedJidList.map((id) => window.Store.WidFactory.createWid(id));
76
70
  options.mentionedJidList = options.mentionedJidList.filter(Boolean);
77
71
  }
78
72
 
@@ -339,14 +333,7 @@ exports.LoadUtils = () => {
339
333
  delete options.extraOptions;
340
334
 
341
335
  if (options.mentionedJidList) {
342
- options.mentionedJidList = await Promise.all(
343
- options.mentionedJidList.map(async (id) => {
344
- const wid = window.Store.WidFactory.createWid(id);
345
- if (await window.Store.QueryExist(wid)) {
346
- return wid;
347
- }
348
- })
349
- );
336
+ options.mentionedJidList = options.mentionedJidList.map((id) => window.Store.WidFactory.createWid(id));
350
337
  options.mentionedJidList = options.mentionedJidList.filter(Boolean);
351
338
  }
352
339
 
@@ -838,22 +825,22 @@ exports.LoadUtils = () => {
838
825
  };
839
826
 
840
827
  window.WWebJS.rejectCall = async (peerJid, id) => {
841
- peerJid = peerJid.split('@')[0] + '@s.whatsapp.net';
842
- let userId = window.Store.User.getMaybeMePnUser().user + '@s.whatsapp.net';
828
+ let userId = window.Store.User.getMaybeMePnUser()._serialized;
829
+
843
830
  const stanza = window.Store.SocketWap.wap('call', {
844
831
  id: window.Store.SocketWap.generateId(),
845
- from: window.Store.SocketWap.USER_JID(userId),
846
- to: window.Store.SocketWap.USER_JID(peerJid),
832
+ from: userId,
833
+ to: peerJid,
847
834
  }, [
848
835
  window.Store.SocketWap.wap('reject', {
849
836
  'call-id': id,
850
- 'call-creator': window.Store.SocketWap.USER_JID(peerJid),
837
+ 'call-creator': peerJid,
851
838
  count: '0',
852
839
  })
853
840
  ]);
854
841
  await window.Store.Socket.deprecatedCastStanza(stanza);
855
842
  };
856
-
843
+
857
844
  window.WWebJS.cropAndResizeImage = async (media, options = {}) => {
858
845
  if (!media.mimetype.includes('image'))
859
846
  throw new Error('Media is not an image');