getContactDeviceCount(userId) → Promise containing number
Get user device count by ID
Each WaWeb Connection counts as one device, and the phone (if exists) counts as one
So for a non-enterprise user with one WaWeb connection it should return "2"
@@ -1151,7 +1166,7 @@
-
contactId
+
userId
string
@@ -1168,7 +1183,7 @@
Returns
-
number
+
Promise containing number
async
@@ -1485,35 +1500,6 @@
inject()
Injection logic
Private function
-
-
Property
-
-
-
-
Name
-
Type
-
Optional
-
Description
-
-
-
-
-
-
reinject
-
-
-
boolean
-
-
-
-
-
-
is this a reinject?
-
-
-
-
-
async
@@ -2235,6 +2221,45 @@
async
+
syncHistory(chatId) → Promise containing boolean
+
Sync chat history conversation
+
+
Parameter
+
+
+
+
Name
+
Type
+
Optional
+
Description
+
+
+
+
+
+
chatId
+
+
+
string
+
+
+
+
+
+
+
+
+
+
+
+
Returns
+
+
Promise containing boolean
+
True if operation completed successfully, false otherwise.
+
+
+
+
async
unarchiveChat() → boolean
Changes and returns the archive state of the Chat
@@ -3555,7 +3580,7 @@
diff --git a/docs/Client.js.html b/docs/Client.js.html
index ec7519e..31ef936 100644
--- a/docs/Client.js.html
+++ b/docs/Client.js.html
@@ -4,7 +4,7 @@
- whatsapp-web.js 1.26.0 » Source: Client.js
+ whatsapp-web.js 1.26.1-alpha.2 » Source: Client.js
@@ -15,7 +15,7 @@
@@ -46,8 +46,9 @@ const { LoadUtils } = require('./util/Injected/Utils');
const ChatFactory = require('./factories/ChatFactory');
const ContactFactory = require('./factories/ContactFactory');
const WebCacheFactory = require('./webCache/WebCacheFactory');
-const { ClientInfo, Message, MessageMedia, Contact, Location, Poll, PollVote, GroupNotification, Label, Call, Buttons, List, Reaction } = require('./structures');
+const { ClientInfo, Message, MessageMedia, Contact, Location, Poll, PollVote, GroupNotification, Label, Call, Buttons, List, Reaction, Broadcast} = require('./structures');
const NoAuth = require('./authStrategies/NoAuth');
+const {exposeFunctionIfAbsent} = require('./util/Puppeteer');
/**
* Starting point for interacting with the WhatsApp Web API
@@ -121,9 +122,8 @@ class Client extends EventEmitter {
/**
* Injection logic
* Private function
- * @property {boolean} reinject is this a reinject?
*/
- async inject(reinject = false) {
+ async inject() {
await this.pupPage.waitForFunction('window.Debug?.VERSION != undefined', {timeout: this.options.authTimeoutMs});
const version = await this.getWWebVersion();
@@ -173,26 +173,21 @@ class Client extends EventEmitter {
// Register qr events
let qrRetries = 0;
- const injected = await this.pupPage.evaluate(() => {
- return typeof window.onQRChangedEvent !== 'undefined';
- });
- if (!injected) {
- await this.pupPage.exposeFunction('onQRChangedEvent', async (qr) => {
- /**
- * Emitted when a QR code is received
- * @event Client#qr
- * @param {string} qr QR Code
- */
- this.emit(Events.QR_RECEIVED, qr);
- if (this.options.qrMaxRetries > 0) {
- qrRetries++;
- if (qrRetries > this.options.qrMaxRetries) {
- this.emit(Events.DISCONNECTED, 'Max qrcode retries reached');
- await this.destroy();
- }
+ await exposeFunctionIfAbsent(this.pupPage, 'onQRChangedEvent', async (qr) => {
+ /**
+ * Emitted when a QR code is received
+ * @event Client#qr
+ * @param {string} qr QR Code
+ */
+ this.emit(Events.QR_RECEIVED, qr);
+ if (this.options.qrMaxRetries > 0) {
+ qrRetries++;
+ if (qrRetries > this.options.qrMaxRetries) {
+ this.emit(Events.DISCONNECTED, 'Max qrcode retries reached');
+ await this.destroy();
}
- });
- }
+ }
+ });
await this.pupPage.evaluate(async () => {
@@ -209,86 +204,78 @@ class Client extends EventEmitter {
});
}
- if (!reinject) {
- await this.pupPage.exposeFunction('onAuthAppStateChangedEvent', async (state) => {
- if (state == 'UNPAIRED_IDLE') {
- // refresh qr code
- window.Store.Cmd.refreshQR();
- }
- });
+ await exposeFunctionIfAbsent(this.pupPage, 'onAuthAppStateChangedEvent', async (state) => {
+ if (state == 'UNPAIRED_IDLE') {
+ // refresh qr code
+ window.Store.Cmd.refreshQR();
+ }
+ });
- await this.pupPage.exposeFunction('onAppStateHasSyncedEvent', async () => {
- const authEventPayload = await this.authStrategy.getAuthEventPayload();
- /**
+ await exposeFunctionIfAbsent(this.pupPage, 'onAppStateHasSyncedEvent', async () => {
+ const authEventPayload = await this.authStrategy.getAuthEventPayload();
+ /**
* Emitted when authentication is successful
* @event Client#authenticated
*/
- this.emit(Events.AUTHENTICATED, authEventPayload);
+ this.emit(Events.AUTHENTICATED, authEventPayload);
- const injected = await this.pupPage.evaluate(async () => {
- return typeof window.Store !== 'undefined' && typeof window.WWebJS !== 'undefined';
- });
+ const injected = await this.pupPage.evaluate(async () => {
+ return typeof window.Store !== 'undefined' && typeof window.WWebJS !== 'undefined';
+ });
- if (!injected) {
- if (this.options.webVersionCache.type === 'local' && this.currentIndexHtml) {
- const { type: webCacheType, ...webCacheOptions } = this.options.webVersionCache;
- const webCache = WebCacheFactory.createWebCache(webCacheType, webCacheOptions);
+ if (!injected) {
+ if (this.options.webVersionCache.type === 'local' && this.currentIndexHtml) {
+ const { type: webCacheType, ...webCacheOptions } = this.options.webVersionCache;
+ const webCache = WebCacheFactory.createWebCache(webCacheType, webCacheOptions);
- await webCache.persist(this.currentIndexHtml, version);
- }
+ await webCache.persist(this.currentIndexHtml, version);
+ }
- if (isCometOrAbove) {
- await this.pupPage.evaluate(ExposeStore);
- } else {
- // make sure all modules are ready before injection
- // 2 second delay after authentication makes sense and does not need to be made dyanmic or removed
- await new Promise(r => setTimeout(r, 2000));
- await this.pupPage.evaluate(ExposeLegacyStore);
- }
+ if (isCometOrAbove) {
+ await this.pupPage.evaluate(ExposeStore);
+ } else {
+ // make sure all modules are ready before injection
+ // 2 second delay after authentication makes sense and does not need to be made dyanmic or removed
+ await new Promise(r => setTimeout(r, 2000));
+ await this.pupPage.evaluate(ExposeLegacyStore);
+ }
- // Check window.Store Injection
- await this.pupPage.waitForFunction('window.Store != undefined');
+ // Check window.Store Injection
+ await this.pupPage.waitForFunction('window.Store != undefined');
- /**
+ /**
* Current connection information
* @type {ClientInfo}
*/
- this.info = new ClientInfo(this, await this.pupPage.evaluate(() => {
- return { ...window.Store.Conn.serialize(), wid: window.Store.User.getMeUser() };
- }));
+ this.info = new ClientInfo(this, await this.pupPage.evaluate(() => {
+ return { ...window.Store.Conn.serialize(), wid: window.Store.User.getMeUser() };
+ }));
- this.interface = new InterfaceController(this);
+ this.interface = new InterfaceController(this);
- //Load util functions (serializers, helper functions)
- await this.pupPage.evaluate(LoadUtils);
+ //Load util functions (serializers, helper functions)
+ await this.pupPage.evaluate(LoadUtils);
- await this.attachEventListeners(reinject);
- reinject = true;
- }
- /**
+ await this.attachEventListeners();
+ }
+ /**
* Emitted when the client has initialized and is ready to receive messages.
* @event Client#ready
*/
- this.emit(Events.READY);
- this.authStrategy.afterAuthReady();
- });
- let lastPercent = null;
- await this.pupPage.exposeFunction('onOfflineProgressUpdateEvent', async (percent) => {
- if (lastPercent !== percent) {
- lastPercent = percent;
- this.emit(Events.LOADING_SCREEN, percent, 'WhatsApp'); // Message is hardcoded as "WhatsApp" for now
- }
- });
- }
- const logoutCatchInjected = await this.pupPage.evaluate(() => {
- return typeof window.onLogoutEvent !== 'undefined';
+ this.emit(Events.READY);
+ this.authStrategy.afterAuthReady();
+ });
+ let lastPercent = null;
+ await exposeFunctionIfAbsent(this.pupPage, 'onOfflineProgressUpdateEvent', async (percent) => {
+ if (lastPercent !== percent) {
+ lastPercent = percent;
+ this.emit(Events.LOADING_SCREEN, percent, 'WhatsApp'); // Message is hardcoded as "WhatsApp" for now
+ }
+ });
+ await exposeFunctionIfAbsent(this.pupPage, 'onLogoutEvent', async () => {
+ this.lastLoggedOut = true;
+ await this.pupPage.waitForNavigation({waitUntil: 'load', timeout: 5000}).catch((_) => _);
});
- if (!logoutCatchInjected) {
- await this.pupPage.exposeFunction('onLogoutEvent', async () => {
- this.lastLoggedOut = true;
- await this.pupPage.waitForNavigation({waitUntil: 'load', timeout: 5000}).catch((_) => _);
- });
- }
await this.pupPage.evaluate(() => {
window.AuthStore.AppState.on('change:state', (_AppState, state) => { window.onAuthAppStateChangedEvent(state); });
window.AuthStore.AppState.on('change:hasSynced', () => { window.onAppStateHasSyncedEvent(); });
@@ -380,7 +367,7 @@ class Client extends EventEmitter {
await this.authStrategy.afterBrowserInitialized();
this.lastLoggedOut = false;
}
- await this.inject(true);
+ await this.inject();
});
}
@@ -403,34 +390,33 @@ class Client extends EventEmitter {
* Private function
* @property {boolean} reinject is this a reinject?
*/
- async attachEventListeners(reinject = false) {
- if (!reinject) {
- await this.pupPage.exposeFunction('onAddMessageEvent', msg => {
- if (msg.type === 'gp2') {
- const notification = new GroupNotification(this, msg);
- if (['add', 'invite', 'linked_group_join'].includes(msg.subtype)) {
- /**
+ async attachEventListeners() {
+ await exposeFunctionIfAbsent(this.pupPage, 'onAddMessageEvent', msg => {
+ if (msg.type === 'gp2') {
+ const notification = new GroupNotification(this, msg);
+ if (['add', 'invite', 'linked_group_join'].includes(msg.subtype)) {
+ /**
* Emitted when a user joins the chat via invite link or is added by an admin.
* @event Client#group_join
* @param {GroupNotification} notification GroupNotification with more information about the action
*/
- this.emit(Events.GROUP_JOIN, notification);
- } else if (msg.subtype === 'remove' || msg.subtype === 'leave') {
- /**
+ this.emit(Events.GROUP_JOIN, notification);
+ } else if (msg.subtype === 'remove' || msg.subtype === 'leave') {
+ /**
* Emitted when a user leaves the chat or is removed by an admin.
* @event Client#group_leave
* @param {GroupNotification} notification GroupNotification with more information about the action
*/
- this.emit(Events.GROUP_LEAVE, notification);
- } else if (msg.subtype === 'promote' || msg.subtype === 'demote') {
- /**
+ this.emit(Events.GROUP_LEAVE, notification);
+ } else if (msg.subtype === 'promote' || msg.subtype === 'demote') {
+ /**
* Emitted when a current user is promoted to an admin or demoted to a regular user.
* @event Client#group_admin_changed
* @param {GroupNotification} notification GroupNotification with more information about the action
*/
- this.emit(Events.GROUP_ADMIN_CHANGED, notification);
- } else if (msg.subtype === 'membership_approval_request') {
- /**
+ this.emit(Events.GROUP_ADMIN_CHANGED, notification);
+ } else if (msg.subtype === 'membership_approval_request') {
+ /**
* Emitted when some user requested to join the group
* that has the membership approval mode turned on
* @event Client#group_membership_request
@@ -439,86 +425,86 @@ class Client extends EventEmitter {
* @param {string} notification.author The user ID that made a request
* @param {number} notification.timestamp The timestamp the request was made at
*/
- this.emit(Events.GROUP_MEMBERSHIP_REQUEST, notification);
- } else {
- /**
+ this.emit(Events.GROUP_MEMBERSHIP_REQUEST, notification);
+ } else {
+ /**
* Emitted when group settings are updated, such as subject, description or picture.
* @event Client#group_update
* @param {GroupNotification} notification GroupNotification with more information about the action
*/
- this.emit(Events.GROUP_UPDATE, notification);
- }
- return;
+ this.emit(Events.GROUP_UPDATE, notification);
}
+ return;
+ }
- const message = new Message(this, msg);
+ const message = new Message(this, msg);
- /**
+ /**
* Emitted when a new message is created, which may include the current user's own messages.
* @event Client#message_create
* @param {Message} message The message that was created
*/
- this.emit(Events.MESSAGE_CREATE, message);
+ this.emit(Events.MESSAGE_CREATE, message);
- if (msg.id.fromMe) return;
+ if (msg.id.fromMe) return;
- /**
+ /**
* Emitted when a new message is received.
* @event Client#message
* @param {Message} message The message that was received
*/
- this.emit(Events.MESSAGE_RECEIVED, message);
- });
+ this.emit(Events.MESSAGE_RECEIVED, message);
+ });
- let last_message;
+ let last_message;
- await this.pupPage.exposeFunction('onChangeMessageTypeEvent', (msg) => {
+ await exposeFunctionIfAbsent(this.pupPage, 'onChangeMessageTypeEvent', (msg) => {
- if (msg.type === 'revoked') {
- const message = new Message(this, msg);
- let revoked_msg;
- if (last_message && msg.id.id === last_message.id.id) {
- revoked_msg = new Message(this, last_message);
- }
+ if (msg.type === 'revoked') {
+ const message = new Message(this, msg);
+ let revoked_msg;
+ if (last_message && msg.id.id === last_message.id.id) {
+ revoked_msg = new Message(this, last_message);
+ }
- /**
+ /**
* Emitted when a message is deleted for everyone in the chat.
* @event Client#message_revoke_everyone
* @param {Message} message The message that was revoked, in its current state. It will not contain the original message's data.
* @param {?Message} revoked_msg The message that was revoked, before it was revoked. It will contain the message's original data.
* Note that due to the way this data is captured, it may be possible that this param will be undefined.
*/
- this.emit(Events.MESSAGE_REVOKED_EVERYONE, message, revoked_msg);
- }
+ this.emit(Events.MESSAGE_REVOKED_EVERYONE, message, revoked_msg);
+ }
- });
+ });
- await this.pupPage.exposeFunction('onChangeMessageEvent', (msg) => {
+ await exposeFunctionIfAbsent(this.pupPage, 'onChangeMessageEvent', (msg) => {
- if (msg.type !== 'revoked') {
- last_message = msg;
- }
+ if (msg.type !== 'revoked') {
+ last_message = msg;
+ }
- /**
+ /**
* The event notification that is received when one of
* the group participants changes their phone number.
*/
- const isParticipant = msg.type === 'gp2' && msg.subtype === 'modify';
+ const isParticipant = msg.type === 'gp2' && msg.subtype === 'modify';
- /**
+ /**
* The event notification that is received when one of
* the contacts changes their phone number.
*/
- const isContact = msg.type === 'notification_template' && msg.subtype === 'change_number';
+ const isContact = msg.type === 'notification_template' && msg.subtype === 'change_number';
- if (isParticipant || isContact) {
- /** @type {GroupNotification} object does not provide enough information about this event, so a @type {Message} object is used. */
- const message = new Message(this, msg);
+ if (isParticipant || isContact) {
+ /** @type {GroupNotification} object does not provide enough information about this event, so a @type {Message} object is used. */
+ const message = new Message(this, msg);
- const newId = isParticipant ? msg.recipients[0] : msg.to;
- const oldId = isParticipant ? msg.author : msg.templateParams.find(id => id !== newId);
+ const newId = isParticipant ? msg.recipients[0] : msg.to;
+ const oldId = isParticipant ? msg.author : msg.templateParams.find(id => id !== newId);
- /**
+ /**
* Emitted when a contact or a group participant changes their phone number.
* @event Client#contact_changed
* @param {Message} message Message with more information about the event.
@@ -527,98 +513,98 @@ class Client extends EventEmitter {
* @param {String} newId The user's new id after the change.
* @param {Boolean} isContact Indicates if a contact or a group participant changed their phone number.
*/
- this.emit(Events.CONTACT_CHANGED, message, oldId, newId, isContact);
- }
- });
+ this.emit(Events.CONTACT_CHANGED, message, oldId, newId, isContact);
+ }
+ });
- await this.pupPage.exposeFunction('onRemoveMessageEvent', (msg) => {
+ await exposeFunctionIfAbsent(this.pupPage, 'onRemoveMessageEvent', (msg) => {
- if (!msg.isNewMsg) return;
+ if (!msg.isNewMsg) return;
- const message = new Message(this, msg);
+ const message = new Message(this, msg);
- /**
+ /**
* Emitted when a message is deleted by the current user.
* @event Client#message_revoke_me
* @param {Message} message The message that was revoked
*/
- this.emit(Events.MESSAGE_REVOKED_ME, message);
+ this.emit(Events.MESSAGE_REVOKED_ME, message);
- });
+ });
- await this.pupPage.exposeFunction('onMessageAckEvent', (msg, ack) => {
+ await exposeFunctionIfAbsent(this.pupPage, 'onMessageAckEvent', (msg, ack) => {
- const message = new Message(this, msg);
+ const message = new Message(this, msg);
- /**
+ /**
* Emitted when an ack event occurrs on message type.
* @event Client#message_ack
* @param {Message} message The message that was affected
* @param {MessageAck} ack The new ACK value
*/
- this.emit(Events.MESSAGE_ACK, message, ack);
+ this.emit(Events.MESSAGE_ACK, message, ack);
- });
+ });
- await this.pupPage.exposeFunction('onChatUnreadCountEvent', async (data) =>{
- const chat = await this.getChatById(data.id);
+ await exposeFunctionIfAbsent(this.pupPage, 'onChatUnreadCountEvent', async (data) =>{
+ const chat = await this.getChatById(data.id);
- /**
+ /**
* Emitted when the chat unread count changes
*/
- this.emit(Events.UNREAD_COUNT, chat);
- });
+ this.emit(Events.UNREAD_COUNT, chat);
+ });
- await this.pupPage.exposeFunction('onMessageMediaUploadedEvent', (msg) => {
+ await exposeFunctionIfAbsent(this.pupPage, 'onMessageMediaUploadedEvent', (msg) => {
- const message = new Message(this, msg);
+ const message = new Message(this, msg);
- /**
+ /**
* Emitted when media has been uploaded for a message sent by the client.
* @event Client#media_uploaded
* @param {Message} message The message with media that was uploaded
*/
- this.emit(Events.MEDIA_UPLOADED, message);
- });
+ this.emit(Events.MEDIA_UPLOADED, message);
+ });
- await this.pupPage.exposeFunction('onAppStateChangedEvent', async (state) => {
- /**
+ await exposeFunctionIfAbsent(this.pupPage, 'onAppStateChangedEvent', async (state) => {
+ /**
* Emitted when the connection state changes
* @event Client#change_state
* @param {WAState} state the new connection state
*/
- this.emit(Events.STATE_CHANGED, state);
+ this.emit(Events.STATE_CHANGED, state);
- const ACCEPTED_STATES = [WAState.CONNECTED, WAState.OPENING, WAState.PAIRING, WAState.TIMEOUT];
+ const ACCEPTED_STATES = [WAState.CONNECTED, WAState.OPENING, WAState.PAIRING, WAState.TIMEOUT];
- if (this.options.takeoverOnConflict) {
- ACCEPTED_STATES.push(WAState.CONFLICT);
+ if (this.options.takeoverOnConflict) {
+ ACCEPTED_STATES.push(WAState.CONFLICT);
- if (state === WAState.CONFLICT) {
- setTimeout(() => {
- this.pupPage.evaluate(() => window.Store.AppState.takeover());
- }, this.options.takeoverTimeoutMs);
- }
+ if (state === WAState.CONFLICT) {
+ setTimeout(() => {
+ this.pupPage.evaluate(() => window.Store.AppState.takeover());
+ }, this.options.takeoverTimeoutMs);
}
+ }
- if (!ACCEPTED_STATES.includes(state)) {
- /**
+ if (!ACCEPTED_STATES.includes(state)) {
+ /**
* Emitted when the client has been disconnected
* @event Client#disconnected
* @param {WAState|"LOGOUT"} reason reason that caused the disconnect
*/
- await this.authStrategy.disconnect();
- this.emit(Events.DISCONNECTED, state);
- this.destroy();
- }
- });
+ await this.authStrategy.disconnect();
+ this.emit(Events.DISCONNECTED, state);
+ this.destroy();
+ }
+ });
- await this.pupPage.exposeFunction('onBatteryStateChangedEvent', (state) => {
- const { battery, plugged } = state;
+ await exposeFunctionIfAbsent(this.pupPage, 'onBatteryStateChangedEvent', (state) => {
+ const { battery, plugged } = state;
- if (battery === undefined) return;
+ if (battery === undefined) return;
- /**
+ /**
* Emitted when the battery percentage for the attached device changes. Will not be sent if using multi-device.
* @event Client#change_battery
* @param {object} batteryInfo
@@ -626,11 +612,11 @@ class Client extends EventEmitter {
* @param {boolean} batteryInfo.plugged - Indicates if the phone is plugged in (true) or not (false)
* @deprecated
*/
- this.emit(Events.BATTERY_CHANGED, { battery, plugged });
- });
+ this.emit(Events.BATTERY_CHANGED, { battery, plugged });
+ });
- await this.pupPage.exposeFunction('onIncomingCall', (call) => {
- /**
+ await exposeFunctionIfAbsent(this.pupPage, 'onIncomingCall', (call) => {
+ /**
* Emitted when a call is received
* @event Client#incoming_call
* @param {object} call
@@ -643,13 +629,13 @@ class Client extends EventEmitter {
* @param {boolean} call.webClientShouldHandle - If Waweb should handle
* @param {object} call.participants - Participants
*/
- const cll = new Call(this, call);
- this.emit(Events.INCOMING_CALL, cll);
- });
+ const cll = new Call(this, call);
+ this.emit(Events.INCOMING_CALL, cll);
+ });
- await this.pupPage.exposeFunction('onReaction', (reactions) => {
- for (const reaction of reactions) {
- /**
+ await exposeFunctionIfAbsent(this.pupPage, 'onReaction', (reactions) => {
+ for (const reaction of reactions) {
+ /**
* Emitted when a reaction is sent, received, updated or removed
* @event Client#message_reaction
* @param {object} reaction
@@ -664,61 +650,60 @@ class Client extends EventEmitter {
* @param {?number} reaction.ack - Ack
*/
- this.emit(Events.MESSAGE_REACTION, new Reaction(this, reaction));
- }
- });
+ this.emit(Events.MESSAGE_REACTION, new Reaction(this, reaction));
+ }
+ });
- await this.pupPage.exposeFunction('onRemoveChatEvent', async (chat) => {
- const _chat = await this.getChatById(chat.id);
+ await exposeFunctionIfAbsent(this.pupPage, 'onRemoveChatEvent', async (chat) => {
+ const _chat = await this.getChatById(chat.id);
- /**
+ /**
* Emitted when a chat is removed
* @event Client#chat_removed
* @param {Chat} chat
*/
- this.emit(Events.CHAT_REMOVED, _chat);
- });
+ this.emit(Events.CHAT_REMOVED, _chat);
+ });
- await this.pupPage.exposeFunction('onArchiveChatEvent', async (chat, currState, prevState) => {
- const _chat = await this.getChatById(chat.id);
+ await exposeFunctionIfAbsent(this.pupPage, 'onArchiveChatEvent', async (chat, currState, prevState) => {
+ const _chat = await this.getChatById(chat.id);
- /**
+ /**
* Emitted when a chat is archived/unarchived
* @event Client#chat_archived
* @param {Chat} chat
* @param {boolean} currState
* @param {boolean} prevState
*/
- this.emit(Events.CHAT_ARCHIVED, _chat, currState, prevState);
- });
+ this.emit(Events.CHAT_ARCHIVED, _chat, currState, prevState);
+ });
- await this.pupPage.exposeFunction('onEditMessageEvent', (msg, newBody, prevBody) => {
+ await exposeFunctionIfAbsent(this.pupPage, 'onEditMessageEvent', (msg, newBody, prevBody) => {
- if(msg.type === 'revoked'){
- return;
- }
- /**
+ if(msg.type === 'revoked'){
+ return;
+ }
+ /**
* Emitted when messages are edited
* @event Client#message_edit
* @param {Message} message
* @param {string} newBody
* @param {string} prevBody
*/
- this.emit(Events.MESSAGE_EDIT, new Message(this, msg), newBody, prevBody);
- });
+ this.emit(Events.MESSAGE_EDIT, new Message(this, msg), newBody, prevBody);
+ });
- await this.pupPage.exposeFunction('onAddMessageCiphertextEvent', msg => {
+ await exposeFunctionIfAbsent(this.pupPage, 'onAddMessageCiphertextEvent', msg => {
- /**
+ /**
* Emitted when messages are edited
* @event Client#message_ciphertext
* @param {Message} message
*/
- this.emit(Events.MESSAGE_CIPHERTEXT, new Message(this, msg));
- });
- }
+ this.emit(Events.MESSAGE_CIPHERTEXT, new Message(this, msg));
+ });
- await this.pupPage.exposeFunction('onPollVoteEvent', (vote) => {
+ await exposeFunctionIfAbsent(this.pupPage, 'onPollVoteEvent', (vote) => {
const _vote = new PollVote(this, vote);
/**
* Emitted when some poll option is selected or deselected,
@@ -1518,6 +1503,17 @@ class Client extends EventEmitter {
return labels.map(data => new Label(this, data));
}
+
+ /**
+ * Get all current Broadcast
+ * @returns {Promise<Array<Broadcast>>}
+ */
+ async getBroadcasts() {
+ const broadcasts = await this.pupPage.evaluate(async () => {
+ return window.WWebJS.getAllStatuses();
+ });
+ return broadcasts.map(data => new Broadcast(this, data));
+ }
/**
* Get Label instance by ID
@@ -1760,19 +1756,40 @@ class Client extends EventEmitter {
* Get user device count by ID
* Each WaWeb Connection counts as one device, and the phone (if exists) counts as one
* So for a non-enterprise user with one WaWeb connection it should return "2"
- * @param {string} contactId
- * @returns {number}
+ * @param {string} userId
+ * @returns {Promise<number>}
*/
- async getContactDeviceCount(contactId) {
- let devices = await window.Store.DeviceList.getDeviceIds([window.Store.WidFactory.createWid(contactId)]);
- if(devices && devices.length && devices[0] != null && typeof devices[0].devices == 'object'){
- return devices[0].devices.length;
- }
- return 0;
+ async getContactDeviceCount(userId) {
+ return await this.pupPage.evaluate(async (userId) => {
+ const devices = await window.Store.DeviceList.getDeviceIds([window.Store.WidFactory.createWid(userId)]);
+ if (devices && devices.length && devices[0] != null && typeof devices[0].devices == 'object') {
+ return devices[0].devices.length;
+ }
+ return 0;
+ }, userId);
+ }
+
+ /**
+ * Sync chat history conversation
+ * @param {string} chatId
+ * @return {Promise<boolean>} True if operation completed successfully, false otherwise.
+ */
+ async syncHistory(chatId) {
+ return await this.pupPage.evaluate(async (chatId) => {
+ const chat = await window.WWebJS.getChat(chatId);
+ if (chat.endOfHistoryTransferType === 0) {
+ await window.Store.HistorySync.sendPeerDataOperationRequest(3, {
+ chatId: chat.id
+ });
+ return true;
+ }
+ return false;
+ }, chatId);
}
}
-module.exports = Client;
+module.exports = Client;
+
@@ -1782,7 +1799,7 @@ module.exports = Client;
diff --git a/docs/ClientInfo.html b/docs/ClientInfo.html
index df2c6aa..0cf2985 100644
--- a/docs/ClientInfo.html
+++ b/docs/ClientInfo.html
@@ -4,7 +4,7 @@
- whatsapp-web.js 1.26.0 » Class: ClientInfo
+ whatsapp-web.js 1.26.1-alpha.2 » Class: ClientInfo
@@ -15,7 +15,7 @@
@@ -242,7 +242,7 @@
diff --git a/docs/Contact.html b/docs/Contact.html
index fa564cb..ea6727b 100644
--- a/docs/Contact.html
+++ b/docs/Contact.html
@@ -4,7 +4,7 @@
- whatsapp-web.js 1.26.0 » Class: Contact
+ whatsapp-web.js 1.26.1-alpha.2 » Class: Contact
@@ -15,7 +15,7 @@
@@ -293,7 +293,7 @@
diff --git a/docs/GroupChat.html b/docs/GroupChat.html
index f030c2f..0360c43 100644
--- a/docs/GroupChat.html
+++ b/docs/GroupChat.html
@@ -4,7 +4,7 @@
- whatsapp-web.js 1.26.0 » Class: GroupChat
+ whatsapp-web.js 1.26.1-alpha.2 » Class: GroupChat
@@ -15,7 +15,7 @@
@@ -205,6 +205,9 @@
Expose a function to the page if it does not exist
+
NOTE:
+ Rewrite it to 'upsertFunction' after updating Puppeteer to 20.6 or higher
+ using page.removeExposedFunction
+ https://pptr.dev/api/puppeteer.page.removeExposedFunction