From 979e97ea425b87a8aea7269519f99b7126aac573 Mon Sep 17 00:00:00 2001 From: Pedro Lopez Date: Sun, 27 Feb 2022 23:30:03 -0400 Subject: [PATCH] chore: mark version v1.16.0 --- docs/Base.html | 6 +- docs/BaseAuthStrategy.html | 65 +++ docs/BusinessContact.html | 24 +- docs/Buttons.html | 6 +- docs/Call.html | 6 +- docs/Chat.html | 6 +- docs/Client.html | 280 ++++--------- docs/Client.js.html | 392 ++++++++++-------- docs/ClientInfo.html | 35 +- docs/Contact.html | 24 +- docs/GroupChat.html | 24 +- docs/GroupNotification.html | 6 +- docs/InterfaceController.html | 6 +- docs/Label.html | 6 +- docs/LegacySessionAuth.html | 188 +++++++++ docs/List.html | 6 +- docs/LocalAuth.html | 135 ++++++ docs/Location.html | 6 +- docs/Message.html | 41 +- docs/MessageMedia.html | 6 +- docs/NoAuth.html | 66 +++ docs/Order.html | 6 +- docs/PrivateChat.html | 6 +- docs/PrivateContact.html | 24 +- docs/Product.html | 6 +- docs/Util.html | 8 +- docs/authStrategies_BaseAuthStrategy.js.html | 77 ++++ docs/authStrategies_LegacySessionAuth.js.html | 125 ++++++ docs/authStrategies_LocalAuth.js.html | 107 +++++ docs/authStrategies_NoAuth.js.html | 65 +++ docs/global.html | 8 +- docs/index.html | 257 ++++++++---- docs/scripts/jsdoc-toc.js | 2 +- docs/structures_Base.js.html | 6 +- docs/structures_BusinessContact.js.html | 6 +- docs/structures_Buttons.js.html | 6 +- docs/structures_Call.js.html | 6 +- docs/structures_Chat.js.html | 6 +- docs/structures_ClientInfo.js.html | 19 +- docs/structures_Contact.js.html | 17 +- docs/structures_GroupChat.js.html | 111 +++-- docs/structures_GroupNotification.js.html | 6 +- docs/structures_Label.js.html | 6 +- docs/structures_List.js.html | 6 +- docs/structures_Location.js.html | 6 +- docs/structures_Message.js.html | 95 +++-- docs/structures_MessageMedia.js.html | 6 +- docs/structures_Order.js.html | 6 +- docs/structures_Payment.js.html | 6 +- docs/structures_PrivateChat.js.html | 6 +- docs/structures_PrivateContact.js.html | 6 +- docs/structures_Product.js.html | 6 +- docs/structures_ProductMetadata.js.html | 6 +- docs/util_Constants.js.html | 11 +- docs/util_InterfaceController.js.html | 6 +- docs/util_Util.js.html | 60 +-- package.json | 2 +- 57 files changed, 1719 insertions(+), 723 deletions(-) create mode 100644 docs/BaseAuthStrategy.html create mode 100644 docs/LegacySessionAuth.html create mode 100644 docs/LocalAuth.html create mode 100644 docs/NoAuth.html create mode 100644 docs/authStrategies_BaseAuthStrategy.js.html create mode 100644 docs/authStrategies_LegacySessionAuth.js.html create mode 100644 docs/authStrategies_LocalAuth.js.html create mode 100644 docs/authStrategies_NoAuth.js.html diff --git a/docs/Base.html b/docs/Base.html index 9e3376a..8d543df 100644 --- a/docs/Base.html +++ b/docs/Base.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: Base + whatsapp-web.js 1.16.0 » Class: Base @@ -15,7 +15,7 @@ @@ -50,7 +50,7 @@ diff --git a/docs/BaseAuthStrategy.html b/docs/BaseAuthStrategy.html new file mode 100644 index 0000000..44b1f1a --- /dev/null +++ b/docs/BaseAuthStrategy.html @@ -0,0 +1,65 @@ + + + + + + + whatsapp-web.js 1.16.0 » Class: BaseAuthStrategy + + + + + + + + +
+
+
+
+ +
+
+
+

new BaseAuthStrategy()

+
+
+
+
+
+
+
+ +
+
+ + + + + + + + + + \ No newline at end of file diff --git a/docs/BusinessContact.html b/docs/BusinessContact.html index 2a3b10c..81ec1f6 100644 --- a/docs/BusinessContact.html +++ b/docs/BusinessContact.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: BusinessContact + whatsapp-web.js 1.16.0 » Class: BusinessContact @@ -15,7 +15,7 @@ @@ -111,19 +111,22 @@
+
getCommonGroups()
+
+
getCountryCode()
getFormattedNumber()
-
getProfilePicUrl()
-
-
+
getProfilePicUrl()
+
+
unblock()
@@ -269,6 +272,15 @@
async
+

getCommonGroups() → Promise containing Array of WAWebJS.ChatId

+

Gets the Contact's common groups with you. Returns empty array if you don't have any common group.

+
+
Inherited from
+
Contact#getCommonGroups
+
Returns
+
+
+
async

getCountryCode() → Promise containing string

Returns the contact's countrycode, (1541859685@c.us) => (1)

