whatsapp-web.js 1.22.2-alpha.3 → 1.22.2-alpha.4

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
@@ -1,4 +1,4 @@
1
- const { Client, Location, List, Buttons, LocalAuth } = require('./index');
1
+ const { Client, Location, Poll, List, Buttons, LocalAuth } = require('./index');
2
2
 
3
3
  const client = new Client({
4
4
  authStrategy: new LocalAuth(),
@@ -290,6 +290,22 @@ client.on('message', async msg => {
290
290
  client.sendMessage(msg.from, list);
291
291
  } else if (msg.body === '!reaction') {
292
292
  msg.react('👍');
293
+ } else if (msg.body === '!sendpoll') {
294
+ /** By default the poll is created as a single choice poll: */
295
+ await msg.reply(new Poll('Winter or Summer?', ['Winter', 'Summer']));
296
+ /** If you want to provide a multiple choice poll, add allowMultipleAnswers as true: */
297
+ await msg.reply(new Poll('Cats or Dogs?', ['Cats', 'Dogs'], { allowMultipleAnswers: true }));
298
+ /**
299
+ * You can provide a custom message secret, it can be used as a poll ID:
300
+ * @note It has to be a unique vector with a length of 32
301
+ */
302
+ await msg.reply(
303
+ new Poll('Cats or Dogs?', ['Cats', 'Dogs'], {
304
+ messageSecret: [
305
+ 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
306
+ ]
307
+ })
308
+ );
293
309
  } else if (msg.body === '!edit') {
294
310
  if (msg.hasQuotedMsg) {
295
311
  const quotedMsg = await msg.getQuotedMessage();
package/index.d.ts CHANGED
@@ -707,6 +707,7 @@ declare namespace WAWebJS {
707
707
  PROTOCOL = 'protocol',
708
708
  REACTION = 'reaction',
709
709
  TEMPLATE_BUTTON_REPLY = 'template_button_reply',
710
+ POLL_CREATION = 'poll_creation',
710
711
  }
711
712
 
712
713
  /** Client status */
@@ -866,6 +867,11 @@ declare namespace WAWebJS {
866
867
  selectedRowId?: string,
867
868
  /** Returns message in a raw format */
868
869
  rawData: object,
870
+ pollName: string,
871
+ /** Avaiaible poll voting options */
872
+ pollOptions: string[],
873
+ /** False for a single choice poll, true for a multiple choice poll */
874
+ allowMultipleAnswers: boolean,
869
875
  /*
870
876
  * Reloads this Message object's data in-place with the latest values from WhatsApp Web.
871
877
  * Note that the Message must still be in the web app cache for this to work, otherwise will return null.
@@ -946,6 +952,27 @@ declare namespace WAWebJS {
946
952
  constructor(latitude: number, longitude: number, options?: LocationSendOptions)
947
953
  }
948
954
 
955
+ /** Poll send options */
956
+ export interface PollSendOptions {
957
+ /** False for a single choice poll, true for a multiple choice poll (false by default) */
958
+ allowMultipleAnswers?: boolean,
959
+ /**
960
+ * The custom message secret, can be used as a poll ID
961
+ * @note It has to be a unique vector with a length of 32
962
+ */
963
+ messageSecret: ?Array<number>
964
+ }
965
+
966
+ /** Represents a Poll on WhatsApp */
967
+ export interface Poll {
968
+ pollName: string,
969
+ pollOptions: Array<{
970
+ name: string,
971
+ localId: number
972
+ }>,
973
+ options: PollSendOptions
974
+ }
975
+
949
976
  export interface Label {
950
977
  /** Label name */
951
978
  name: string,
@@ -1037,7 +1064,7 @@ declare namespace WAWebJS {
1037
1064
  static fromUrl: (url: string, options?: MediaFromURLOptions) => Promise<MessageMedia>
1038
1065
  }
1039
1066
 
1040
- export type MessageContent = string | MessageMedia | Location | Contact | Contact[] | List | Buttons
1067
+ export type MessageContent = string | MessageMedia | Location | Poll | Contact | Contact[] | List | Buttons
1041
1068
 
1042
1069
  /**
1043
1070
  * Represents a Contact on WhatsApp
package/index.js CHANGED
@@ -18,6 +18,7 @@ module.exports = {
18
18
  BusinessContact: require('./src/structures/BusinessContact'),
19
19
  ClientInfo: require('./src/structures/ClientInfo'),
20
20
  Location: require('./src/structures/Location'),
21
+ Poll: require('./src/structures/Poll'),
21
22
  ProductMetadata: require('./src/structures/ProductMetadata'),
22
23
  List: require('./src/structures/List'),
23
24
  Buttons: require('./src/structures/Buttons'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whatsapp-web.js",
3
- "version": "1.22.2-alpha.3",
3
+ "version": "1.22.2-alpha.4",
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
@@ -11,7 +11,7 @@ const { ExposeStore, LoadUtils } = require('./util/Injected');
11
11
  const ChatFactory = require('./factories/ChatFactory');
12
12
  const ContactFactory = require('./factories/ContactFactory');
13
13
  const WebCacheFactory = require('./webCache/WebCacheFactory');
14
- const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification, Label, Call, Buttons, List, Reaction, Chat } = require('./structures');
14
+ const { ClientInfo, Message, MessageMedia, Contact, Location, Poll, GroupNotification, Label, Call, Buttons, List, Reaction } = require('./structures');
15
15
  const LegacySessionAuth = require('./authStrategies/LegacySessionAuth');
16
16
  const NoAuth = require('./authStrategies/NoAuth');
17
17
 
@@ -620,16 +620,20 @@ class Client extends EventEmitter {
620
620
  }
621
621
  });
622
622
 
623
- await page.exposeFunction('onRemoveChatEvent', (chat) => {
623
+ await page.exposeFunction('onRemoveChatEvent', async (chat) => {
624
+ const _chat = await this.getChatById(chat.id);
625
+
624
626
  /**
625
627
  * Emitted when a chat is removed
626
628
  * @event Client#chat_removed
627
629
  * @param {Chat} chat
628
630
  */
629
- this.emit(Events.CHAT_REMOVED, new Chat(this, chat));
631
+ this.emit(Events.CHAT_REMOVED, _chat);
630
632
  });
631
633
 
632
- await page.exposeFunction('onArchiveChatEvent', (chat, currState, prevState) => {
634
+ await page.exposeFunction('onArchiveChatEvent', async (chat, currState, prevState) => {
635
+ const _chat = await this.getChatById(chat.id);
636
+
633
637
  /**
634
638
  * Emitted when a chat is archived/unarchived
635
639
  * @event Client#chat_archived
@@ -637,7 +641,7 @@ class Client extends EventEmitter {
637
641
  * @param {boolean} currState
638
642
  * @param {boolean} prevState
639
643
  */
640
- this.emit(Events.CHAT_ARCHIVED, new Chat(this, chat), currState, prevState);
644
+ this.emit(Events.CHAT_ARCHIVED, _chat, currState, prevState);
641
645
  });
642
646
 
643
647
  await page.exposeFunction('onEditMessageEvent', (msg, newBody, prevBody) => {
@@ -816,7 +820,7 @@ class Client extends EventEmitter {
816
820
  /**
817
821
  * Send a message to a specific chatId
818
822
  * @param {string} chatId
819
- * @param {string|MessageMedia|Location|Contact|Array<Contact>|Buttons|List} content
823
+ * @param {string|MessageMedia|Location|Poll|Contact|Array<Contact>|Buttons|List} content
820
824
  * @param {MessageSendOptions} [options] - Options used when sending the message
821
825
  *
822
826
  * @returns {Promise<Message>} Message that was just sent
@@ -853,6 +857,9 @@ class Client extends EventEmitter {
853
857
  } else if (content instanceof Location) {
854
858
  internalOptions.location = content;
855
859
  content = '';
860
+ } else if (content instanceof Poll) {
861
+ internalOptions.poll = content;
862
+ content = '';
856
863
  } else if (content instanceof Contact) {
857
864
  internalOptions.contactCard = content.id._serialized;
858
865
  content = '';
@@ -51,7 +51,7 @@ class Message extends Base {
51
51
  * Message content
52
52
  * @type {string}
53
53
  */
54
- this.body = this.hasMedia ? data.caption || '' : data.body || '';
54
+ this.body = this.hasMedia ? data.caption || '' : data.body || data.pollName || '';
55
55
 
56
56
  /**
57
57
  * Message type
@@ -271,6 +271,20 @@ class Message extends Base {
271
271
  this.selectedRowId = data.listResponse.singleSelectReply.selectedRowId;
272
272
  }
273
273
 
274
+ if (this.type === MessageTypes.POLL_CREATION) {
275
+ this.pollName = data.pollName;
276
+ this.pollOptions = data.pollOptions;
277
+ this.allowMultipleAnswers = Boolean(!data.pollSelectableOptionsCount);
278
+ this.pollInvalidated = data.pollInvalidated;
279
+ this.isSentCagPollCreation = data.isSentCagPollCreation;
280
+
281
+ delete this._data.pollName;
282
+ delete this._data.pollOptions;
283
+ delete this._data.pollSelectableOptionsCount;
284
+ delete this._data.pollInvalidated;
285
+ delete this._data.isSentCagPollCreation;
286
+ }
287
+
274
288
  return super._patch(data);
275
289
  }
276
290
 
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Poll send options
5
+ * @typedef {Object} PollSendOptions
6
+ * @property {boolean} [allowMultipleAnswers=false] If false it is a single choice poll, otherwise it is a multiple choice poll (false by default)
7
+ * @property {?Array<number>} messageSecret The custom message secret, can be used as a poll ID. NOTE: it has to be a unique vector with a length of 32
8
+ */
9
+
10
+ /** Represents a Poll on WhatsApp */
11
+ class Poll {
12
+ /**
13
+ * @param {string} pollName
14
+ * @param {Array<string>} pollOptions
15
+ * @param {PollSendOptions} options
16
+ */
17
+ constructor(pollName, pollOptions, options = {}) {
18
+ /**
19
+ * The name of the poll
20
+ * @type {string}
21
+ */
22
+ this.pollName = pollName.trim();
23
+
24
+ /**
25
+ * The array of poll options
26
+ * @type {Array.<{name: string, localId: number}>}
27
+ */
28
+ this.pollOptions = pollOptions.map((option, index) => ({
29
+ name: option.trim(),
30
+ localId: index
31
+ }));
32
+
33
+ /**
34
+ * The send options for the poll
35
+ * @type {PollSendOptions}
36
+ */
37
+ this.options = {
38
+ allowMultipleAnswers: options.allowMultipleAnswers === true,
39
+ messageSecret: options.messageSecret
40
+ };
41
+ }
42
+ }
43
+
44
+ module.exports = Poll;
@@ -19,4 +19,5 @@ module.exports = {
19
19
  List: require('./List'),
20
20
  Payment: require('./Payment'),
21
21
  Reaction: require('./Reaction'),
22
+ Poll: require('./Poll'),
22
23
  };
@@ -108,6 +108,7 @@ exports.MessageTypes = {
108
108
  PROTOCOL: 'protocol',
109
109
  REACTION: 'reaction',
110
110
  TEMPLATE_BUTTON_REPLY: 'template_button_reply',
111
+ POLL_CREATION: 'poll_creation',
111
112
  };
112
113
 
113
114
  /**
@@ -142,7 +142,7 @@ exports.ExposeStore = (moduleRaidStr) => {
142
142
  const modifiedFunction = (...args) => callback(originalFunction, ...args);
143
143
  module[target.index][target.property] = modifiedFunction;
144
144
  };
145
-
145
+
146
146
  window.injectToFunction({ moduleId: 'mediaTypeFromProtobuf', index: 0, property: 'mediaTypeFromProtobuf' }, (func, ...args) => { const [proto] = args; return proto.locationMessage ? null : func(...args); });
147
147
 
148
148
  window.injectToFunction({ moduleId: 'typeAttributeFromProtobuf', index: 0, property: 'typeAttributeFromProtobuf' }, (func, ...args) => { const [proto] = args; return proto.locationMessage || proto.groupInviteMessage ? 'text' : func(...args); });
@@ -215,6 +215,23 @@ exports.LoadUtils = () => {
215
215
  delete options.location;
216
216
  }
217
217
 
218
+ let _pollOptions = {};
219
+ if (options.poll) {
220
+ const { pollName, pollOptions } = options.poll;
221
+ const { allowMultipleAnswers, messageSecret } = options.poll.options;
222
+ _pollOptions = {
223
+ type: 'poll_creation',
224
+ pollName: pollName,
225
+ pollOptions: pollOptions,
226
+ pollSelectableOptionsCount: allowMultipleAnswers ? 0 : 1,
227
+ messageSecret:
228
+ Array.isArray(messageSecret) && messageSecret.length === 32
229
+ ? new Uint8Array(messageSecret)
230
+ : window.crypto.getRandomValues(new Uint8Array(32))
231
+ };
232
+ delete options.poll;
233
+ }
234
+
218
235
  let vcardOptions = {};
219
236
  if (options.contactCard) {
220
237
  let contact = window.Store.Contact.get(options.contactCard);
@@ -334,6 +351,7 @@ exports.LoadUtils = () => {
334
351
  type: 'chat',
335
352
  ...ephemeralFields,
336
353
  ...locationOptions,
354
+ ..._pollOptions,
337
355
  ...attOptions,
338
356
  ...(attOptions.toJSON ? attOptions.toJSON() : {}),
339
357
  ...quotedMsgOptions,