@@ -314,7 +326,7 @@
diff --git a/docs/Buttons.html b/docs/Buttons.html index 642cdc3..f03eac7 100644 --- a/docs/Buttons.html +++ b/docs/Buttons.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: Buttons + whatsapp-web.js 1.16.0 » Class: Buttons @@ -15,7 +15,7 @@ @@ -234,7 +234,7 @@ Returns: [{ buttonId:'customId',buttonText:{'displayText':&#
diff --git a/docs/Call.html b/docs/Call.html index de50a16..432b0cd 100644 --- a/docs/Call.html +++ b/docs/Call.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: Call + whatsapp-web.js 1.16.0 » Class: Call @@ -15,7 +15,7 @@ @@ -144,7 +144,7 @@
diff --git a/docs/Chat.html b/docs/Chat.html index 1a9cd4b..c2afeea 100644 --- a/docs/Chat.html +++ b/docs/Chat.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: Chat + whatsapp-web.js 1.16.0 » Class: Chat @@ -15,7 +15,7 @@ @@ -483,7 +483,7 @@
diff --git a/docs/Client.html b/docs/Client.html index 0d30a80..dac8f52 100644 --- a/docs/Client.html +++ b/docs/Client.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: Client + whatsapp-web.js 1.16.0 » Class: Client @@ -15,7 +15,7 @@ @@ -26,7 +26,7 @@
async
+

getCommonGroups(contactId) → Promise containing Array of WAWebJS.ChatId

+

Gets the Contact's common groups with you. Returns empty array if you don't have any common group.

+
+

Parameter

+ + + + + + + + + + + + + + + + + +
NameTypeOptionalDescription
+

contactId

+
+

string

+
+

 

+
+

the whatsapp user's ID (_serialized format)

+
+
+
+
Returns
+
+

Promise containing Array of WAWebJS.ChatId 

+
+
+
async

getContactById(contactId) → Promise containing Contact

Get contact instance by ID

@@ -1452,6 +1429,11 @@
async
+

sendPresenceUnavailable()

+

Marks the client as unavailable

+
+
+
async

sendSeen(chatId) → Promise containing boolean

Mark as seen for the Chat

@@ -1491,7 +1473,7 @@
async
-

setDisplayName(displayName)

+

setDisplayName(displayName) → Promise containing Boolean

Sets the current user's display name. This is the name shown to WhatsApp users that have not added you as a contact beside your number in groups and in your profile.

@@ -1524,6 +1506,10 @@
+
Returns
+
+

Promise containing Boolean 

+
async

setStatus(status)

@@ -1650,104 +1636,10 @@

authenticated

Emitted when authentication is successful

-
-

Parameters

- - - - - - - - - - - - - - - - - -
NameTypeOptionalDescription
-

session

-
-

object

-
-

 

-
-

Object containing session information. Can be used to restore the session.

-

Values in session have the following properties:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeOptionalDescription
-

WABrowserId

-
-

string

-
-

 

-
-
-

WASecretBundle

-
-

string

-
-

 

-
-
-

WAToken1

-
-

string

-
-

 

-
-
-

WAToken2

-
-

string

-
-

 

-
-
-
-

change_battery

-

Emitted when the battery percentage for the attached device changes

+

Emitted when the battery percentage for the attached device changes. Will not be sent if using multi-device.

Parameters

@@ -1818,6 +1710,8 @@
+
Deprecated
+

change_state

Emitted when the connection state changes

@@ -2370,7 +2264,7 @@

qr

-

Emitted when the QR code is received

+

Emitted when a QR code is received

Parameter

@@ -2416,7 +2310,7 @@
diff --git a/docs/Client.js.html b/docs/Client.js.html index 74260b7..929584b 100644 --- a/docs/Client.js.html +++ b/docs/Client.js.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Source: Client.js + whatsapp-web.js 1.16.0 » Source: Client.js @@ -15,7 +15,7 @@ @@ -34,7 +34,6 @@ const EventEmitter = require('events'); const puppeteer = require('puppeteer'); const moduleRaid = require('@pedroslopez/moduleraid/moduleraid'); -const jsQR = require('jsqr'); const Util = require('./util/Util'); const InterfaceController = require('./util/InterfaceController'); @@ -42,22 +41,20 @@ const { WhatsWebURL, DefaultOptions, Events, WAState } = require('./ut const { ExposeStore, LoadUtils } = require('./util/Injected'); const ChatFactory = require('./factories/ChatFactory'); const ContactFactory = require('./factories/ContactFactory'); -const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification , Label, Call, Buttons, List} = require('./structures'); +const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification, Label, Call, Buttons, List } = require('./structures'); +const LegacySessionAuth = require('./authStrategies/LegacySessionAuth'); +const NoAuth = require('./authStrategies/NoAuth'); + /** * Starting point for interacting with the WhatsApp Web API * @extends {EventEmitter} * @param {object} options - Client options + * @param {AuthStrategy} options.authStrategy - Determines how to save and restore sessions. Will use LegacySessionAuth if options.session is set. Otherwise, NoAuth will be used. * @param {number} options.authTimeoutMs - Timeout for authentication selector in puppeteer * @param {object} options.puppeteer - Puppeteer launch options. View docs here: https://github.com/puppeteer/puppeteer/ - * @param {number} options.qrRefreshIntervalMs - Refresh interval for qr code (how much time to wait before checking if the qr code has changed) - * @param {number} options.qrTimeoutMs - Timeout for qr code selector in puppeteer * @param {number} options.qrMaxRetries - How many times should the qrcode be refreshed before giving up - * @param {string} options.restartOnAuthFail - Restart client with a new session (i.e. use null 'session' var) if authentication fails - * @param {object} options.session - Whatsapp session to restore. If not set, will start a new session - * @param {string} options.session.WABrowserId - * @param {string} options.session.WASecretBundle - * @param {string} options.session.WAToken1 - * @param {string} options.session.WAToken2 + * @param {string} options.restartOnAuthFail - @deprecated This option should be set directly on the LegacySessionAuth. + * @param {object} options.session - @deprecated Only here for backwards-compatibility. You should move to using LocalAuth, or set the authStrategy to LegacySessionAuth explicitly. * @param {number} options.takeoverOnConflict - If another whatsapp web session is detected (another browser), take over the session in the current browser * @param {number} options.takeoverTimeoutMs - How much time to wait before taking over the session * @param {string} options.userAgent - User agent to use in puppeteer @@ -79,13 +76,33 @@ const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification * @fires Client#group_update * @fires Client#disconnected * @fires Client#change_state - * @fires Client#change_battery */ class Client extends EventEmitter { constructor(options = {}) { super(); this.options = Util.mergeDefault(DefaultOptions, options); + + if(!this.options.authStrategy) { + if(Object.prototype.hasOwnProperty.call(this.options, 'session')) { + process.emitWarning( + 'options.session is deprecated and will be removed in a future release due to incompatibility with multi-device. ' + + 'Use the LocalAuth authStrategy, don\'t pass in a session as an option, or suppress this warning by using the LegacySessionAuth strategy explicitly (see https://wwebjs.dev/guide/authentication.html#legacysessionauth-strategy).', + 'DeprecationWarning' + ); + + this.authStrategy = new LegacySessionAuth({ + session: this.options.session, + restartOnAuthFail: this.options.restartOnAuthFail + }); + } else { + this.authStrategy = new NoAuth(); + } + } else { + this.authStrategy = this.options.authStrategy; + } + + this.authStrategy.setup(this); this.pupBrowser = null; this.pupPage = null; @@ -98,41 +115,25 @@ class Client extends EventEmitter { */ async initialize() { let [browser, page] = [null, null]; - - if(this.options.puppeteer && this.options.puppeteer.browserWSEndpoint) { - browser = await puppeteer.connect(this.options.puppeteer); + + await this.authStrategy.beforeBrowserInitialized(); + + const puppeteerOpts = this.options.puppeteer; + if (puppeteerOpts && puppeteerOpts.browserWSEndpoint) { + browser = await puppeteer.connect(puppeteerOpts); page = await browser.newPage(); } else { - browser = await puppeteer.launch(this.options.puppeteer); + browser = await puppeteer.launch(puppeteerOpts); page = (await browser.pages())[0]; } - + await page.setUserAgent(this.options.userAgent); + if (this.options.bypassCSP) await page.setBypassCSP(true); this.pupBrowser = browser; this.pupPage = page; - // remember me - await page.evaluateOnNewDocument(() => { - localStorage.setItem('remember-me', 'true'); - }); - - if (this.options.session) { - await page.evaluateOnNewDocument( - session => { - if(document.referrer === 'https://whatsapp.com/') { - localStorage.clear(); - localStorage.setItem('WABrowserId', session.WABrowserId); - localStorage.setItem('WASecretBundle', session.WASecretBundle); - localStorage.setItem('WAToken1', session.WAToken1); - localStorage.setItem('WAToken2', session.WAToken2); - } - }, this.options.session); - } - - if(this.options.bypassCSP) { - await page.setBypassCSP(true); - } + await this.authStrategy.afterBrowserInitialized(); await page.goto(WhatsWebURL, { waitUntil: 'load', @@ -140,56 +141,54 @@ class Client extends EventEmitter { referer: 'https://whatsapp.com/' }); - const KEEP_PHONE_CONNECTED_IMG_SELECTOR = '[data-icon="intro-md-beta-logo-dark"], [data-icon="intro-md-beta-logo-light"], [data-asset-intro-image-light="true"], [data-asset-intro-image-dark="true"]'; + const INTRO_IMG_SELECTOR = '[data-testid="intro-md-beta-logo-dark"], [data-testid="intro-md-beta-logo-light"], [data-asset-intro-image-light="true"], [data-asset-intro-image-dark="true"]'; + const INTRO_QRCODE_SELECTOR = 'div[data-ref] canvas'; - if (this.options.session) { - // Check if session restore was successful - try { - await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: this.options.authTimeoutMs }); - } catch (err) { - if (err.name === 'TimeoutError') { - /** - * Emitted when there has been an error while trying to restore an existing session - * @event Client#auth_failure - * @param {string} message - */ - this.emit(Events.AUTHENTICATION_FAILURE, 'Unable to log in. Are the session details valid?'); - browser.close(); - if (this.options.restartOnAuthFail) { - // session restore failed so try again but without session to force new authentication - this.options.session = null; - this.initialize(); - } - return; + // Checks which selector appears first + const needAuthentication = await Promise.race([ + new Promise(resolve => { + page.waitForSelector(INTRO_IMG_SELECTOR, { timeout: this.options.authTimeoutMs }) + .then(() => resolve(false)) + .catch((err) => resolve(err)); + }), + new Promise(resolve => { + page.waitForSelector(INTRO_QRCODE_SELECTOR, { timeout: this.options.authTimeoutMs }) + .then(() => resolve(true)) + .catch((err) => resolve(err)); + }) + ]); + + // Checks if an error ocurred on the first found selector. The second will be discarded and ignored by .race; + if (needAuthentication instanceof Error) throw needAuthentication; + + // Scan-qrcode selector was found. Needs authentication + if (needAuthentication) { + const { failed, failureEventPayload, restart } = await this.authStrategy.onAuthenticationNeeded(); + if(failed) { + /** + * Emitted when there has been an error while trying to restore an existing session + * @event Client#auth_failure + * @param {string} message + */ + this.emit(Events.AUTHENTICATION_FAILURE, failureEventPayload); + await this.destroy(); + if (restart) { + // session restore failed so try again but without session to force new authentication + return this.initialize(); } - - throw err; + return; } - } else { + const QR_CONTAINER = 'div[data-ref]'; + const QR_RETRY_BUTTON = 'div[data-ref] > span > button'; let qrRetries = 0; - - const getQrCode = async () => { - // Check if retry button is present - var QR_RETRY_SELECTOR = 'div[data-ref] > span > button'; - var qrRetry = await page.$(QR_RETRY_SELECTOR); - if (qrRetry) { - await qrRetry.click(); - } - - // Wait for QR Code - const QR_CANVAS_SELECTOR = 'canvas'; - await page.waitForSelector(QR_CANVAS_SELECTOR, { timeout: this.options.qrTimeoutMs }); - const qrImgData = await page.$eval(QR_CANVAS_SELECTOR, canvas => [].slice.call(canvas.getContext('2d').getImageData(0, 0, 264, 264).data)); - const qr = jsQR(qrImgData, 264, 264).data; - + await page.exposeFunction('qrChanged', async (qr) => { /** - * Emitted when the QR code is received + * 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) { @@ -197,15 +196,39 @@ class Client extends EventEmitter { await this.destroy(); } } - }; - getQrCode(); - this._qrRefreshInterval = setInterval(getQrCode, this.options.qrRefreshIntervalMs); + }); + + await page.evaluate(function (selectors) { + const qr_container = document.querySelector(selectors.QR_CONTAINER); + window.qrChanged(qr_container.dataset.ref); + + const obs = new MutationObserver((muts) => { + muts.forEach(mut => { + // Listens to qr token change + if (mut.type === 'attributes' && mut.attributeName === 'data-ref') { + window.qrChanged(mut.target.dataset.ref); + } else + // Listens to retry button, when found, click it + if (mut.type === 'childList') { + const retry_button = document.querySelector(selectors.QR_RETRY_BUTTON); + if (retry_button) retry_button.click(); + } + }); + }); + obs.observe(qr_container.parentElement, { + subtree: true, + childList: true, + attributes: true, + attributeFilter: ['data-ref'], + }); + }, { + QR_CONTAINER, + QR_RETRY_BUTTON + }); // Wait for code scan try { - await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: 0 }); - clearInterval(this._qrRefreshInterval); - this._qrRefreshInterval = undefined; + await page.waitForSelector(INTRO_IMG_SELECTOR, { timeout: 0 }); } catch(error) { if ( error.name === 'ProtocolError' && @@ -218,44 +241,29 @@ class Client extends EventEmitter { throw error; } + } await page.evaluate(ExposeStore, moduleRaid.toString()); - - // Get session tokens - const localStorage = JSON.parse(await page.evaluate(() => { - return JSON.stringify(window.localStorage); - })); - - const session = { - WABrowserId: localStorage.WABrowserId, - WASecretBundle: localStorage.WASecretBundle, - WAToken1: localStorage.WAToken1, - WAToken2: localStorage.WAToken2 - }; + const authEventPayload = await this.authStrategy.getAuthEventPayload(); /** * Emitted when authentication is successful * @event Client#authenticated - * @param {object} session Object containing session information. Can be used to restore the session. - * @param {string} session.WABrowserId - * @param {string} session.WASecretBundle - * @param {string} session.WAToken1 - * @param {string} session.WAToken2 */ - this.emit(Events.AUTHENTICATED, session); + this.emit(Events.AUTHENTICATED, authEventPayload); // Check window.Store Injection await page.waitForFunction('window.Store != undefined'); - const isMD = await page.evaluate(() => { - return window.Store.Features.features.MD_BACKEND; + await page.evaluate(async () => { + // safely unregister service workers + const registrations = await navigator.serviceWorker.getRegistrations(); + for (let registration of registrations) { + registration.unregister(); + } }); - if(isMD) { - throw new Error('Multi-device is not yet supported by whatsapp-web.js. Please check out https://github.com/pedroslopez/whatsapp-web.js/pull/889 to follow the progress.'); - } - //Load util functions (serializers, helper functions) await page.evaluate(LoadUtils); @@ -265,7 +273,7 @@ class Client extends EventEmitter { * @type {ClientInfo} */ this.info = new ClientInfo(this, await page.evaluate(() => { - return window.Store.Conn.serialize(); + return { ...window.Store.Conn.serialize(), wid: window.Store.User.getMeUser() }; })); // Add InterfaceController @@ -429,11 +437,12 @@ class Client extends EventEmitter { if (battery === undefined) return; /** - * Emitted when the battery percentage for the attached device changes + * 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 * @param {number} batteryInfo.battery - The current battery percentage * @param {boolean} batteryInfo.plugged - Indicates if the phone is plugged in (true) or not (false) + * @deprecated */ this.emit(Events.BATTERY_CHANGED, { battery, plugged }); }); @@ -452,14 +461,14 @@ class Client extends EventEmitter { * @param {boolean} call.webClientShouldHandle - If Waweb should handle * @param {object} call.participants - Participants */ - const cll = new Call(this,call); + const cll = new Call(this, call); this.emit(Events.INCOMING_CALL, cll); }); - + await page.evaluate(() => { window.Store.Msg.on('change', (msg) => { window.onChangeMessageEvent(window.WWebJS.getMessageModel(msg)); }); window.Store.Msg.on('change:type', (msg) => { window.onChangeMessageTypeEvent(window.WWebJS.getMessageModel(msg)); }); - window.Store.Msg.on('change:ack', (msg,ack) => { window.onMessageAckEvent(window.WWebJS.getMessageModel(msg), ack); }); + window.Store.Msg.on('change:ack', (msg, ack) => { window.onMessageAckEvent(window.WWebJS.getMessageModel(msg), ack); }); window.Store.Msg.on('change:isUnsentMedia', (msg, unsent) => { if (msg.id.fromMe && !unsent) window.onMessageMediaUploadedEvent(window.WWebJS.getMessageModel(msg)); }); window.Store.Msg.on('remove', (msg) => { if (msg.isNewMsg) window.onRemoveMessageEvent(window.WWebJS.getMessageModel(msg)); }); window.Store.AppState.on('change:state', (_AppState, state) => { window.onAppStateChangedEvent(state); }); @@ -497,9 +506,6 @@ class Client extends EventEmitter { * Closes the client */ async destroy() { - if (this._qrRefreshInterval) { - clearInterval(this._qrRefreshInterval); - } await this.pupBrowser.close(); } @@ -507,9 +513,11 @@ class Client extends EventEmitter { * Logs out the client, closing the current session */ async logout() { - return await this.pupPage.evaluate(() => { + await this.pupPage.evaluate(() => { return window.Store.AppState.logout(); }); + + await this.authStrategy.logout(); } /** @@ -539,7 +547,7 @@ class Client extends EventEmitter { /** * Message options. * @typedef {Object} MessageSendOptions - * @property {boolean} [linkPreview=true] - Show links preview + * @property {boolean} [linkPreview=true] - Show links preview. Has no effect on multi-device accounts. * @property {boolean} [sendAudioAsVoice=false] - Send audio as voice message * @property {boolean} [sendVideoAsGif=false] - Send video as gif * @property {boolean} [sendMediaAsSticker=false] - Send media as a sticker @@ -589,34 +597,36 @@ class Client extends EventEmitter { } else if (content instanceof Location) { internalOptions.location = content; content = ''; - } else if(content instanceof Contact) { + } else if (content instanceof Contact) { internalOptions.contactCard = content.id._serialized; content = ''; - } else if(Array.isArray(content) && content.length > 0 && content[0] instanceof Contact) { + } else if (Array.isArray(content) && content.length > 0 && content[0] instanceof Contact) { internalOptions.contactCardList = content.map(contact => contact.id._serialized); content = ''; - } else if(content instanceof Buttons){ - if(content.type !== 'chat'){internalOptions.attachment = content.body;} + } else if (content instanceof Buttons) { + if (content.type !== 'chat') { internalOptions.attachment = content.body; } internalOptions.buttons = content; content = ''; - } else if(content instanceof List){ + } else if (content instanceof List) { internalOptions.list = content; content = ''; } if (internalOptions.sendMediaAsSticker && internalOptions.attachment) { - internalOptions.attachment = - await Util.formatToWebpSticker(internalOptions.attachment, { + internalOptions.attachment = await Util.formatToWebpSticker( + internalOptions.attachment, { name: options.stickerName, author: options.stickerAuthor, categories: options.stickerCategories - }); + }, this.pupPage + ); } const newMessage = await this.pupPage.evaluate(async (chatId, message, options, sendSeen) => { const chatWid = window.Store.WidFactory.createWid(chatId); const chat = await window.Store.Chat.find(chatWid); + if (sendSeen) { window.WWebJS.sendSeen(chatId); } @@ -703,7 +713,7 @@ class Client extends EventEmitter { */ async getInviteInfo(inviteCode) { return await this.pupPage.evaluate(inviteCode => { - return window.Store.Wap.groupInviteInfo(inviteCode); + return window.Store.InviteInfo.sendQueryGroupInvite(inviteCode); }, inviteCode); } @@ -722,25 +732,25 @@ class Client extends EventEmitter { /** * Accepts a private invitation to join a group - * @param {object} inviteV4 Invite V4 Info + * @param {object} inviteInfo Invite V4 Info * @returns {Promise<Object>} */ async acceptGroupV4Invite(inviteInfo) { - if(!inviteInfo.inviteCode) throw 'Invalid invite code, try passing the message.inviteV4 object'; + if (!inviteInfo.inviteCode) throw 'Invalid invite code, try passing the message.inviteV4 object'; if (inviteInfo.inviteCodeExp == 0) throw 'Expired invite code'; - return await this.pupPage.evaluate(async inviteInfo => { - let { groupId, fromId, inviteCode, inviteCodeExp, toId } = inviteInfo; - return await window.Store.Wap.acceptGroupV4Invite(groupId, fromId, inviteCode, String(inviteCodeExp), toId); + return this.pupPage.evaluate(async inviteInfo => { + let { groupId, fromId, inviteCode, inviteCodeExp } = inviteInfo; + return await window.Store.JoinInviteV4.sendJoinGroupViaInviteV4(inviteCode, String(inviteCodeExp), groupId, fromId); }, inviteInfo); } - + /** * Sets the current user's status message * @param {string} status New status message */ async setStatus(status) { await this.pupPage.evaluate(async status => { - return await window.Store.Wap.sendSetStatus(status); + return await window.Store.StatusUtils.setMyStatus(status); }, status); } @@ -748,11 +758,22 @@ class Client extends EventEmitter { * Sets the current user's display name. * This is the name shown to WhatsApp users that have not added you as a contact beside your number in groups and in your profile. * @param {string} displayName New display name + * @returns {Promise<Boolean>} */ async setDisplayName(displayName) { - await this.pupPage.evaluate(async displayName => { - return await window.Store.Wap.setPushname(displayName); + const couldSet = await this.pupPage.evaluate(async displayName => { + if(!window.Store.Conn.canSetMyPushname()) return false; + + if(window.Store.Features.features.MD_BACKEND) { + // TODO + return false; + } else { + const res = await window.Store.Wap.setPushname(displayName); + return !res.status || res.status === 200; + } }, displayName); + + return couldSet; } /** @@ -771,7 +792,16 @@ class Client extends EventEmitter { */ async sendPresenceAvailable() { return await this.pupPage.evaluate(() => { - return window.Store.Wap.sendPresenceAvailable(); + return window.Store.PresenceUtils.sendPresenceAvailable(); + }); + } + + /** + * Marks the client as unavailable + */ + async sendPresenceUnavailable() { + return await this.pupPage.evaluate(() => { + return window.Store.PresenceUtils.sendPresenceUnavailable(); }); } @@ -878,12 +908,37 @@ class Client extends EventEmitter { */ async getProfilePicUrl(contactId) { const profilePic = await this.pupPage.evaluate((contactId) => { - return window.Store.Wap.profilePicFind(contactId); + const chatWid = window.Store.WidFactory.createWid(contactId); + return window.Store.getProfilePicFull(chatWid); }, contactId); return profilePic ? profilePic.eurl : undefined; } + /** + * Gets the Contact's common groups with you. Returns empty array if you don't have any common group. + * @param {string} contactId the whatsapp user's ID (_serialized format) + * @returns {Promise<WAWebJS.ChatId[]>} + */ + async getCommonGroups(contactId) { + const commonGroups = await this.pupPage.evaluate(async (contactId) => { + const contact = window.Store.Contact.get(contactId); + if (contact.commonGroups) { + return contact.commonGroups.serialize(); + } + const status = await window.Store.findCommonGroups(contact); + if (status) { + return contact.commonGroups.serialize(); + } + return []; + }, contactId); + const chats = []; + for (const group of commonGroups) { + chats.push(group.id); + } + return chats; + } + /** * Force reset of connection state for the client */ @@ -899,10 +954,7 @@ class Client extends EventEmitter { * @returns {Promise<Boolean>} */ async isRegisteredUser(id) { - return await this.pupPage.evaluate(async (id) => { - let result = await window.Store.Wap.queryExist(id); - return result.jid !== undefined; - }, id); + return Boolean(await this.getNumberId(id)); } /** @@ -912,14 +964,15 @@ class Client extends EventEmitter { * @returns {Promise<Object|null>} */ async getNumberId(number) { - if (!number.endsWith('@c.us')) number += '@c.us'; - try { - return await this.pupPage.evaluate(async numberId => { - return window.WWebJS.getNumberId(numberId); - }, number); - } catch(_) { - return null; + if (!number.endsWith('@c.us')) { + number += '@c.us'; } + + return await this.pupPage.evaluate(async number => { + const result = await window.Store.QueryExist(number); + if (!result || result.wid === undefined) return null; + return result.wid; + }, number); } /** @@ -928,14 +981,14 @@ class Client extends EventEmitter { * @returns {Promise<string>} */ async getFormattedNumber(number) { - if(!number.endsWith('@s.whatsapp.net')) number = number.replace('c.us', 's.whatsapp.net'); - if(!number.includes('@s.whatsapp.net')) number = `${number}@s.whatsapp.net`; - + if (!number.endsWith('@s.whatsapp.net')) number = number.replace('c.us', 's.whatsapp.net'); + if (!number.includes('@s.whatsapp.net')) number = `${number}@s.whatsapp.net`; + return await this.pupPage.evaluate(async numberId => { return window.Store.NumberInfo.formattedPhoneNumber(numberId); }, number); } - + /** * Get the country code of a WhatsApp ID. * @param {string} number Number or ID @@ -948,7 +1001,7 @@ class Client extends EventEmitter { return window.Store.NumberInfo.findCC(numberId); }, number); } - + /** * Create a new group * @param {string} name group title @@ -967,12 +1020,9 @@ class Client extends EventEmitter { } const createRes = await this.pupPage.evaluate(async (name, participantIds) => { - const res = await window.Store.Wap.createGroup(name, participantIds); - console.log(res); - if (!res.status === 200) { - throw 'An error occurred while creating the group!'; - } - + const participantWIDs = participantIds.map(p => window.Store.WidFactory.createWid(p)); + const id = window.Store.genId(); + const res = await window.Store.GroupUtils.sendCreateGroup(name, participantWIDs, undefined, id); return res; }, name, participants); @@ -993,9 +1043,9 @@ class Client extends EventEmitter { async getLabels() { const labels = await this.pupPage.evaluate(async () => { return window.WWebJS.getLabels(); - }); + }); - return labels.map(data => new Label(this , data)); + return labels.map(data => new Label(this, data)); } /** @@ -1006,7 +1056,7 @@ class Client extends EventEmitter { async getLabelById(labelId) { const label = await this.pupPage.evaluate(async (labelId) => { return window.WWebJS.getLabel(labelId); - }, labelId); + }, labelId); return new Label(this, label); } @@ -1016,12 +1066,12 @@ class Client extends EventEmitter { * @param {string} chatId * @returns {Promise<Array<Label>>} */ - async getChatLabels(chatId){ + async getChatLabels(chatId) { const labels = await this.pupPage.evaluate(async (chatId) => { return window.WWebJS.getChatLabels(chatId); }, chatId); - return labels.map(data => new Label(this, data)); + return labels.map(data => new Label(this, data)); } /** @@ -1029,16 +1079,16 @@ class Client extends EventEmitter { * @param {string} labelId * @returns {Promise<Array<Chat>>} */ - async getChatsByLabelId(labelId){ + async getChatsByLabelId(labelId) { const chatIds = await this.pupPage.evaluate(async (labelId) => { const label = window.Store.Label.get(labelId); const labelItems = label.labelItemCollection.models; return labelItems.reduce((result, item) => { - if(item.parentType === 'Chat'){ + if (item.parentType === 'Chat') { result.push(item.parentId); } return result; - },[]); + }, []); }, labelId); return Promise.all(chatIds.map(id => this.getChatById(id))); @@ -1051,7 +1101,7 @@ class Client extends EventEmitter { async getBlockedContacts() { const blockedContacts = await this.pupPage.evaluate(() => { let chatIds = window.Store.Blocklist.models.map(a => a.id._serialized); - return Promise.all(chatIds.map(id => window.WWebJS.getContact(id))); + return Promise.all(chatIds.map(id => window.WWebJS.getContact(id))); }); return blockedContacts.map(contact => ContactFactory.create(this.client, contact)); @@ -1069,7 +1119,7 @@ module.exports = Client;
diff --git a/docs/ClientInfo.html b/docs/ClientInfo.html index 15bb01e..5e1933f 100644 --- a/docs/ClientInfo.html +++ b/docs/ClientInfo.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: ClientInfo + whatsapp-web.js 1.16.0 » Class: ClientInfo @@ -15,7 +15,7 @@ @@ -39,31 +39,26 @@
-
me
-
-
phone
-
-
-
-
platform
-
pushname
-
-
+
pushname
+
+
wid
+
+
@@ -93,15 +88,9 @@

Properties

-

me -  object

-
-
Deprecated
-
Use .wid instead
-

phone  object

-

Information about the phone this client is connected to

+

Information about the phone this client is connected to. Not available in multi-device.

Properties

@@ -188,10 +177,12 @@
+
Deprecated
+

platform  string

-

Platform the phone is running on

+

Platform WhatsApp is running on

pushname @@ -211,6 +202,8 @@

getBatteryStatus() → (object, number, or boolean)

Get current battery percentage and charging status for the attached device

+
Deprecated
+
Returns

object  @@ -238,7 +231,7 @@

diff --git a/docs/Contact.html b/docs/Contact.html index d726f30..30e50f3 100644 --- a/docs/Contact.html +++ b/docs/Contact.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: Contact + whatsapp-web.js 1.16.0 » Class: Contact @@ -15,7 +15,7 @@ @@ -108,19 +108,22 @@

+
getProfilePicUrl()
+
+
unblock()
@@ -236,6 +239,15 @@
async
+

getCommonGroups() → Promise containing Array of WAWebJS.ChatId

+

Gets the Contact's common groups with you. Returns empty array if you don't have any common group.

+
+
Returns
+
+

Promise containing Array of WAWebJS.ChatId 

+
+
+
async

getCountryCode() → Promise containing string

Returns the contact's countrycode, (1541859685@c.us) => (1)

@@ -281,7 +293,7 @@
diff --git a/docs/GroupChat.html b/docs/GroupChat.html index 9918ae8..62302fe 100644 --- a/docs/GroupChat.html +++ b/docs/GroupChat.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: GroupChat + whatsapp-web.js 1.16.0 » Class: GroupChat @@ -15,7 +15,7 @@ @@ -645,12 +645,14 @@
async
-

revokeInvite() → Promise

+

revokeInvite() → Promise containing string

Invalidates the current group invite code and generates a new one

Returns
-

Promise 

+

Promise containing string  +

New invite code

+

async
@@ -731,7 +733,7 @@
Chat#sendStateTyping
async
-

setDescription(description) → Promise

+

setDescription(description) → Promise containing boolean

Updates the group description

Parameter

@@ -764,7 +766,9 @@
Returns
-

Promise 

+

Promise containing boolean  +

Returns true if the description was properly updated. This can return false if the user does not have the necessary permissions.

+

async
@@ -850,7 +854,7 @@
async
-

setSubject(subject) → Promise

+

setSubject(subject) → Promise containing boolean

Updates the group subject

Parameter

@@ -883,7 +887,9 @@
Returns
-

Promise 

+

Promise containing boolean  +

Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.

+

async
@@ -921,7 +927,7 @@
diff --git a/docs/GroupNotification.html b/docs/GroupNotification.html index 51b4c41..2090ce5 100644 --- a/docs/GroupNotification.html +++ b/docs/GroupNotification.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: GroupNotification + whatsapp-web.js 1.16.0 » Class: GroupNotification @@ -15,7 +15,7 @@ @@ -233,7 +233,7 @@
diff --git a/docs/InterfaceController.html b/docs/InterfaceController.html index 1d18650..1c6d8cf 100644 --- a/docs/InterfaceController.html +++ b/docs/InterfaceController.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: InterfaceController + whatsapp-web.js 1.16.0 » Class: InterfaceController @@ -15,7 +15,7 @@ @@ -382,7 +382,7 @@
diff --git a/docs/Label.html b/docs/Label.html index 0f95982..e401c74 100644 --- a/docs/Label.html +++ b/docs/Label.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: Label + whatsapp-web.js 1.16.0 » Class: Label @@ -15,7 +15,7 @@ @@ -163,7 +163,7 @@
diff --git a/docs/LegacySessionAuth.html b/docs/LegacySessionAuth.html new file mode 100644 index 0000000..414c156 --- /dev/null +++ b/docs/LegacySessionAuth.html @@ -0,0 +1,188 @@ + + + + + + + whatsapp-web.js 1.16.0 » Class: LegacySessionAuth + + + + + + + + +
+
+
+
+ +
+
+
+

new LegacySessionAuth(options)

+
+

Parameters

+ + + + + + + + + + + + + + + + + +
NameTypeOptionalDescription
+

options

+
+

 

+
+

 

+
+

options

+

Values in options have the following properties:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeOptionalDescription
+

restartOnAuthFail

+
+

 

+
+

 

+
+

Restart client with a new session (i.e. use null 'session' var) if authentication fails

+
+

session

+
+

 

+
+

 

+
+

Whatsapp session to restore. If not set, will start a new session

+
+

session.WABrowserId

+
+

 

+
+

 

+
+
+

session.WASecretBundle

+
+

 

+
+

 

+
+
+

session.WAToken1

+
+

 

+
+

 

+
+
+

session.WAToken2

+
+

 

+
+

 

+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+ + + + + + + + + \ No newline at end of file diff --git a/docs/List.html b/docs/List.html index f5aa6f7..857256d 100644 --- a/docs/List.html +++ b/docs/List.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: List + whatsapp-web.js 1.16.0 » Class: List @@ -15,7 +15,7 @@ @@ -256,7 +256,7 @@ Returns: [{'title':'sectionTitle','rows':[{'r
diff --git a/docs/LocalAuth.html b/docs/LocalAuth.html new file mode 100644 index 0000000..41247a5 --- /dev/null +++ b/docs/LocalAuth.html @@ -0,0 +1,135 @@ + + + + + + + whatsapp-web.js 1.16.0 » Class: LocalAuth + + + + + + + + +
+
+
+
+ +
+
+
+

new LocalAuth(options)

+
+

Parameters

+ + + + + + + + + + + + + + + + + +
NameTypeOptionalDescription
+

options

+
+

 

+
+

 

+
+

options

+

Values in options have the following properties:

+ + + + + + + + + + + + + + + + + + + + + + + +
NameTypeOptionalDescription
+

clientId

+
+

 

+
+

 

+
+

Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance

+
+

dataPath

+
+

 

+
+

 

+
+

Change the default path for saving session files, default is: "./.wwebjs_auth/"

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+ + + + + + + + + \ No newline at end of file diff --git a/docs/Location.html b/docs/Location.html index ece044c..cb67ee1 100644 --- a/docs/Location.html +++ b/docs/Location.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: Location + whatsapp-web.js 1.16.0 » Class: Location @@ -15,7 +15,7 @@ @@ -149,7 +149,7 @@
diff --git a/docs/Message.html b/docs/Message.html index f3d9578..ec2acd0 100644 --- a/docs/Message.html +++ b/docs/Message.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: Message + whatsapp-web.js 1.16.0 » Class: Message @@ -15,7 +15,7 @@ @@ -54,6 +54,9 @@
deviceType
+
duration
+
+
forwardingScore
@@ -97,13 +100,13 @@
links
+
location
+
+
-
location
-
-
mediaKey
@@ -113,6 +116,9 @@
orderId
+
rawData
+
+
timestamp
@@ -178,6 +184,9 @@
getQuotedMessage()
+
reload()
+
+
reply(content[, chatId][, options])
@@ -227,6 +236,11 @@

String that represents from which device type the message was sent

+

duration +  string

+

Indicates the duration of the message in seconds

+
+

forwardingScore  number

Indicates how many times the message was forwarded.

@@ -313,6 +327,11 @@

Order ID for message type ORDER

+

rawData +  Object

+

Returns message in a raw format

+
+

timestamp  number

Unix timestamp for when the message was created

@@ -496,6 +515,16 @@
async
+

reload() → Promise containing Message

+

Reloads this Message object's data in-place with the latest values from WhatsApp Web. + Note that the Message must still be in the web app cache for this to work, otherwise will return null.

+
+
Returns
+
+

Promise containing Message 

+
+
+
async

reply(content[, chatId][, options]) → Promise containing Message

Sends a message as a reply to this message. If chatId is specified, it will be sent through the specified Chat. If not, it will send the message @@ -580,7 +609,7 @@

diff --git a/docs/MessageMedia.html b/docs/MessageMedia.html index 781b468..08d066e 100644 --- a/docs/MessageMedia.html +++ b/docs/MessageMedia.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: MessageMedia + whatsapp-web.js 1.16.0 » Class: MessageMedia @@ -15,7 +15,7 @@ @@ -343,7 +343,7 @@
diff --git a/docs/NoAuth.html b/docs/NoAuth.html new file mode 100644 index 0000000..6eb911c --- /dev/null +++ b/docs/NoAuth.html @@ -0,0 +1,66 @@ + + + + + + + whatsapp-web.js 1.16.0 » Class: NoAuth + + + + + + + + +
+
+
+
+ +
+
+
+

new NoAuth()

+
+
+
+
+
+
+
+ +
+
+
+ +
+ + + + + + + + + \ No newline at end of file diff --git a/docs/Order.html b/docs/Order.html index 96d69db..1b73612 100644 --- a/docs/Order.html +++ b/docs/Order.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: Order + whatsapp-web.js 1.16.0 » Class: Order @@ -15,7 +15,7 @@ @@ -102,7 +102,7 @@
diff --git a/docs/PrivateChat.html b/docs/PrivateChat.html index fc3cb17..316c454 100644 --- a/docs/PrivateChat.html +++ b/docs/PrivateChat.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: PrivateChat + whatsapp-web.js 1.16.0 » Class: PrivateChat @@ -15,7 +15,7 @@ @@ -519,7 +519,7 @@
diff --git a/docs/PrivateContact.html b/docs/PrivateContact.html index 1f3f4c6..4035f05 100644 --- a/docs/PrivateContact.html +++ b/docs/PrivateContact.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: PrivateContact + whatsapp-web.js 1.16.0 » Class: PrivateContact @@ -15,7 +15,7 @@ @@ -108,19 +108,22 @@
+
getProfilePicUrl()
+
+
unblock()
@@ -262,6 +265,15 @@
async
+

getCommonGroups() → Promise containing Array of WAWebJS.ChatId

+

Gets the Contact's common groups with you. Returns empty array if you don't have any common group.

+
+
Inherited from
+
Contact#getCommonGroups
+
Returns
+
+
+
async

getCountryCode() → Promise containing string

Returns the contact's countrycode, (1541859685@c.us) => (1)

@@ -307,7 +319,7 @@
diff --git a/docs/Product.html b/docs/Product.html index 40a21e4..1a732f1 100644 --- a/docs/Product.html +++ b/docs/Product.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: Product + whatsapp-web.js 1.16.0 » Class: Product @@ -15,7 +15,7 @@ @@ -127,7 +127,7 @@
diff --git a/docs/Util.html b/docs/Util.html index c0d09eb..1909096 100644 --- a/docs/Util.html +++ b/docs/Util.html @@ -4,7 +4,7 @@ - whatsapp-web.js 1.15.8 » Class: Util + whatsapp-web.js 1.16.0 » Class: Util @@ -15,7 +15,7 @@ @@ -26,7 +26,7 @@