Compare commits

..

176 Commits

Author SHA1 Message Date
Pedro Lopez
5d83b45ed4 chore: mark version v1.15.7 2022-02-19 15:48:03 -04:00
github-actions[bot]
e29354fca3 Update supported WhatsApp Web version to v2.2204.13 (#1210)
Co-authored-by: pedroslopez <pedroslopez@users.noreply.github.com>
2022-02-19 15:45:21 -04:00
Shir Serlui
66283da903 Fix message.delete(true) (#1211)
* Fix message.delete(true)

* Fix for tests
2022-02-19 15:31:23 -04:00
Tomas Melone
d7f7889b0f fix: Remove duplicate identifier (#1205) 2022-02-19 15:18:34 -04:00
Pedro Lopez
11955e9f03 chore: mark version v1.15.6 2022-02-08 22:38:33 -04:00
Md. Fahim Bin Amin
444abc2c76 added the Code of Conduct, closing #1156 (#1176) 2022-02-08 22:34:33 -04:00
Pedro S. Lopez
20f3bc7a8b fix: dont cause redirect loop due to session restore (#1181)
* fix: dont cause redirect loop due to session restore

* back to `state` in docs

* use referer to determine first injection

* bring bzck disconnect on nav

* revert some changes
2022-02-08 22:33:20 -04:00
Pedro Lopez
93c8a2b05e chore: mark version v1.15.5 2022-02-06 22:20:08 -04:00
Pedro S. Lopez
70ca073f38 fix: send messages properly when disappearing mode is on (#1174)
* fix: send messages properly when dissappearing mode is on

* add `isEphemeral` to message model
2022-02-06 21:48:55 -04:00
Shir Serlui
7e36cceaf0 extra options can override other options when sending message (#1103)
* Fix the option to use special options

When we want to use some extra function we need to pass it into the options object, but because it inserted in the first line, the auto options reset some options (like 'type').
This is minor change that can help to add functionallity

* Update Injected.js

Put the special options in the end

* Update Injected.js

Fix , mistake

* only `extra` options can override everything else

Co-authored-by: Pedro Lopez <pedroslopez@me.com>
2022-02-06 21:00:10 -04:00
Noam Zaks
303ea3ab6b fix types and docs for Buttons class (#1070)
* fix: typing of buttons class

* fix remaining types

Co-authored-by: Pedro Lopez <pedroslopez@me.com>
2022-02-07 00:56:57 +00:00
Pedro Lopez
4aae8b0f32 fix: sort before splicing when fetching messages 2022-02-06 20:03:59 -04:00
Pedro Lopez
64803c2ba6 update typings for fetchMessages changes 2022-02-06 19:30:13 -04:00
Azeem Haider
aa9e19a19e fetchMessages gets currently available messages by default (#1015)
* get chat default messages fix #1014

* fixing format

* Update src/structures/Chat.js

Co-authored-by: Pedro S. Lopez <pedroslopez@me.com>

Co-authored-by: Pedro S. Lopez <pedroslopez@me.com>
2022-02-06 19:27:38 -04:00
Pedro S. Lopez
7631400de1 add back the pull_request trigger on lint 2022-02-06 19:16:57 -04:00
Pedro Lopez
d7478de68a fix: emit message events after ciphertext is decrypted
fixes #924
fixes #1041
2022-02-06 18:54:10 -04:00
Pedro Lopez
a9b2a1aab8 remove duplicated message type 2022-02-06 16:30:44 -04:00
Pedro Lopez
3b4632201d fix: add missing message types 2022-02-06 16:26:25 -04:00
Pedro Lopez
2200390d4c disable eslint warning on intentionally skipped test 2022-02-05 23:36:05 -04:00
dependabot[bot]
b1f7ff01bc chore(deps-dev): bump sinon from 12.0.1 to 13.0.1 (#1160)
Bumps [sinon](https://github.com/sinonjs/sinon) from 12.0.1 to 13.0.1.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v12.0.1...v13.0.1)

---
updated-dependencies:
- dependency-name: sinon
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-05 23:35:04 -04:00
dependabot[bot]
21d565154a chore(deps-dev): bump dotenv from 10.0.0 to 16.0.0 (#1171)
Bumps [dotenv](https://github.com/motdotla/dotenv) from 10.0.0 to 16.0.0.
- [Release notes](https://github.com/motdotla/dotenv/releases)
- [Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md)
- [Commits](https://github.com/motdotla/dotenv/compare/v10.0.0...v16.0.0)

---
updated-dependencies:
- dependency-name: dotenv
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-05 23:32:53 -04:00
dependabot[bot]
09cbee0e65 chore(deps-dev): bump eslint-plugin-mocha from 9.0.0 to 10.0.3 (#1087)
Bumps [eslint-plugin-mocha](https://github.com/lo1tuma/eslint-plugin-mocha) from 9.0.0 to 10.0.3.
- [Release notes](https://github.com/lo1tuma/eslint-plugin-mocha/releases)
- [Changelog](https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/CHANGELOG.md)
- [Commits](https://github.com/lo1tuma/eslint-plugin-mocha/compare/9.0.0...10.0.3)

---
updated-dependencies:
- dependency-name: eslint-plugin-mocha
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-05 23:32:30 -04:00
github-actions[bot]
fa9f5aba38 Update supported WhatsApp Web version to v2.2202.12 (#1152)
Co-authored-by: pedroslopez <pedroslopez@users.noreply.github.com>
2022-02-05 23:17:11 -04:00
Pedro S. Lopez
c859ac39ce fix: dont crash when calling .destroy() while waiting for qr scan (#1172)
fixes #739
fixes #951
2022-02-05 23:05:01 -04:00
Pedro S. Lopez
221d29736a remove unnecessary pull_request trigger for lint 2022-02-05 23:04:47 -04:00
Igor Nunes
078933f061 fix(typings): add MessageTypes BUTTONS_RESPONSE (#1032)
fixes #1104
2022-02-05 22:11:53 -04:00
Pedro S. Lopez
f149516d0d chore(tests): add Chat model tests (#784)
* add search and status tests

* reset to previous status in test

* move version to its own test

* add tests for Chat model

* keep hooks at the top

* run tests recursively in default script
2022-02-05 22:05:42 -04:00
Pedro S. Lopez
2f1c894a34 add tests for takeoverOnConflict (#1170)
* add tests

* fix module test, remove unused CryptoLib
2022-02-05 20:04:00 -04:00
Pedro S. Lopez
32e47d818a fix: only emit disconnected event on navigation when state is PAIRING (#1169) 2022-02-05 18:19:02 -04:00
Zulfikar
20aee44c3b fix getLabels error (#1049)
Co-authored-by: Rajeh Taher <rajeh@reforward.dev>
2022-02-05 16:41:27 -04:00
Shir Serlui
bb2ef88e0a fix: message.delete() can revoke for everyone (#1107)
Change msg.canRevoke to msg._canRevoke according to WhatsApp code change
2022-02-05 15:52:04 -04:00
tuyuribr
6878598a5d fix: await promise when setting user agent (#1113)
Some of my devices were bugging out because the setUserAgent didn't had an await, after this everything was working fine (try loading the wwebjs in a broken microSd ahhaha).

We need some testing but on my limited testing everything is working

Co-authored-by: Rajeh Taher <rajeh@reforward.dev>
2022-02-05 15:42:25 -04:00
Pedro Lopez
4e6a00dffe chore: mark version v1.15.4 2022-01-25 20:49:07 -04:00
Pedro Lopez
b93c7b4b76 fix invalid jsdoc 2022-01-25 20:48:44 -04:00
Pedro Lopez
a37ff69692 fix: restore node 12 support 2022-01-25 20:40:50 -04:00
github-actions[bot]
3705d1fea9 Update supported WhatsApp Web version to v2.2202.8 (#1084)
Co-authored-by: pedroslopez <pedroslopez@users.noreply.github.com>
Co-authored-by: Pedro S. Lopez <pedroslopez@me.com>
2022-01-25 20:16:08 -04:00
Pedro S. Lopez
7950aae5d1 fix: find Store in v2.2202.8 (#1130)
Co-authored-by: Rajeh Taher <rajeh@reforward.dev>
2022-01-25 20:15:19 -04:00
Pedro Lopez
bdff59fb44 fix: remove problematic import 2022-01-25 19:45:57 -04:00
Wictor Nogueira
d05803074a update MessageMedia.fromUrl (#811)
* fix MessageMedia.fromUrl docs

* use content-type as fallback

* set filename based on url

* fix empty filename

* wrap expression in parentheses

* hotfix

* JSDoc fix

* fix for jsdog

* eslint gets retirement home

Co-authored-by: Rajeh Taher <rajeh@reforward.dev>
Co-authored-by: Aliyss Snow <33941859+Aliyss@users.noreply.github.com>
2022-01-21 23:57:15 +01:00
Rajeh Taher
d86c39de3c fix: Fix inactivity issue (#946)
* Fixed Remember me issue

* Update Client.js
2021-12-16 15:25:35 +00:00
shirser121
46ba9c5e9a Add isGif to message._patch (#963)
* Update Message.js

Add isGif to the message data

* add typings

Co-authored-by: Rajeh Taher <rajeh@reforward.dev>
Co-authored-by: Pedro Lopez <pedroslopez@me.com>
2021-12-12 21:57:11 -04:00
Pedro Lopez
d7a493e68a fix: use correct @types/node-fetch ver, use working node-fetch ver from puppeteer, add test 2021-12-12 21:28:38 -04:00
dependabot[bot]
da95d927b9 chore(deps): bump puppeteer from 10.4.0 to 13.0.0 (#1057)
Bumps [puppeteer](https://github.com/puppeteer/puppeteer) from 10.4.0 to 13.0.0.
- [Release notes](https://github.com/puppeteer/puppeteer/releases)
- [Changelog](https://github.com/puppeteer/puppeteer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/puppeteer/puppeteer/compare/v10.4.0...v13.0.0)

---
updated-dependencies:
- dependency-name: puppeteer
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-12 21:09:56 -04:00
dependabot[bot]
92bc5e62ab chore(deps-dev): bump eslint from 7.32.0 to 8.4.1 (#1038)
Bumps [eslint](https://github.com/eslint/eslint) from 7.32.0 to 8.4.1.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v7.32.0...v8.4.1)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-12 19:47:11 -04:00
dependabot[bot]
73a3e28a4b chore(deps-dev): bump @types/node-fetch from 2.5.12 to 3.0.3 (#911)
Bumps [@types/node-fetch](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node-fetch) from 2.5.12 to 3.0.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node-fetch)

---
updated-dependencies:
- dependency-name: "@types/node-fetch"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-12 19:46:30 -04:00
dependabot[bot]
4f376fc2fa chore(deps-dev): bump sinon from 11.1.2 to 12.0.1 (#1024)
Bumps [sinon](https://github.com/sinonjs/sinon) from 11.1.2 to 12.0.1.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/docs/changelog.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v11.1.2...v12.0.1)

---
updated-dependencies:
- dependency-name: sinon
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-12 19:41:08 -04:00
dependabot[bot]
a20c8ef8f8 chore(deps): bump mime from 2.6.0 to 3.0.0 (#1023)
Bumps [mime](https://github.com/broofa/mime) from 2.6.0 to 3.0.0.
- [Release notes](https://github.com/broofa/mime/releases)
- [Changelog](https://github.com/broofa/mime/blob/master/CHANGELOG.md)
- [Commits](https://github.com/broofa/mime/compare/v2.6.0...v3.0.0)

---
updated-dependencies:
- dependency-name: mime
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-12 19:38:33 -04:00
tuyuribr
2052e0479d Fix: multiple list sections (#1004)
* Fix multiple list sections

* singleQuotes

* Update src/structures/List.js

Co-authored-by: Rajeh Taher <rajeh@reforward.dev>
2021-12-10 20:47:07 +01:00
Pedro Lopez
c55db82f73 mark version v1.15.3 2021-12-07 23:06:53 -04:00
github-actions[bot]
4e837b00f9 Update supported WhatsApp Web version to v2.2147.14 (#1033)
Co-authored-by: pedroslopez <pedroslopez@users.noreply.github.com>
2021-12-07 23:05:54 -04:00
tuyuribr
89a06b15a8 Hot Fix WA 2.2147.14 (#1035)
* Hot Fix WA 2.2147.14

* Update Injected.js

* Update Client.js

* sendPresence1

* Update Client.js

* queryLinkPreview

* openChatDrawer

* revert back to using Wap

Co-authored-by: Pedro Lopez <pedroslopez@me.com>
2021-12-07 23:04:44 -04:00
Pedro Lopez
55247576da add script to get change log 2021-11-24 10:07:27 -04:00
Pedro Lopez
8a1f6f0648 chore: mark version v1.15.2 2021-11-24 09:49:16 -04:00
github-actions[bot]
254ca884aa Update supported WhatsApp Web version to v2.2146.9 (#969)
Co-authored-by: pedroslopez <pedroslopez@users.noreply.github.com>
Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
2021-11-24 09:43:59 -04:00
tuyuribr
3958105926 Fix WA 2.2146.9 (#990)
* Fix WA 2.2146.9

WA is serving two versions to me,  so we need to check window.mR.findModule('Conn').lengh for a while

* to singleQuotes

* Update Injected.js

* simplify getting `Conn` module, use different object for `Store`

Co-authored-by: Pedro Lopez <pedroslopez@me.com>
2021-11-24 09:40:01 -04:00
Pedro Lopez
818bf48e5d fix: convert button ids to string 2021-11-01 21:30:34 -04:00
Pedro S. Lopez
d71544566c move links section in readme 2021-10-30 21:29:39 -04:00
Pedro S. Lopez
187aa50131 Url updates for wwebjs.dev (#944)
* Update package.json

* update links in readme
2021-10-30 21:27:08 -04:00
Pedro Lopez
e11e00d938 chore: update docs for v1.15.1 2021-10-30 00:46:37 -04:00
Pedro Lopez
d9dd89ccaf chore: mark version v1.15.1 2021-10-30 00:46:09 -04:00
Pedro Lopez
3aa0e4f7b3 fix: dont modify id reference when serializing message 2021-10-30 00:45:04 -04:00
Pedro Lopez
d82cf448d9 chore: mark version v1.15.0 2021-10-30 00:15:24 -04:00
github-actions[bot]
3f576c990c Update supported WhatsApp Web version to v2.2142.12 (#827)
Co-authored-by: pedroslopez <pedroslopez@users.noreply.github.com>
Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
2021-10-30 00:14:07 -04:00
Pedro Lopez
d44a525b02 fix: serialize message id remote when fetching messages
close #825
2021-10-30 00:12:06 -04:00
Pedro Lopez
d8217029ba add test for maxQrRetries 2021-10-30 00:03:19 -04:00
victormga
2a7337b142 max qr refresh before giving up (#852)
* max qr refresh before giving up

* Update src/Client.js

Co-authored-by: Rajeh Taher <rajeh@reforward.dev>

Co-authored-by: Rajeh Taher <rajeh@reforward.dev>
2021-10-29 23:45:04 -04:00
Pedro S. Lopez
1fcfaa0362 Update README.md (#907) 2021-10-29 23:43:27 -04:00
Pedro Lopez
c434e04e41 fix countrycode and formatted number functions, add tests 2021-10-29 23:41:49 -04:00
Rajeh Taher
97a1d399ee Format phone numbers (#650)
* 📦 Declared NumberInfo in store

* 📝 Add client.js functionality

* 🚨 eslint just admires singlequote strings

* 📝 Add shortcuts to using client method

*  Adding parity between the ids

*  Same method name parity

* 🚨 ESLint indentation error.

* 🚨 ESLint doublequote string error.

* 🎨 Proposed changes

* 🎨 Fixed badly done code :v and applied proposed changes.

*  fixed calling the wrong function (sigh)

*  Fixed missing try-catch code.

* 🚨 Fixes ESLint indentation errors.

*  fix the documentation issues.

* 🏷️ typescript

* 🏷️ Typo in function name

Co-authored-by: Rajeh Taher <rajeh@reforward.tk>
2021-10-29 23:33:38 -04:00
Rajeh Taher
dbf9bf2158 Type file improvements (#855)
* Updated Types

* Updated types to include (#868)

* Update index.d.ts

* fix list type

Co-authored-by: Pedro Lopez <pedroslopez@me.com>
Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
2021-10-29 23:32:13 -04:00
Pedro Lopez
353af130d0 remove unnecessary default 2021-10-29 23:25:06 -04:00
Rajeh Taher
06107af67d Allow a chat to be muted indefinitely (#849)
* muteChat fixed

* Update src/Client.js

Co-authored-by: Pedro S. Lopez <pedroslopez@me.com>

* Update src/Client.js

Co-authored-by: Pedro S. Lopez <pedroslopez@me.com>

* date fix

Co-authored-by: Pedro S. Lopez <pedroslopez@me.com>
2021-10-29 23:24:36 -04:00
Muhamad Ristiyanto
4338664590 Add getBlockedContacts method (#770)
* add simple method to get blocked ids

* Change getBlockedList to getBlockedIds

* getBlockedIds to getBlockedContacts

* typo

* ESLint & other changes

* 🏷️ types

* fix: no `this.client`

* add tests

Co-authored-by: Rajeh Taher <rajeh@reforward.dev>
Co-authored-by: Pedro Lopez <pedroslopez@me.com>
Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
2021-10-30 03:18:26 +00:00
Rajeh Taher
95facee885 Fixes GroupNotification.getChat() returning client's chat. (#699)
* 🥅 getChat returns expected, instead of the client's chat.

* 🥅 Fixed .reply method too

* revert + fix
2021-10-29 23:00:10 -04:00
Pedro Lopez
1f38b762ed add warning for multidevice, keep working for forced upgrade 2021-10-29 22:58:57 -04:00
tuyuribr
b60029ed09 feat: Send buttons and Lists (#756) 2021-09-14 00:06:05 +03:00
tuyuribr
ab415ff9be feat: Include payment info (#684) 2021-09-13 23:58:39 +03:00
Pedro Lopez
7beeff4901 chore: mark version 1.14.1 2021-09-01 09:19:28 -04:00
Pedro Lopez
022c87f3c7 optionally patch _find function if it's not found 2021-09-01 09:18:34 -04:00
Pedro Lopez
e527fe74fd fix: patch find function to get chats 2021-09-01 09:16:12 -04:00
Pedro S. Lopez
7597608f9d Update README.md 2021-08-02 00:49:03 -04:00
Pedro Lopez
be018e651d update .npmignore 2021-08-02 00:07:52 -04:00
Pedro Lopez
64189d2d67 chore: mark version v1.14.0 2021-08-01 23:59:56 -04:00
Pedro Lopez
38e31a07cf Update package.json and readme for node 12 support 2021-08-01 23:57:21 -04:00
Pedro Lopez
40cec51956 fix: node v12 support 2021-08-01 23:56:27 -04:00
Pedro S. Lopez
d9ccb6f276 fix: correctly resolve media that hasn't been downloaded (#763)
* fix: correctly abort if media does not exist

* catch 404s

* dont throw for media that cant be fetched
2021-08-01 23:29:06 -04:00
github-actions[bot]
628b6e4d49 Update supported WhatsApp Web version to v2.2126.14 (#806)
Co-authored-by: pedroslopez <pedroslopez@users.noreply.github.com>
2021-08-01 23:13:07 -04:00
Pedro S. Lopez
8e56aef3ce fix: more stable latest version check (#805) 2021-08-01 23:04:02 -04:00
Wictor Nogueira
cd774bef17 feat: Add MessageMedia.fromUrl method (#769) 2021-07-31 16:36:11 +03:00
Pedro S. Lopez
9c2592e164 chore: temporarily stop update action from auto running 2021-07-20 14:51:58 -04:00
Pedro S. Lopez
ae6d61bda9 fix: correctly serialize messages with replyButtons 2021-07-19 22:23:06 -04:00
Pedro S. Lopez
98acd2312d delete gh branch automatically when closing update PR 2021-07-19 19:46:24 -04:00
Pedro Lopez
62c7c15f44 chore: update links 2021-07-19 00:19:40 -04:00
Pedro Lopez
e12c53f6ce chore: specify minimum required node version 2021-07-19 00:11:57 -04:00
Pedro S. Lopez
811008da4b Delete CNAME 2021-07-18 23:37:45 -04:00
Pedro S. Lopez
863284c9d1 Create CNAME 2021-07-18 23:37:21 -04:00
Pedro S. Lopez
ec95483518 Create CNAME 2021-07-18 23:36:02 -04:00
Pedro S. Lopez
ff2eb95751 Change WA Web update PR branch name 2021-07-18 22:57:18 -04:00
dependabot[bot]
1b5e9d2392 chore(deps-dev): bump mocha from 8.4.0 to 9.0.2 (#776)
Bumps [mocha](https://github.com/mochajs/mocha) from 8.4.0 to 9.0.2.
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v8.4.0...v9.0.2)

---
updated-dependencies:
- dependency-name: mocha
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-18 22:55:06 -04:00
Pedro Lopez
340e9764fe Publish gh-pages site (branch name change) 2021-07-18 22:43:07 -04:00
Rajeh Taher
084525ddfa Add Operating System information for bug reports. (#725)
* 📄 Add Operating System information for bug reports.

* 🐛 Forgot Line Break
2021-07-17 22:04:44 -04:00
github-actions[bot]
3398501ee6 Update supported WhatsApp Web version to v2.2126.11 (#766)
Co-authored-by: pedroslopez <pedroslopez@users.noreply.github.com>
Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
2021-07-17 00:07:38 -04:00
tuyuribr
cdede835af Include Calls (#720)
* Get Call module

* The call event

* Update onCall index.d.ts
2021-07-17 00:05:53 -04:00
Pedro S. Lopez
449d0f01d8 Trim current version string 2021-07-16 03:19:58 -04:00
Pedro S. Lopez
4ed9312eb7 Update update.yml 2021-07-16 03:09:54 -04:00
Pedro S. Lopez
76deaad2fd Update update.yml 2021-07-16 03:05:18 -04:00
Pedro S. Lopez
284903dce4 Update README.md 2021-07-16 02:53:39 -04:00
Pedro S. Lopez
a03cc41d22 Add tests and detect WhatsApp Web updates (#686)
* test setup, add initializer tests

* test sending messages

* add script to check latest version

* add github action

* use env vars

* configure environment with .env file

* add test for sticker name and author

* add DownloadManager model

* test chats and contacts

* test for number utility functions

* throw error if no remote id has been set

* Update .version
2021-07-16 02:50:05 -04:00
ApeironTsuka
04d2308bbc Update node-webpmux 2.x syntax to 3.x (support upstream breaking change) (#762)
Co-authored-by: Apeiron <apeiron@none>
2021-07-15 22:50:54 -04:00
Pedro S. Lopez
dc9b7e5f3d Update minimum moduleRaid version to 5.0.2
close #741
2021-07-14 22:42:21 -04:00
dependabot[bot]
cc7a729223 chore(deps): bump puppeteer from 5.5.0 to 10.1.0 (#750)
Bumps [puppeteer](https://github.com/puppeteer/puppeteer) from 5.5.0 to 10.1.0.
- [Release notes](https://github.com/puppeteer/puppeteer/releases)
- [Changelog](https://github.com/puppeteer/puppeteer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/puppeteer/puppeteer/compare/v5.5.0...v10.1.0)

---
updated-dependencies:
- dependency-name: puppeteer
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-14 18:39:24 -04:00
dependabot[bot]
2ec46f674a chore(deps): bump sharp from 0.26.3 to 0.28.3 (#751)
Bumps [sharp](https://github.com/lovell/sharp) from 0.26.3 to 0.28.3.
- [Release notes](https://github.com/lovell/sharp/releases)
- [Changelog](https://github.com/lovell/sharp/blob/master/docs/changelog.md)
- [Commits](https://github.com/lovell/sharp/compare/v0.26.3...v0.28.3)

---
updated-dependencies:
- dependency-name: sharp
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-14 18:35:59 -04:00
dependabot[bot]
22993fc23d chore(deps): bump node-webpmux from 2.0.3 to 3.0.0 (#749)
Bumps [node-webpmux](https://github.com/ApeironTsuka/node-webpmux) from 2.0.3 to 3.0.0.
- [Release notes](https://github.com/ApeironTsuka/node-webpmux/releases)
- [Commits](https://github.com/ApeironTsuka/node-webpmux/commits)

---
updated-dependencies:
- dependency-name: node-webpmux
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-14 18:33:36 -04:00
Edson Tégila
cd52075447 Add the option to use "browserWSEndpoint" (#727)
* Update Client.js

* Update package.json

* Update package.json

* 🚨🔥 Fixed ESLint and removed old code.

* Update README.md

* Update README.md

* Update Client.js

* chore(deps): bump sharp from 0.26.3 to 0.28.3

Bumps [sharp](https://github.com/lovell/sharp) from 0.26.3 to 0.28.3.
- [Release notes](https://github.com/lovell/sharp/releases)
- [Changelog](https://github.com/lovell/sharp/blob/master/docs/changelog.md)
- [Commits](https://github.com/lovell/sharp/compare/v0.26.3...v0.28.3)

---
updated-dependencies:
- dependency-name: sharp
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update package.json

* Update README.md

* Update example.js

* Update README.md

Co-authored-by: Rajeh Taher <52720753+PurpShell@users.noreply.github.com>
Co-authored-by: Rajeh Taher <rajeh@reforward.tk>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Aliyss Snow <33941859+Aliyss@users.noreply.github.com>
2021-07-13 10:27:00 -07:00
Rajeh Taher
54a07fa22f feat: Add support to suspicious links (#642) 2021-07-12 11:03:11 -07:00
Pedro S. Lopez
1d49f74ab4 Update dependabot.yml 2021-07-11 21:29:58 -04:00
Pedro S. Lopez
ea4dfb17f3 Create dependabot.yml 2021-07-11 21:28:39 -04:00
stefanfuchs
efa6cf98d2 fix: location class type (#718) 2021-07-12 00:54:32 +00:00
Giancarlo Rocha
9d715735ed feat: message forwarding score (#716) 2021-07-11 20:52:54 -04:00
Pedro Lopez
4afff38713 Fix download media (v1.13.2) 2021-07-09 03:08:52 -04:00
Pedro Lopez
b13dea0339 chore: mark version v1.13.1 2021-07-09 02:39:13 -04:00
Pedro S. Lopez
0ef6061d7e Fix downloading media for WhatsApp Web v2.2126.10 (#735)
* fix downloadMedia

* return a boolean for hasMedia
2021-07-09 02:38:31 -04:00
Pedro Lopez
0465507009 chore: mark version v1.13.0 2021-07-09 01:22:08 -04:00
Pedro Lopez
2fd96e76b9 update readme to indicate node 14 is required 2021-07-09 01:18:09 -04:00
Pedro Lopez
caab11cfe4 bump minimum required moduleraid version 2021-07-09 01:14:07 -04:00
Pedro S. Lopez
ebba1b9ab9 Update lint.yml 2021-06-05 19:02:08 -04:00
JoseHM8A
cdc00e934d feat: acceptGroupV4Invite (#677)
* Added option client.acceptGroupV4Invite()

* Update Client.js

* Update index.d.ts

Added a description to the inviteV4 object

Renamed "invite" by "inviteV4"

* Update Client.js

* Update Message.js

renamed "invite" to "inviteV4"

* Update Client.js

* Added message.acceptGroupV4Invite method

* Update index.d.ts

acceptGroupV4Invite

* better typings, refactor some names

Co-authored-by: Pedro Lopez <pedroslopez@me.com>
2021-06-05 17:10:47 -04:00
Pedro S. Lopez
795570a697 chore: update eslint and ecmaVersion (#680) 2021-06-02 23:39:01 -04:00
Pedro S. Lopez
0465742ffb chore: update lint action (#679)
* update lint action

* fix script path

* ignore docs

* update names
2021-06-02 23:17:28 -04:00
Ricardo Araújo Paes
38976558f5 feat(dev): add argument bypassCSP to use in pupperter (#635) 2021-06-01 22:05:44 -04:00
Wictor Nogueira
b895437458 add searchMessages method (#586)
* add searchMessages method

* fix typing

* fix typing

* remove unused statement

Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
2021-06-01 21:54:27 -04:00
tuyuribr
0a061f982c feat: Add from which device the message was sent (#648)
* Add from which device the message was sent.

Use the message Id for fingerprint the device that was being use when the message was sent

* To single quotes

Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
2021-05-31 21:03:23 -04:00
Aliyss Snow
63d11d3f84 feat: disable / enable WA Web features (#543)
* Added Features and Enabling/Disabling of Features within WhatsappWeb

* remove feature commands from example

Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
Co-authored-by: Pedro Lopez <pedroslopez@me.com>
2021-05-31 20:58:55 -04:00
renjop
5177a257cf feat: Get Orders and Products (#612)
* - Get products and orders

* - Get products and orders

* - Eslint fixes

* - Eslint fixes

* allow downloading media for products

* products and orders work on normal accounts

Co-authored-by: Renato Jop <renato.jop@consystec-corp.com>
Co-authored-by: Pedro Lopez <pedroslopez@me.com>
Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
2021-05-31 20:46:43 -04:00
Wictor Nogueira
f506c171c1 add extra option to MessageSendOptions (#600)
Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
2021-05-31 19:24:30 -04:00
tuyuribr
64e2cc48fc feat: openChatWindow can open new chats (#592)
Open the chat window even if you never chatted with the chatId

Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
2021-05-31 19:21:57 -04:00
Wictor Nogueira
6c66ab2bef Add sendVideoAsGif option (#578)
* Add sendVideoAsGif option

* fix typo

Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
2021-05-31 19:18:10 -04:00
Rajeh Taher
efc7018f9a Add support for sticker Name and author (#527)
* Added Sticker author and sticker name support

This patch of Client.js includes support for sticker metadata

* Docs: stickerName and stickerAuthor in MessageOpts

* Hotfix_Sticker_Feature

fixes a bug

* Update global.html

* updated

* fixed comma

* Fixed duplicate code

* Fixing eslint

* Fixing eslint again

* eslint....

* fixing problem with eslint.

* move sticker exif data filling to Utils.formatToWebpSticker() function

* Update Client.js

* Added temporary stuff

* eslint

* Update Util.js

* eslint bad :D

* eslint

* polish work with files

* fix error and TODOs

* clean up code to match with repo code style

* update typescript params

* Update src/util/Util.js

camel Case

Co-authored-by: Pedro S. Lopez <pedroslopez@me.com>

* Update Util.js

*  webp-converter  node-webpmux

* Update Util.js

*  Use node-webpmux

*  node-webpmux  node-webpmux-commonjs

* ✏️ Fixed require mode

* :heavy_plus_sign:node-webpmux  node-webpmux-commonjs

* ⬆️ Node-webpmux update changes

* 🚨 removing try/catch

* 🚨 complier warnings

* 🧐 stupid mistakes

* ⬆️ Upgrade required version

* 🐛 creating a buffer the right way

* 🐛 linting and simplification

* 🐛 unsimplification

* 🚨 eslint loves singlequotes

*  Added emojis / categories in metadata

* 🏷️ TypeScript Declarations

*  Sticker Categories in sendMessage

* 🏷️ Improved TS declarations

* fix stickerCategories type

* fix: don't set name/author if not defined

Co-authored-by: Marcelo Carvalho <mpirescarvalho17@gmail.com>
Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
Co-authored-by: Pedro S. Lopez <pedroslopez@me.com>
2021-05-31 19:13:30 -04:00
Pedro Lopez
5991b28b88 update supported whatsapp web ver to v2.2114.8 2021-04-20 23:02:33 -04:00
Pedro Lopez
2894832b00 chore: mark version v1.12.6 2021-04-20 22:59:35 -04:00
Pedro Lopez
6cece4a006 fix: emit disconnected event on page navigation
This also addresses an issue due to a change in behavior from WhatsApp Web when the session is logged out from the device.
2021-04-20 20:02:22 -04:00
Pedro Lopez
f1e2f32988 fix: click correct element on manual qr code refresh 2021-04-20 19:39:13 -04:00
Pedro S. Lopez
f564e41781 chore: bump version to v1.12.5 2021-02-25 00:31:39 -04:00
Jacob Galam
e6015162c5 fix(types): media type in MessageSendOptions (#554)
Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
2021-02-25 00:27:23 -04:00
Pedro S. Lopez
bc90ffcb19 fix: WhatsApp Web v2.2106.5 compatibility 2021-02-25 00:23:49 -04:00
Antoine Schaller
2702757dce fix: star() & unstar() functions (#547) 2021-02-15 22:24:07 -04:00
Pedro S. Lopez
56171f957e chore: don't auto set bug label on issues
This should be manually added when it's confirmed a bug
2021-02-13 11:29:16 -04:00
Pedro S. Lopez
204a1c79af chore: mark version v1.12.4 2021-02-11 18:44:15 -04:00
Pedro S. Lopez
168c84250e fix sending stickers on WhatsApp Web v2.2104.6 2021-02-11 18:40:35 -04:00
Pedro S. Lopez
d96e8e5eb5 chore: mark version v1.12.3 2021-02-09 15:40:57 -04:00
Pedro S. Lopez
0cbb0373ad fix(ts): getNumberId typings caused error on build 2021-02-09 15:35:57 -04:00
Pedro S. Lopez
1f756142e4 ignore logs on npm publish 2021-02-09 00:48:58 -04:00
Pedro S. Lopez
4047afe332 chore: mark version v1.12.2 2021-02-09 00:47:28 -04:00
Pedro S. Lopez
89029ac916 add docs 2021-02-09 00:43:45 -04:00
Artem Sinelnikov
fa4923db98 fixed acceptInvite typings 2021-02-09 00:43:45 -04:00
Pedro S. Lopez
559133c3c4 fix: upload media on WhatsApp Web v2.2104.6 2021-02-09 00:35:25 -04:00
Pedro S. Lopez
e2acd03efc fix: download media on WhatsApp Web v2.2104.6 2021-02-09 00:24:48 -04:00
Pedro S. Lopez
c6974295a6 chore: mark version v1.12.1 2021-01-30 20:38:10 -04:00
Pedro S. Lopez
6590c75c8a fix (ts): include pupPage and pupBrowser properties on Client typedef 2021-01-30 20:36:46 -04:00
Pedro S. Lopez
1bdc7335d8 chore: mark version v1.12.0 2020-12-29 00:38:44 -04:00
Pedro S. Lopez
bb9d160f72 docs: switch links to point to the guide 2020-12-29 00:37:25 -04:00
Pedro S. Lopez
cea1830dde docs: fix error generating Label docs 2020-12-29 00:33:49 -04:00
Pedro S. Lopez
f639c53f0a feat: Get message delivery information (close #418) 2020-12-29 00:33:49 -04:00
Raphael R
3e32fe27ea feat: mark chat as unread (#475)
Co-authored-by: Pedro S. Lopez <pedroslopez@me.com>
2020-12-29 00:33:49 -04:00
Marcelo Carvalho
5c6195738f feat: add GroupChat types (#485)
Co-authored-by: Pedro S. Lopez <pedroslopez@me.com>
2020-12-29 00:33:49 -04:00
Pedro S. Lopez
32575490da docs: fix typo 2020-12-29 00:33:49 -04:00
Antoine Schaller
5a0ccc8b17 feat: added starred indicator to messages (#501)
Co-authored-by: Pedro S. Lopez <pedroslopez@me.com>
2020-12-29 00:33:49 -04:00
Marcelo Carvalho
1b946940f4 feat: star/unstar messages (#494) 2020-12-29 00:33:49 -04:00
Pedro S. Lopez
71dbe99023 feat: get Contact's "About" text (close #491) 2020-12-29 00:33:49 -04:00
Pedro S. Lopez
8b101d1f3d feat: get links included in message (#457) 2020-12-29 00:33:49 -04:00
Marcelo Carvalho
e2a642a81b feat: send media as stickers (#479)
Adds the option `sendMediaAsSticker` that will take care of converting media to appropriate formats and send it as a sticker. Note that ffmpeg is required to properly convert animated stickers that are not in webp format.

Co-authored-by: Pedro S. Lopez <pedroslopez@me.com>
2020-12-29 00:33:49 -04:00
Pedro Lopez
0c0a5a752b docs: fix slight typo 2020-12-29 00:33:49 -04:00
Marcelo Carvalho
e141a5df97 feat: send media as document (#490)
Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
2020-12-29 00:33:49 -04:00
Lucas Rosa
576768e390 feat: Get registered ID for a given phone number (#483)
Exposes internal getNumberById function for easy usage.
This can help with dealing with brazilian numbers with the extra digit, always returning the correct ID.

This will probably eventually replace the current isRegisteredUser function.

Co-authored-by: Pedro Lopez <pedroslopez@me.com>
2020-12-29 00:33:49 -04:00
Aliyss Snow
87cb5a0519 feat(interface): Open chat search, open chat at message position (#447) 2020-12-29 00:33:49 -04:00
dyegoaurelio
274d24002b feat: WA Business Labels support (#407)
* Get all labels
* Get chats by label
* Get labels assigned to chats

Co-authored-by: Pedro S. Lopez <pslamoros@hotmail.com>
Co-authored-by: Pedro Lopez <pedroslopez@me.com>
2020-12-29 00:33:49 -04:00
89 changed files with 9779 additions and 535 deletions

2
.env.example Normal file
View File

@@ -0,0 +1,2 @@
WWEBJS_TEST_SESSION_PATH=test_session.json
WWEBJS_TEST_REMOTE_ID=XXXXXXXXXX@c.us

View File

@@ -5,14 +5,16 @@
"es6": true,
"node": true
},
"extends": "eslint:recommended",
"extends": ["eslint:recommended", "plugin:mocha/recommended"],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018
"ecmaVersion": 2020
},
"plugins": ["mocha"],
"ignorePatterns": ["docs"],
"rules": {
"indent": [
"error",

View File

@@ -2,7 +2,6 @@
name: Bug report
about: Is something not working as intended? Report it here.
title: ''
labels: bug
assignees: ''
---
@@ -35,5 +34,8 @@ If applicable, add code snippets to help explain your problem.
- npm or yarn version (`npm -v`):
- whatsapp-web.js version:
**Other**
- Operating system (the one running node) [Linux / MacOS / Windows]:
- Operating system version (ex. Windows 10):
### Additional context
Add any other context about the problem here.

7
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
open-pull-requests-limit: 10
schedule:
interval: "monthly"

View File

@@ -6,19 +6,15 @@ on:
jobs:
eslint:
name: eslint
name: ESLint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: install node v12
uses: actions/setup-node@v1
- uses: actions/checkout@v2
- name: Install node v14
uses: actions/setup-node@v2
with:
node-version: 12
- name: npm install
node-version: '14'
- name: Install dependencies
run: npm install
- name: eslint
uses: icrawl/action-eslint@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
job-name: eslint
- name: Run ESLint
run: ./node_modules/.bin/eslint .

39
.github/workflows/update.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: Update
on:
schedule:
- cron: "0/15 * * * *"
workflow_dispatch:
jobs:
update:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./tools/version-checker
steps:
- uses: actions/checkout@v2
- name: Install node v16
uses: actions/setup-node@v2
with:
node-version: '16'
- name: Install dependencies
run: npm install
- name: Run Updater
run: ./update-version
- name: Store WA Version
run: echo WA_VERSION=`cat ./.version` >> $GITHUB_ENV
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
branch: auto-wa-web-update/patch
delete-branch: true
commit-message: Update supported WhatsApp Web version to v${{ env.WA_VERSION }}
title: Update WhatsApp Web Version (${{ env.WA_VERSION }})
body: |
A new version of WhatsApp Web has been detected!
Tests should be run against this new version before merging.
labels: WhatsApp Change
reviewers: pedroslopez

View File

@@ -5,4 +5,13 @@ docs/*
.jsdoc.json
.editorconfig
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
*session.json
.env
tools/
tests/

133
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,133 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[pedroslopez@me.com](mailto:pedroslopez@me.com).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
at [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -1,4 +1,4 @@
[![npm](https://img.shields.io/npm/v/whatsapp-web.js.svg)](https://www.npmjs.com/package/whatsapp-web.js) [![Depfu](https://badges.depfu.com/badges/4a65a0de96ece65fdf39e294e0c8dcba/overview.svg)](https://depfu.com/github/pedroslopez/whatsapp-web.js?project_id=9765) ![WhatsApp_Web 2.2049.10](https://img.shields.io/badge/WhatsApp_Web-2.2049.10-brightgreen.svg) [![Discord Chat](https://img.shields.io/discord/698610475432411196.svg?logo=discord)](https://discord.gg/H7DqQs4)
[![npm](https://img.shields.io/npm/v/whatsapp-web.js.svg)](https://www.npmjs.com/package/whatsapp-web.js) [![Depfu](https://badges.depfu.com/badges/4a65a0de96ece65fdf39e294e0c8dcba/overview.svg)](https://depfu.com/github/pedroslopez/whatsapp-web.js?project_id=9765) ![WhatsApp_Web 2.2204.13](https://img.shields.io/badge/WhatsApp_Web-2.2204.13-brightgreen.svg) [![Discord Chat](https://img.shields.io/discord/698610475432411196.svg?logo=discord)](https://discord.gg/H7DqQs4)
# whatsapp-web.js
A WhatsApp API client that connects through the WhatsApp Web browser app
@@ -7,16 +7,24 @@ It uses Puppeteer to run a real instance of Whatsapp Web to avoid getting blocke
**NOTE:** I can't guarantee you will not be blocked by using this method, although it has worked for me. WhatsApp does not allow bots or unofficial clients on their platform, so this shouldn't be considered totally safe.
## Quick Links
* [Guide / Getting Started](https://wwebjs.dev/guide) _(work in progress)_
* [Reference documentation](https://docs.wwebjs.dev/)
* [GitHub](https://github.com/pedroslopez/whatsapp-web.js)
* [npm](https://npmjs.org/package/whatsapp-web.js)
## Installation
The module is now available on npm! `npm i whatsapp-web.js`
Please note that Node v10.18.1+ is required due to Puppeteer.
Please note that Node v12+ is required.
## Example usage
```js
const { Client } = require('whatsapp-web.js');
const client = new Client();
client.on('qr', (qr) => {
@@ -39,6 +47,39 @@ client.initialize();
Take a look at [example.js](https://github.com/pedroslopez/whatsapp-web.js/blob/master/example.js) for another example with more use cases.
## Remote Access
You could also connect to any previously existing browser instance:
```js
const client = new Client({
puppeteer: {
browserWSEndpoint: `ws://localhost:3000`
}
});
```
### Docker
1) Installing a browser using browserless:
```
docker run \
--rm \
-p 3000:3000 \
-e "MAX_CONCURRENT_SESSIONS=1" \
browserless/chrome:latest
```
Reference: https://docs.browserless.io/docs/docker-quickstart.html
### Remote Debugging
2) Running a browser with websocket remote debugging enabled:
> chrome.exe --remote-debugging-port=9222
After that check the following webpage and check http://127.0.0.1:9220/json and get the **webSocketDebuggerUrl**
## Supported features
| Feature | Status |
@@ -46,11 +87,13 @@ Take a look at [example.js](https://github.com/pedroslopez/whatsapp-web.js/blob/
| Send messages | ✅ |
| Receive messages | ✅ |
| Send media (images/audio/documents) | ✅ |
| Send media (video) | ✅ [(requires google chrome)](https://github.com/pedroslopez/whatsapp-web.js/issues/78#issuecomment-592723583) |
| Send stickers | _pending_ |
| Send media (video) | ✅ [(requires google chrome)](https://wwebjs.dev/guide/handling-attachments.html#caveat-for-sending-videos-and-gifs) |
| Send stickers | |
| Receive media (images/audio/video/documents) | ✅ |
| Send contact cards | ✅ |
| Send location | ✅ |
| Send buttons | ✅ |
| Send lists | ✅ (business accounts not supported) |
| Receive location | ✅ |
| Message replies | ✅ |
| Join groups by invite | ✅ |
@@ -69,12 +112,6 @@ Take a look at [example.js](https://github.com/pedroslopez/whatsapp-web.js/blob/
Something missing? Make an issue and let us know!
## Links
* [Reference](https://pedroslopez.me/whatsapp-web.js)
* [Guide](https://waguide.pedroslopez.me/) _(work in progress)_
* [GitHub](https://github.com/pedroslopez/whatsapp-web.js)
## Contributing
Pull requests are welcome! If you see something you'd like to add, please do. For drastic changes, please open an issue first.

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: Base</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: Base</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -50,7 +50,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: BusinessContact</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: BusinessContact</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -101,6 +101,9 @@
<dt><a href="BusinessContact.html#block">block()</a></dt>
<dd>
</dd>
<dt><a href="BusinessContact.html#getAbout">getAbout()</a></dt>
<dd>
</dd>
<dt><a href="BusinessContact.html#getChat">getChat()</a></dt>
<dd>
</dd>
@@ -108,15 +111,23 @@
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="BusinessContact.html#getProfilePicUrl">getProfilePicUrl()</a></dt>
<dt><a href="BusinessContact.html#getCountryCode">getCountryCode()</a></dt>
<dd>
</dd>
<dt><a href="BusinessContact.html#unblock">unblock()</a></dt>
<dt><a href="BusinessContact.html#getFormattedNumber">getFormattedNumber()</a></dt>
<dd>
</dd>
<dt><a href="BusinessContact.html#getProfilePicUrl">getProfilePicUrl()</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="BusinessContact.html#unblock">unblock()</a></dt>
<dd>
</dd>
</dl>
</div>
</div>
</div>
@@ -239,6 +250,15 @@
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getAbout"><span class="symbol-name">getAbout</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing nullable string</span></span></h3>
<p>Gets the Contact's current &quot;about&quot; info. Returns null if you don't have permission to read their status.</p>
<dl class="dl-compact">
<dt>Inherited from</dt>
<dd><a href="Contact.html#getAbout">Contact#getAbout</a></dd>
<dt>Returns</dt>
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getChat"><span class="symbol-name">getChat</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="Chat.html">Chat</a></span></span></h3>
<p>Returns the Chat that corresponds to this Contact.
Will return null when getting chat for currently logged in user.</p>
@@ -249,6 +269,24 @@
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getCountryCode"><span class="symbol-name">getCountryCode</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Returns the contact's countrycode, (1541859685@c.us) =&gt; (1)</p>
<dl class="dl-compact">
<dt>Inherited from</dt>
<dd><a href="Contact.html#getCountryCode">Contact#getCountryCode</a></dd>
<dt>Returns</dt>
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getFormattedNumber"><span class="symbol-name">getFormattedNumber</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Returns the contact's formatted phone number, (12345678901@c.us) =&gt; (+1 (234) 5678-901)</p>
<dl class="dl-compact">
<dt>Inherited from</dt>
<dd><a href="Contact.html#getFormattedNumber">Contact#getFormattedNumber</a></dd>
<dt>Returns</dt>
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getProfilePicUrl"><span class="symbol-name">getProfilePicUrl</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Returns the contact's profile picture URL, if privacy settings allow it</p>
<dl class="dl-compact">
@@ -276,7 +314,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

249
docs/Buttons.html Normal file
View File

@@ -0,0 +1,249 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Class: Buttons</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-main" role="main">
<header class="page-header">
<div class="symbol-detail-labels"><span class="label label-kind">class</span></div>
<h1><small></small><span class="symbol-name">Buttons</span></h1>
<p class="source-link">Source: <a href="structures_Buttons.js.html#source-line-23">structures/<wbr>Buttons.<wbr>js:23</a></p>
<div class="symbol-classdesc">
<p>Message type buttons</p>
</div>
<dl class="dl-compact">
</dl>
</header>
<section id="summary">
<div class="summary-callout">
<h2 class="summary-callout-heading">Properties</h2>
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Buttons.html#body">body</a></dt>
<dd>
</dd>
<dt><a href="Buttons.html#buttons">buttons</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Buttons.html#footer">footer</a></dt>
<dd>
</dd>
<dt><a href="Buttons.html#title">title</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
</div>
</div>
</div>
<div class="summary-callout">
<h2 class="summary-callout-heading">Method</h2>
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Buttons.html#_format">_format(buttons)</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
</div>
<div class="summary-column">
</div>
</div>
</div>
</section>
<section>
<h2 id="Buttons">new&nbsp;<span class="symbol-name">Buttons</span><span class="signature"><span class="signature-params">(body, buttons, title, footer)</span></span></h2>
<section>
<h3>Parameters</h3>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>body</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>buttons</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>See <a href="global.html#ButtonSpec"><code>ButtonSpec</code></a></p>
</td>
</tr>
<tr>
<td>
<p>title</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Value can be null.</p>
</td>
</tr>
<tr>
<td>
<p>footer</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Value can be null.</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
</section>
<section>
<h2>Properties</h2>
<section>
<h3 id="body"><span class="symbol-name">body</span><small class="property-type">
&nbsp;(string or <a href="MessageMedia.html">MessageMedia</a>)</small></h3>
<p>Message body</p>
<dl class="dl-compact">
</dl>
<h3 id="buttons"><span class="symbol-name">buttons</span><small class="property-type">
&nbsp;Array of <a href="global.html#FormattedButtonSpec">FormattedButtonSpec</a></small></h3>
<p>buttons of message</p>
<dl class="dl-compact">
</dl>
<h3 id="footer"><span class="symbol-name">footer</span><small class="property-type">
&nbsp;string</small></h3>
<p>footer of message</p>
<dl class="dl-compact">
</dl>
<h3 id="title"><span class="symbol-name">title</span><small class="property-type">
&nbsp;string</small></h3>
<p>title of message</p>
<dl class="dl-compact">
</dl>
</section>
<h2>Method</h2>
<section>
<h3 id="_format"><span class="symbol-name">_format</span><span class="signature"><span class="signature-params">(buttons)</span>&nbsp;&rarr; <span class="signature-returns"> Array of <a href="global.html#FormattedButtonSpec">FormattedButtonSpec</a></span></span></h3>
<p>Creates button array from simple array</p>
<section>
<h4>
Example
</h4>
<div>
<pre class="prettyprint"><code>Input: [{id:&#x27;customId&#x27;,body:&#x27;button1&#x27;},{body:&#x27;button2&#x27;},{body:&#x27;button3&#x27;},{body:&#x27;button4&#x27;}]
Returns: [{ buttonId:&#x27;customId&#x27;,buttonText:{&#x27;displayText&#x27;:&#x27;button1&#x27;},type: 1 },{buttonId:&#x27;n3XKsL&#x27;,buttonText:{&#x27;displayText&#x27;:&#x27;button2&#x27;},type:1},{buttonId:&#x27;NDJk0a&#x27;,buttonText:{&#x27;displayText&#x27;:&#x27;button3&#x27;},type:1}]</code></pre>
</div>
</section>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>buttons</p>
</td>
<td>
<p>Array of <a href="global.html#ButtonSpec">ButtonSpec</a></p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Array of <a href="global.html#FormattedButtonSpec">FormattedButtonSpec</a></code> </p>
</dd>
</dl>
</section>
</section>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

1
docs/CNAME Normal file
View File

@@ -0,0 +1 @@
docs.wwebjs.dev

159
docs/Call.html Normal file
View File

@@ -0,0 +1,159 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Class: Call</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-main" role="main">
<header class="page-header">
<div class="symbol-detail-labels"><span class="label label-kind">class</span></div>
<h1><small></small><span class="symbol-name">Call</span></h1>
<p class="source-link">Source: <a href="structures_Call.js.html#source-line-9">structures/<wbr>Call.<wbr>js:9</a></p>
<div class="symbol-classdesc">
<p>Represents a Call on WhatsApp</p>
</div>
<dl class="dl-compact">
</dl>
</header>
<section id="summary">
<div class="summary-callout">
<h2 class="summary-callout-heading">Properties</h2>
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Call.html#canHandleLocally">canHandleLocally</a></dt>
<dd>
</dd>
<dt><a href="Call.html#from">from</a></dt>
<dd>
</dd>
<dt><a href="Call.html#fromMe">fromMe</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Call.html#id">id</a></dt>
<dd>
</dd>
<dt><a href="Call.html#isGroup">isGroup</a></dt>
<dd>
</dd>
<dt><a href="Call.html#isVideo">isVideo</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Call.html#participants">participants</a></dt>
<dd>
</dd>
<dt><a href="Call.html#timestamp">timestamp</a></dt>
<dd>
</dd>
<dt><a href="Call.html#webClientShouldHandle">webClientShouldHandle</a></dt>
<dd>
</dd>
</dl>
</div>
</div>
</div>
</section>
<section>
<h2 id="Call">new&nbsp;<span class="symbol-name">Call</span><span class="signature"><span class="signature-params">()</span></span></h2>
<dl class="dl-compact">
<dt>Extends</dt>
<dd><a href="Base.html">Base</a></dd>
</dl>
</section>
<section>
<h2>Properties</h2>
<section>
<h3 id="canHandleLocally"><span class="symbol-name">canHandleLocally</span><small class="property-type">
&nbsp;boolean</small></h3>
<p>Indicates if the call can be handled in waweb</p>
<dl class="dl-compact">
</dl>
<h3 id="from"><span class="symbol-name">from</span><small class="property-type">
&nbsp;string</small></h3>
<p>From</p>
<dl class="dl-compact">
</dl>
<h3 id="fromMe"><span class="symbol-name">fromMe</span><small class="property-type">
&nbsp;boolean</small></h3>
<p>Indicates if the call was sent by the current user</p>
<dl class="dl-compact">
</dl>
<h3 id="id"><span class="symbol-name">id</span><small class="property-type">
&nbsp;string</small></h3>
<p>Call ID</p>
<dl class="dl-compact">
</dl>
<h3 id="isGroup"><span class="symbol-name">isGroup</span><small class="property-type">
&nbsp;boolean</small></h3>
<p>Is Group</p>
<dl class="dl-compact">
</dl>
<h3 id="isVideo"><span class="symbol-name">isVideo</span><small class="property-type">
&nbsp;boolean</small></h3>
<p>Is video</p>
<dl class="dl-compact">
</dl>
<h3 id="participants"><span class="symbol-name">participants</span><small class="property-type">
&nbsp;object</small></h3>
<p>Object with participants</p>
<dl class="dl-compact">
</dl>
<h3 id="timestamp"><span class="symbol-name">timestamp</span><small class="property-type">
&nbsp;number</small></h3>
<p>Unix timestamp for when the call was created</p>
<dl class="dl-compact">
</dl>
<h3 id="webClientShouldHandle"><span class="symbol-name">webClientShouldHandle</span><small class="property-type">
&nbsp;boolean</small></h3>
<p>Indicates if the call Should be handled in waweb</p>
<dl class="dl-compact">
</dl>
</section>
</section>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: Chat</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: Chat</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -101,11 +101,17 @@
<dt><a href="Chat.html#fetchMessages">fetchMessages(searchOptions)</a></dt>
<dd>
</dd>
<dt><a href="Chat.html#getContact">getContact()</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Chat.html#getContact">getContact()</a></dt>
<dt><a href="Chat.html#getLabels">getLabels()</a></dt>
<dd>
</dd>
<dt><a href="Chat.html#markUnread">markUnread()</a></dt>
<dd>
</dd>
<dt><a href="Chat.html#mute">mute(unmuteDate)</a></dt>
@@ -170,7 +176,7 @@
<dl class="dl-compact">
</dl>
<h3 id="isMuted"><span class="symbol-name">isMuted</span><small class="property-type">
&nbsp;number</small></h3>
&nbsp;boolean</small></h3>
<p>Indicates if the chat is muted or not</p>
<dl class="dl-compact">
</dl>
@@ -288,8 +294,7 @@
<p>Yes</p>
</td>
<td>
<p>The amount of messages to return. Note that the actual number of returned messages may be smaller if there aren't enough messages in the conversation. Set this to Infinity to load all messages.</p>
<p>Defaults to <code>50</code>.</p>
<p>The amount of messages to return. If no limit is specified, the available messages will be returned. Note that the actual number of returned messages may be smaller if there aren't enough messages in the conversation. Set this to Infinity to load all messages.</p>
</td>
</tr>
</tbody>
@@ -315,8 +320,22 @@
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getLabels"><span class="symbol-name">getLabels</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Array of <a href="Label.html">Label</a></span></span></h3>
<p>Returns array of all Labels assigned to this Chat</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing Array of <a href="Label.html">Label</a></code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="markUnread"><span class="symbol-name">markUnread</span><span class="signature"><span class="signature-params">()</span></span></h3>
<p>Mark this chat as unread</p>
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="mute"><span class="symbol-name">mute</span><span class="signature"><span class="signature-params">(unmuteDate)</span></span></h3>
<p>Mutes this chat until a specified date</p>
<p>Mutes this chat forever, unless a date is specified</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
@@ -340,7 +359,8 @@
<p>&nbsp;</p>
</td>
<td>
<p>Date at which the Chat will be unmuted</p>
<p>Date at which the Chat will be unmuted, leave as is to mute forever</p>
<p>Value can be null.</p>
</td>
</tr>
</tbody>
@@ -463,7 +483,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: Client</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: Client</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -26,7 +26,7 @@
<header class="page-header">
<div class="symbol-detail-labels"><span class="label label-kind">class</span></div>
<h1><small></small><span class="symbol-name">Client</span></h1>
<p class="source-link">Source: <a href="Client.js.html#source-line-50">Client.<wbr>js:50</a></p>
<p class="source-link">Source: <a href="Client.js.html#source-line-53">Client.<wbr>js:53</a></p>
<div class="symbol-classdesc">
<p>Starting point for interacting with the WhatsApp Web API</p>
</div>
@@ -55,6 +55,9 @@
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Client.html#acceptGroupV4Invite">acceptGroupV4Invite(inviteV4)</a></dt>
<dd>
</dd>
<dt><a href="Client.html#acceptInvite">acceptInvite(inviteCode)</a></dt>
<dd>
</dd>
@@ -67,25 +70,49 @@
<dt><a href="Client.html#destroy">destroy()</a></dt>
<dd>
</dd>
<dt><a href="Client.html#getBlockedContacts">getBlockedContacts()</a></dt>
<dd>
</dd>
<dt><a href="Client.html#getChatById">getChatById(chatId)</a></dt>
<dd>
</dd>
<dt><a href="Client.html#getChatLabels">getChatLabels(chatId)</a></dt>
<dd>
</dd>
<dt><a href="Client.html#getChats">getChats()</a></dt>
<dd>
</dd>
<dt><a href="Client.html#getChatsByLabelId">getChatsByLabelId(labelId)</a></dt>
<dd>
</dd>
<dt><a href="Client.html#getContactById">getContactById(contactId)</a></dt>
<dd>
</dd>
<dt><a href="Client.html#getContacts">getContacts()</a></dt>
<dd>
</dd>
<dt><a href="Client.html#getInviteInfo">getInviteInfo(inviteCode)</a></dt>
<dt><a href="Client.html#getCountryCode">getCountryCode(number)</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Client.html#getFormattedNumber">getFormattedNumber(number)</a></dt>
<dd>
</dd>
<dt><a href="Client.html#getInviteInfo">getInviteInfo(inviteCode)</a></dt>
<dd>
</dd>
<dt><a href="Client.html#getLabelById">getLabelById(labelId)</a></dt>
<dd>
</dd>
<dt><a href="Client.html#getLabels">getLabels()</a></dt>
<dd>
</dd>
<dt><a href="Client.html#getNumberId">getNumberId(number)</a></dt>
<dd>
</dd>
<dt><a href="Client.html#getProfilePicUrl">getProfilePicUrl(contactId)</a></dt>
<dd>
</dd>
@@ -104,19 +131,25 @@
<dt><a href="Client.html#logout">logout()</a></dt>
<dd>
</dd>
<dt><a href="Client.html#markChatUnread">markChatUnread(chatId)</a></dt>
<dd>
</dd>
<dt><a href="Client.html#muteChat">muteChat(chatId, unmuteDate)</a></dt>
<dd>
</dd>
<dt><a href="Client.html#pinChat">pinChat()</a></dt>
<dd>
</dd>
<dt><a href="Client.html#resetState">resetState()</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Client.html#pinChat">pinChat()</a></dt>
<dd>
</dd>
<dt><a href="Client.html#resetState">resetState()</a></dt>
<dd>
</dd>
<dt><a href="Client.html#searchMessages">searchMessages(query[, options])</a></dt>
<dd>
</dd>
<dt><a href="Client.html#sendMessage">sendMessage(chatId, content[, options])</a></dt>
<dd>
</dd>
@@ -178,6 +211,9 @@
<dt><a href="Client.html#event:group_update">group_update</a></dt>
<dd>
</dd>
<dt><a href="Client.html#event:incoming_call">incoming_call</a></dt>
<dd>
</dd>
<dt><a href="Client.html#event:media_uploaded">media_uploaded</a></dt>
<dd>
</dd>
@@ -187,13 +223,13 @@
<dt><a href="Client.html#event:message_ack">message_ack</a></dt>
<dd>
</dd>
<dt><a href="Client.html#event:message_create">message_create</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Client.html#event:message_create">message_create</a></dt>
<dd>
</dd>
<dt><a href="Client.html#event:message_revoke_everyone">message_revoke_everyone</a></dt>
<dd>
</dd>
@@ -304,6 +340,20 @@
<p>Timeout for qr code selector in puppeteer</p>
</td>
</tr>
<tr>
<td>
<p>qrMaxRetries</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>How many times should the qrcode be refreshed before giving up</p>
</td>
</tr>
<tr>
<td>
<p>restartOnAuthFail</p>
@@ -426,6 +476,34 @@
<p>User agent to use in puppeteer</p>
</td>
</tr>
<tr>
<td>
<p>ffmpegPath</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Ffmpeg path to use when formating videos to webp while sending stickers</p>
</td>
</tr>
<tr>
<td>
<p>bypassCSP</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Sets bypassing of page's Content-Security-Policy.</p>
</td>
</tr>
</tbody>
</table>
</td>
@@ -467,7 +545,45 @@
<h2>Methods</h2>
<section>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="acceptInvite"><span class="symbol-name">acceptInvite</span><span class="signature"><span class="signature-params">(inviteCode)</span></span></h3>
<h3 id="acceptGroupV4Invite"><span class="symbol-name">acceptGroupV4Invite</span><span class="signature"><span class="signature-params">(inviteV4)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Object</span></span></h3>
<p>Accepts a private invitation to join a group</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>inviteV4</p>
</td>
<td>
<p>object</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Invite V4 Info</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing Object</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="acceptInvite"><span class="symbol-name">acceptInvite</span><span class="signature"><span class="signature-params">(inviteCode)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Accepts an invitation to join a group</p>
<section>
<h4>Parameter</h4>
@@ -499,6 +615,12 @@
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing string</code> 
<p>Id of the joined Chat</p>
</p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="archiveChat"><span class="symbol-name">archiveChat</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> boolean</span></span></h3>
@@ -579,6 +701,15 @@
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getBlockedContacts"><span class="symbol-name">getBlockedContacts</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Array of <a href="Contact.html">Contact</a></span></span></h3>
<p>Gets all blocked contacts by host account</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing Array of <a href="Contact.html">Contact</a></code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getChatById"><span class="symbol-name">getChatById</span><span class="signature"><span class="signature-params">(chatId)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="Chat.html">Chat</a></span></span></h3>
<p>Get chat instance by ID</p>
<section>
@@ -616,6 +747,43 @@
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getChatLabels"><span class="symbol-name">getChatLabels</span><span class="signature"><span class="signature-params">(chatId)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Array of <a href="Label.html">Label</a></span></span></h3>
<p>Get all Labels assigned to a chat</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>chatId</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing Array of <a href="Label.html">Label</a></code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getChats"><span class="symbol-name">getChats</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Array of <a href="Chat.html">Chat</a></span></span></h3>
<p>Get all current chat instances</p>
<dl class="dl-compact">
@@ -625,6 +793,43 @@
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getChatsByLabelId"><span class="symbol-name">getChatsByLabelId</span><span class="signature"><span class="signature-params">(labelId)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Array of <a href="Chat.html">Chat</a></span></span></h3>
<p>Get all Chats for a specific Label</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>labelId</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing Array of <a href="Chat.html">Chat</a></code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getContactById"><span class="symbol-name">getContactById</span><span class="signature"><span class="signature-params">(contactId)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="Contact.html">Contact</a></span></span></h3>
<p>Get contact instance by ID</p>
<section>
@@ -671,6 +876,82 @@
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getCountryCode"><span class="symbol-name">getCountryCode</span><span class="signature"><span class="signature-params">(number)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Get the country code of a WhatsApp ID.</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>number</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Number or ID</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing string</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getFormattedNumber"><span class="symbol-name">getFormattedNumber</span><span class="signature"><span class="signature-params">(number)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Get the formatted number of a WhatsApp ID.</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>number</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Number or ID</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing string</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getInviteInfo"><span class="symbol-name">getInviteInfo</span><span class="signature"><span class="signature-params">(inviteCode)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing object</span></span></h3>
<p>Returns an object with information about the invite code's group</p>
<section>
@@ -710,6 +991,91 @@
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getLabelById"><span class="symbol-name">getLabelById</span><span class="signature"><span class="signature-params">(labelId)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="Label.html">Label</a></span></span></h3>
<p>Get Label instance by ID</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>labelId</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing <a href="Label.html">Label</a></code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getLabels"><span class="symbol-name">getLabels</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Array of <a href="Label.html">Label</a></span></span></h3>
<p>Get all current Labels</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing Array of <a href="Label.html">Label</a></code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getNumberId"><span class="symbol-name">getNumberId</span><span class="signature"><span class="signature-params">(number)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing (Object or null)</span></span></h3>
<p>Get the registered WhatsApp ID for a number.
Will return null if the number is not registered on WhatsApp.</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>number</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Number or ID (&quot;@c.us&quot; will be automatically appended if not specified)</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing (Object or null)</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getProfilePicUrl"><span class="symbol-name">getProfilePicUrl</span><span class="signature"><span class="signature-params">(contactId)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Returns the contact ID's profile picture URL, if privacy settings allow it</p>
<section>
@@ -814,8 +1180,42 @@
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="markChatUnread"><span class="symbol-name">markChatUnread</span><span class="signature"><span class="signature-params">(chatId)</span></span></h3>
<p>Mark the Chat as unread</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>chatId</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>ID of the chat that will be marked as unread</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="muteChat"><span class="symbol-name">muteChat</span><span class="signature"><span class="signature-params">(chatId, unmuteDate)</span></span></h3>
<p>Mutes the Chat until a specified date</p>
<p>Mutes this chat forever, unless a date is specified</p>
<section>
<h4>Parameters</h4>
<table class="jsdoc-details-table">
@@ -853,7 +1253,8 @@
<p>&nbsp;</p>
</td>
<td>
<p>Date when the chat will be unmuted</p>
<p>Date when the chat will be unmuted, leave as is to mute forever</p>
<p>Value can be null.</p>
</td>
</tr>
</tbody>
@@ -878,6 +1279,108 @@
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="searchMessages"><span class="symbol-name">searchMessages</span><span class="signature"><span class="signature-params">(query[, options])</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Array of <a href="Message.html">Message</a></span></span></h3>
<p>Searches for messages</p>
<section>
<h4>Parameters</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>query</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>options</p>
</td>
<td>
<p>Object</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>Values in <code>options</code> have the following properties:</p>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>page</p>
</td>
<td>
<p>number</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>limit</p>
</td>
<td>
<p>number</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>chatId</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing Array of <a href="Message.html">Message</a></code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="sendMessage"><span class="symbol-name">sendMessage</span><span class="signature"><span class="signature-params">(chatId, content[, options])</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="Message.html">Message</a></span></span></h3>
<p>Send a message to a specific chatId</p>
<section>
@@ -910,7 +1413,7 @@
<p>content</p>
</td>
<td>
<p>(string, <a href="MessageMedia.html">MessageMedia</a>, <a href="Location.html">Location</a>, <a href="Contact.html">Contact</a>, or Array of <a href="Contact.html">Contact</a>)</p>
<p>(string, <a href="MessageMedia.html">MessageMedia</a>, <a href="Location.html">Location</a>, <a href="Contact.html">Contact</a>, Array of <a href="Contact.html">Contact</a>, <a href="Buttons.html">Buttons</a>, or <a href="List.html">List</a>)</p>
</td>
<td>
<p>&nbsp;</p>
@@ -1368,13 +1871,13 @@
<p>reason</p>
</td>
<td>
<p><a href="global.html#WAState">WAState</a></p>
<p>(<a href="global.html#WAState">WAState</a> or "NAVIGATION")</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>state that caused the disconnect</p>
<p>reason that caused the disconnect</p>
</td>
</tr>
</tbody>
@@ -1481,6 +1984,163 @@
</section>
<dl class="dl-compact">
</dl>
<h3 id="event:incoming_call"><span class="symbol-name">incoming_call</span></h3>
<p>Emitted when a call is received</p>
<section>
<h4>Parameters</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>call</p>
</td>
<td>
<p>object</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Values in <code>call</code> have the following properties:</p>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>id</p>
</td>
<td>
<p>number</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Call id</p>
</td>
</tr>
<tr>
<td>
<p>peerJid</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Who called</p>
</td>
</tr>
<tr>
<td>
<p>isVideo</p>
</td>
<td>
<p>boolean</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>if is video</p>
</td>
</tr>
<tr>
<td>
<p>isGroup</p>
</td>
<td>
<p>boolean</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>if is group</p>
</td>
</tr>
<tr>
<td>
<p>canHandleLocally</p>
</td>
<td>
<p>boolean</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>if we can handle in waweb</p>
</td>
</tr>
<tr>
<td>
<p>outgoing</p>
</td>
<td>
<p>boolean</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>if is outgoing</p>
</td>
</tr>
<tr>
<td>
<p>webClientShouldHandle</p>
</td>
<td>
<p>boolean</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>If Waweb should handle</p>
</td>
</tr>
<tr>
<td>
<p>participants</p>
</td>
<td>
<p>object</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Participants</p>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
<h3 id="event:media_uploaded"><span class="symbol-name">media_uploaded</span></h3>
<p>Emitted when media has been uploaded for a message sent by the client.</p>
<section>
@@ -1756,7 +2416,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: Client.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: Client.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -42,7 +42,7 @@ const { WhatsWebURL, DefaultOptions, Events, WAState } &#x3D; require(&#x27;./ut
const { ExposeStore, LoadUtils } &#x3D; require(&#x27;./util/Injected&#x27;);
const ChatFactory &#x3D; require(&#x27;./factories/ChatFactory&#x27;);
const ContactFactory &#x3D; require(&#x27;./factories/ContactFactory&#x27;);
const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification } &#x3D; require(&#x27;./structures&#x27;);
const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification , Label, Call, Buttons, List} &#x3D; require(&#x27;./structures&#x27;);
/**
* Starting point for interacting with the WhatsApp Web API
* @extends {EventEmitter}
@@ -51,6 +51,7 @@ const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification
* @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 &#x27;session&#x27; 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
@@ -60,6 +61,8 @@ const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification
* @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
* @param {string} options.ffmpegPath - Ffmpeg path to use when formating videos to webp while sending stickers
* @param {boolean} options.bypassCSP - Sets bypassing of page&#x27;s Content-Security-Policy.
*
* @fires Client#qr
* @fires Client#authenticated
@@ -86,39 +89,61 @@ class Client extends EventEmitter {
this.pupBrowser &#x3D; null;
this.pupPage &#x3D; null;
Util.setFfmpegPath(this.options.ffmpegPath);
}
/**
* Sets up events and requirements, kicks off authentication request
*/
async initialize() {
const browser &#x3D; await puppeteer.launch(this.options.puppeteer);
const page &#x3D; (await browser.pages())[0];
page.setUserAgent(this.options.userAgent);
let [browser, page] &#x3D; [null, null];
if(this.options.puppeteer &amp;amp;&amp;amp; this.options.puppeteer.browserWSEndpoint) {
browser &#x3D; await puppeteer.connect(this.options.puppeteer);
page &#x3D; await browser.newPage();
} else {
browser &#x3D; await puppeteer.launch(this.options.puppeteer);
page &#x3D; (await browser.pages())[0];
}
await page.setUserAgent(this.options.userAgent);
this.pupBrowser &#x3D; browser;
this.pupPage &#x3D; page;
// remember me
await page.evaluateOnNewDocument(() &#x3D;&gt; {
localStorage.setItem(&#x27;remember-me&#x27;, &#x27;true&#x27;);
});
if (this.options.session) {
await page.evaluateOnNewDocument(
session &#x3D;&gt; {
localStorage.clear();
localStorage.setItem(&#x27;WABrowserId&#x27;, session.WABrowserId);
localStorage.setItem(&#x27;WASecretBundle&#x27;, session.WASecretBundle);
localStorage.setItem(&#x27;WAToken1&#x27;, session.WAToken1);
localStorage.setItem(&#x27;WAToken2&#x27;, session.WAToken2);
if(document.referrer &#x3D;&#x3D;&#x3D; &#x27;https://whatsapp.com/&#x27;) {
localStorage.clear();
localStorage.setItem(&#x27;WABrowserId&#x27;, session.WABrowserId);
localStorage.setItem(&#x27;WASecretBundle&#x27;, session.WASecretBundle);
localStorage.setItem(&#x27;WAToken1&#x27;, session.WAToken1);
localStorage.setItem(&#x27;WAToken2&#x27;, session.WAToken2);
}
}, this.options.session);
}
if(this.options.bypassCSP) {
await page.setBypassCSP(true);
}
await page.goto(WhatsWebURL, {
waitUntil: &#x27;load&#x27;,
timeout: 0,
referer: &#x27;https://whatsapp.com/&#x27;
});
const KEEP_PHONE_CONNECTED_IMG_SELECTOR &#x3D; &#x27;[data-asset-intro-image-light&#x3D;&quot;true&quot;], [data-asset-intro-image-dark&#x3D;&quot;true&quot;]&#x27;;
const KEEP_PHONE_CONNECTED_IMG_SELECTOR &#x3D; &#x27;[data-icon&#x3D;&quot;intro-md-beta-logo-dark&quot;], [data-icon&#x3D;&quot;intro-md-beta-logo-light&quot;], [data-asset-intro-image-light&#x3D;&quot;true&quot;], [data-asset-intro-image-dark&#x3D;&quot;true&quot;]&#x27;;
if (this.options.session) {
// Check if session restore was successfull
// Check if session restore was successful
try {
await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: this.options.authTimeoutMs });
} catch (err) {
@@ -142,39 +167,61 @@ class Client extends EventEmitter {
}
} else {
let qrRetries &#x3D; 0;
const getQrCode &#x3D; async () &#x3D;&gt; {
// Check if retry button is present
var QR_RETRY_SELECTOR &#x3D; &#x27;div[data-ref] &gt; span &gt; div&#x27;;
var QR_RETRY_SELECTOR &#x3D; &#x27;div[data-ref] &gt; span &gt; button&#x27;;
var qrRetry &#x3D; await page.$(QR_RETRY_SELECTOR);
if (qrRetry) {
await qrRetry.click();
}
// Wait for QR Code
const QR_CANVAS_SELECTOR &#x3D; &#x27;canvas&#x27;;
await page.waitForSelector(QR_CANVAS_SELECTOR, { timeout: this.options.qrTimeoutMs });
const qrImgData &#x3D; await page.$eval(QR_CANVAS_SELECTOR, canvas &#x3D;&gt; [].slice.call(canvas.getContext(&#x27;2d&#x27;).getImageData(0, 0, 264, 264).data));
const qr &#x3D; jsQR(qrImgData, 264, 264).data;
/**
* Emitted when the QR code is received
* @event Client#qr
* @param {string} qr QR Code
*/
this.emit(Events.QR_RECEIVED, qr);
if (this.options.qrMaxRetries &gt; 0) {
qrRetries++;
if (qrRetries &gt; this.options.qrMaxRetries) {
this.emit(Events.DISCONNECTED, &#x27;Max qrcode retries reached&#x27;);
await this.destroy();
}
}
};
getQrCode();
this._qrRefreshInterval &#x3D; setInterval(getQrCode, this.options.qrRefreshIntervalMs);
// Wait for code scan
await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: 0 });
clearInterval(this._qrRefreshInterval);
this._qrRefreshInterval &#x3D; undefined;
try {
await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: 0 });
clearInterval(this._qrRefreshInterval);
this._qrRefreshInterval &#x3D; undefined;
} catch(error) {
if (
error.name &#x3D;&#x3D;&#x3D; &#x27;ProtocolError&#x27; &amp;amp;&amp;amp;
error.message &amp;amp;&amp;amp;
error.message.match(/Target closed/)
) {
// something has called .destroy() while waiting
return;
}
throw error;
}
}
await page.evaluate(ExposeStore, moduleRaid.toString());
// Get session tokens
const localStorage &#x3D; JSON.parse(await page.evaluate(() &#x3D;&gt; {
return JSON.stringify(window.localStorage);
@@ -201,6 +248,14 @@ class Client extends EventEmitter {
// Check window.Store Injection
await page.waitForFunction(&#x27;window.Store !&#x3D; undefined&#x27;);
const isMD &#x3D; await page.evaluate(() &#x3D;&gt; {
return window.Store.Features.features.MD_BACKEND;
});
if(isMD) {
throw new Error(&#x27;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.&#x27;);
}
//Load util functions (serializers, helper functions)
await page.evaluate(LoadUtils);
@@ -218,8 +273,6 @@ class Client extends EventEmitter {
// Register events
await page.exposeFunction(&#x27;onAddMessageEvent&#x27;, msg &#x3D;&gt; {
if (!msg.isNewMsg) return;
if (msg.type &#x3D;&#x3D;&#x3D; &#x27;gp2&#x27;) {
const notification &#x3D; new GroupNotification(this, msg);
if (msg.subtype &#x3D;&#x3D;&#x3D; &#x27;add&#x27; || msg.subtype &#x3D;&#x3D;&#x3D; &#x27;invite&#x27;) {
@@ -363,7 +416,7 @@ class Client extends EventEmitter {
/**
* Emitted when the client has been disconnected
* @event Client#disconnected
* @param {WAState} reason state that caused the disconnect
* @param {WAState|&quot;NAVIGATION&quot;} reason reason that caused the disconnect
*/
this.emit(Events.DISCONNECTED, state);
this.destroy();
@@ -385,8 +438,25 @@ class Client extends EventEmitter {
this.emit(Events.BATTERY_CHANGED, { battery, plugged });
});
await page.exposeFunction(&#x27;onIncomingCall&#x27;, (call) &#x3D;&gt; {
/**
* Emitted when a call is received
* @event Client#incoming_call
* @param {object} call
* @param {number} call.id - Call id
* @param {string} call.peerJid - Who called
* @param {boolean} call.isVideo - if is video
* @param {boolean} call.isGroup - if is group
* @param {boolean} call.canHandleLocally - if we can handle in waweb
* @param {boolean} call.outgoing - if is outgoing
* @param {boolean} call.webClientShouldHandle - If Waweb should handle
* @param {object} call.participants - Participants
*/
const cll &#x3D; new Call(this,call);
this.emit(Events.INCOMING_CALL, cll);
});
await page.evaluate(() &#x3D;&gt; {
window.Store.Msg.on(&#x27;add&#x27;, (msg) &#x3D;&gt; { if (msg.isNewMsg) window.onAddMessageEvent(window.WWebJS.getMessageModel(msg)); });
window.Store.Msg.on(&#x27;change&#x27;, (msg) &#x3D;&gt; { window.onChangeMessageEvent(window.WWebJS.getMessageModel(msg)); });
window.Store.Msg.on(&#x27;change:type&#x27;, (msg) &#x3D;&gt; { window.onChangeMessageTypeEvent(window.WWebJS.getMessageModel(msg)); });
window.Store.Msg.on(&#x27;change:ack&#x27;, (msg,ack) &#x3D;&gt; { window.onMessageAckEvent(window.WWebJS.getMessageModel(msg), ack); });
@@ -394,6 +464,17 @@ class Client extends EventEmitter {
window.Store.Msg.on(&#x27;remove&#x27;, (msg) &#x3D;&gt; { if (msg.isNewMsg) window.onRemoveMessageEvent(window.WWebJS.getMessageModel(msg)); });
window.Store.AppState.on(&#x27;change:state&#x27;, (_AppState, state) &#x3D;&gt; { window.onAppStateChangedEvent(state); });
window.Store.Conn.on(&#x27;change:battery&#x27;, (state) &#x3D;&gt; { window.onBatteryStateChangedEvent(state); });
window.Store.Call.on(&#x27;add&#x27;, (call) &#x3D;&gt; { window.onIncomingCall(call); });
window.Store.Msg.on(&#x27;add&#x27;, (msg) &#x3D;&gt; {
if (msg.isNewMsg) {
if(msg.type &#x3D;&#x3D;&#x3D; &#x27;ciphertext&#x27;) {
// defer message event until ciphertext is resolved (type changed)
msg.once(&#x27;change:type&#x27;, (_msg) &#x3D;&gt; window.onAddMessageEvent(window.WWebJS.getMessageModel(_msg)));
} else {
window.onAddMessageEvent(window.WWebJS.getMessageModel(msg));
}
}
});
});
/**
@@ -401,6 +482,15 @@ class Client extends EventEmitter {
* @event Client#ready
*/
this.emit(Events.READY);
// Disconnect when navigating away when in PAIRING state (detect logout)
this.pupPage.on(&#x27;framenavigated&#x27;, async () &#x3D;&gt; {
const appState &#x3D; await this.getState();
if(!appState || appState &#x3D;&#x3D;&#x3D; WAState.PAIRING) {
this.emit(Events.DISCONNECTED, &#x27;NAVIGATION&#x27;);
await this.destroy();
}
});
}
/**
@@ -451,18 +541,24 @@ class Client extends EventEmitter {
* @typedef {Object} MessageSendOptions
* @property {boolean} [linkPreview&#x3D;true] - Show links preview
* @property {boolean} [sendAudioAsVoice&#x3D;false] - Send audio as voice message
* @property {boolean} [sendVideoAsGif&#x3D;false] - Send video as gif
* @property {boolean} [sendMediaAsSticker&#x3D;false] - Send media as a sticker
* @property {boolean} [sendMediaAsDocument&#x3D;false] - Send media as a document
* @property {boolean} [parseVCards&#x3D;true] - Automatically parse vCards and send them as contacts
* @property {string} [caption] - Image or video caption
* @property {string} [quotedMessageId] - Id of the message that is being quoted (or replied to)
* @property {Contact[]} [mentions] - Contacts that are being mentioned in the message
* @property {boolean} [sendSeen&#x3D;true] - Mark the conversation as seen after sending the message
* @property {boolean} [media] - Media to be sent
* @property {string} [stickerAuthor&#x3D;undefined] - Sets the author of the sticker, (if sendMediaAsSticker is true).
* @property {string} [stickerName&#x3D;undefined] - Sets the name of the sticker, (if sendMediaAsSticker is true).
* @property {string[]} [stickerCategories&#x3D;undefined] - Sets the categories of the sticker, (if sendMediaAsSticker is true). Provide emoji char array, can be null.
* @property {MessageMedia} [media] - Media to be sent
*/
/**
* Send a message to a specific chatId
* @param {string} chatId
* @param {string|MessageMedia|Location|Contact|Array&amp;lt;Contact&gt;} content
* @param {string|MessageMedia|Location|Contact|Array&amp;lt;Contact&gt;|Buttons|List} content
* @param {MessageSendOptions} [options] - Options used when sending the message
*
* @returns {Promise&amp;lt;Message&gt;} Message that was just sent
@@ -471,10 +567,14 @@ class Client extends EventEmitter {
let internalOptions &#x3D; {
linkPreview: options.linkPreview &#x3D;&#x3D;&#x3D; false ? undefined : true,
sendAudioAsVoice: options.sendAudioAsVoice,
sendVideoAsGif: options.sendVideoAsGif,
sendMediaAsSticker: options.sendMediaAsSticker,
sendMediaAsDocument: options.sendMediaAsDocument,
caption: options.caption,
quotedMessageId: options.quotedMessageId,
parseVCards: options.parseVCards &#x3D;&#x3D;&#x3D; false ? false : true,
mentionedJidList: Array.isArray(options.mentions) ? options.mentions.map(contact &#x3D;&gt; contact.id._serialized) : []
mentionedJidList: Array.isArray(options.mentions) ? options.mentions.map(contact &#x3D;&gt; contact.id._serialized) : [],
extraOptions: options.extra
};
const sendSeen &#x3D; typeof options.sendSeen &#x3D;&#x3D;&#x3D; &#x27;undefined&#x27; ? true : options.sendSeen;
@@ -495,6 +595,22 @@ class Client extends EventEmitter {
} else if(Array.isArray(content) &amp;amp;&amp;amp; content.length &gt; 0 &amp;amp;&amp;amp; content[0] instanceof Contact) {
internalOptions.contactCardList &#x3D; content.map(contact &#x3D;&gt; contact.id._serialized);
content &#x3D; &#x27;&#x27;;
} else if(content instanceof Buttons){
if(content.type !&#x3D;&#x3D; &#x27;chat&#x27;){internalOptions.attachment &#x3D; content.body;}
internalOptions.buttons &#x3D; content;
content &#x3D; &#x27;&#x27;;
} else if(content instanceof List){
internalOptions.list &#x3D; content;
content &#x3D; &#x27;&#x27;;
}
if (internalOptions.sendMediaAsSticker &amp;amp;&amp;amp; internalOptions.attachment) {
internalOptions.attachment &#x3D;
await Util.formatToWebpSticker(internalOptions.attachment, {
name: options.stickerName,
author: options.stickerAuthor,
categories: options.stickerCategories
});
}
const newMessage &#x3D; await this.pupPage.evaluate(async (chatId, message, options, sendSeen) &#x3D;&gt; {
@@ -512,6 +628,24 @@ class Client extends EventEmitter {
return new Message(this, newMessage);
}
/**
* Searches for messages
* @param {string} query
* @param {Object} [options]
* @param {number} [options.page]
* @param {number} [options.limit]
* @param {string} [options.chatId]
* @returns {Promise&amp;lt;Message[]&gt;}
*/
async searchMessages(query, options &#x3D; {}) {
const messages &#x3D; await this.pupPage.evaluate(async (query, page, count, remote) &#x3D;&gt; {
const { messages } &#x3D; await window.Store.Msg.search(query, page, count, remote);
return messages.map(msg &#x3D;&gt; window.WWebJS.getMessageModel(msg));
}, query, options.page, options.limit, options.chatId);
return messages.map(msg &#x3D;&gt; new Message(this, msg));
}
/**
* Get all current chat instances
* @returns {Promise&amp;lt;Array&amp;lt;Chat&gt;&gt;}
@@ -576,6 +710,7 @@ class Client extends EventEmitter {
/**
* Accepts an invitation to join a group
* @param {string} inviteCode Invitation code
* @returns {Promise&amp;lt;string&gt;} Id of the joined Chat
*/
async acceptInvite(inviteCode) {
const chatId &#x3D; await this.pupPage.evaluate(async inviteCode &#x3D;&gt; {
@@ -585,6 +720,20 @@ class Client extends EventEmitter {
return chatId._serialized;
}
/**
* Accepts a private invitation to join a group
* @param {object} inviteV4 Invite V4 Info
* @returns {Promise&amp;lt;Object&gt;}
*/
async acceptGroupV4Invite(inviteInfo) {
if(!inviteInfo.inviteCode) throw &#x27;Invalid invite code, try passing the message.inviteV4 object&#x27;;
if (inviteInfo.inviteCodeExp &#x3D;&#x3D; 0) throw &#x27;Expired invite code&#x27;;
return await this.pupPage.evaluate(async inviteInfo &#x3D;&gt; {
let { groupId, fromId, inviteCode, inviteCodeExp, toId } &#x3D; inviteInfo;
return await window.Store.Wap.acceptGroupV4Invite(groupId, fromId, inviteCode, String(inviteCodeExp), toId);
}, inviteInfo);
}
/**
* Sets the current user&#x27;s status message
* @param {string} status New status message
@@ -612,6 +761,7 @@ class Client extends EventEmitter {
*/
async getState() {
return await this.pupPage.evaluate(() &#x3D;&gt; {
if(!window.Store) return null;
return window.Store.AppState.state;
});
}
@@ -633,7 +783,7 @@ class Client extends EventEmitter {
return await this.pupPage.evaluate(async chatId &#x3D;&gt; {
let chat &#x3D; await window.Store.Chat.get(chatId);
await window.Store.Cmd.archiveChat(chat, true);
return chat.archive;
return true;
}, chatId);
}
@@ -645,7 +795,7 @@ class Client extends EventEmitter {
return await this.pupPage.evaluate(async chatId &#x3D;&gt; {
let chat &#x3D; await window.Store.Chat.get(chatId);
await window.Store.Cmd.archiveChat(chat, false);
return chat.archive;
return false;
}, chatId);
}
@@ -687,15 +837,16 @@ class Client extends EventEmitter {
}
/**
* Mutes the Chat until a specified date
* Mutes this chat forever, unless a date is specified
* @param {string} chatId ID of the chat that will be muted
* @param {Date} unmuteDate Date when the chat will be unmuted
* @param {?Date} unmuteDate Date when the chat will be unmuted, leave as is to mute forever
*/
async muteChat(chatId, unmuteDate) {
unmuteDate &#x3D; unmuteDate ? unmuteDate.getTime() / 1000 : -1;
await this.pupPage.evaluate(async (chatId, timestamp) &#x3D;&gt; {
let chat &#x3D; await window.Store.Chat.get(chatId);
await chat.mute.mute(timestamp, !0);
}, chatId, unmuteDate.getTime() / 1000);
}, chatId, unmuteDate || -1);
}
/**
@@ -709,6 +860,17 @@ class Client extends EventEmitter {
}, chatId);
}
/**
* Mark the Chat as unread
* @param {string} chatId ID of the chat that will be marked as unread
*/
async markChatUnread(chatId) {
await this.pupPage.evaluate(async chatId &#x3D;&gt; {
let chat &#x3D; await window.Store.Chat.get(chatId);
await window.Store.Cmd.markChatUnread(chat, true);
}, chatId);
}
/**
* Returns the contact ID&#x27;s profile picture URL, if privacy settings allow it
* @param {string} contactId the whatsapp user&#x27;s ID
@@ -743,6 +905,50 @@ class Client extends EventEmitter {
}, id);
}
/**
* Get the registered WhatsApp ID for a number.
* Will return null if the number is not registered on WhatsApp.
* @param {string} number Number or ID (&quot;@c.us&quot; will be automatically appended if not specified)
* @returns {Promise&amp;lt;Object|null&gt;}
*/
async getNumberId(number) {
if (!number.endsWith(&#x27;@c.us&#x27;)) number +&#x3D; &#x27;@c.us&#x27;;
try {
return await this.pupPage.evaluate(async numberId &#x3D;&gt; {
return window.WWebJS.getNumberId(numberId);
}, number);
} catch(_) {
return null;
}
}
/**
* Get the formatted number of a WhatsApp ID.
* @param {string} number Number or ID
* @returns {Promise&amp;lt;string&gt;}
*/
async getFormattedNumber(number) {
if(!number.endsWith(&#x27;@s.whatsapp.net&#x27;)) number &#x3D; number.replace(&#x27;c.us&#x27;, &#x27;s.whatsapp.net&#x27;);
if(!number.includes(&#x27;@s.whatsapp.net&#x27;)) number &#x3D; &#x60;${number}@s.whatsapp.net&#x60;;
return await this.pupPage.evaluate(async numberId &#x3D;&gt; {
return window.Store.NumberInfo.formattedPhoneNumber(numberId);
}, number);
}
/**
* Get the country code of a WhatsApp ID.
* @param {string} number Number or ID
* @returns {Promise&amp;lt;string&gt;}
*/
async getCountryCode(number) {
number &#x3D; number.replace(&#x27; &#x27;, &#x27;&#x27;).replace(&#x27;+&#x27;, &#x27;&#x27;).replace(&#x27;@c.us&#x27;, &#x27;&#x27;);
return await this.pupPage.evaluate(async numberId &#x3D;&gt; {
return window.Store.NumberInfo.findCC(numberId);
}, number);
}
/**
* Create a new group
* @param {string} name group title
@@ -780,6 +986,76 @@ class Client extends EventEmitter {
return { gid: createRes.gid, missingParticipants };
}
/**
* Get all current Labels
* @returns {Promise&amp;lt;Array&amp;lt;Label&gt;&gt;}
*/
async getLabels() {
const labels &#x3D; await this.pupPage.evaluate(async () &#x3D;&gt; {
return window.WWebJS.getLabels();
});
return labels.map(data &#x3D;&gt; new Label(this , data));
}
/**
* Get Label instance by ID
* @param {string} labelId
* @returns {Promise&amp;lt;Label&gt;}
*/
async getLabelById(labelId) {
const label &#x3D; await this.pupPage.evaluate(async (labelId) &#x3D;&gt; {
return window.WWebJS.getLabel(labelId);
}, labelId);
return new Label(this, label);
}
/**
* Get all Labels assigned to a chat
* @param {string} chatId
* @returns {Promise&amp;lt;Array&amp;lt;Label&gt;&gt;}
*/
async getChatLabels(chatId){
const labels &#x3D; await this.pupPage.evaluate(async (chatId) &#x3D;&gt; {
return window.WWebJS.getChatLabels(chatId);
}, chatId);
return labels.map(data &#x3D;&gt; new Label(this, data));
}
/**
* Get all Chats for a specific Label
* @param {string} labelId
* @returns {Promise&amp;lt;Array&amp;lt;Chat&gt;&gt;}
*/
async getChatsByLabelId(labelId){
const chatIds &#x3D; await this.pupPage.evaluate(async (labelId) &#x3D;&gt; {
const label &#x3D; window.Store.Label.get(labelId);
const labelItems &#x3D; label.labelItemCollection.models;
return labelItems.reduce((result, item) &#x3D;&gt; {
if(item.parentType &#x3D;&#x3D;&#x3D; &#x27;Chat&#x27;){
result.push(item.parentId);
}
return result;
},[]);
}, labelId);
return Promise.all(chatIds.map(id &#x3D;&gt; this.getChatById(id)));
}
/**
* Gets all blocked contacts by host account
* @returns {Promise&amp;lt;Array&amp;lt;Contact&gt;&gt;}
*/
async getBlockedContacts() {
const blockedContacts &#x3D; await this.pupPage.evaluate(() &#x3D;&gt; {
let chatIds &#x3D; window.Store.Blocklist.models.map(a &#x3D;&gt; a.id._serialized);
return Promise.all(chatIds.map(id &#x3D;&gt; window.WWebJS.getContact(id)));
});
return blockedContacts.map(contact &#x3D;&gt; ContactFactory.create(this.client, contact));
}
}
module.exports &#x3D; Client;
@@ -793,7 +1069,7 @@ module.exports &#x3D; Client;
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: ClientInfo</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: ClientInfo</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -238,7 +238,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: Contact</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: Contact</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -26,7 +26,7 @@
<header class="page-header">
<div class="symbol-detail-labels"><span class="label label-kind">class</span></div>
<h1><small></small><span class="symbol-name">Contact</span></h1>
<p class="source-link">Source: <a href="structures_Contact.js.html#source-line-9">structures/<wbr>Contact.<wbr>js:9</a></p>
<p class="source-link">Source: <a href="structures_Contact.js.html#source-line-17">structures/<wbr>Contact.<wbr>js:17</a></p>
<div class="symbol-classdesc">
<p>Represents a Contact on WhatsApp</p>
</div>
@@ -98,6 +98,9 @@
<dt><a href="Contact.html#block">block()</a></dt>
<dd>
</dd>
<dt><a href="Contact.html#getAbout">getAbout()</a></dt>
<dd>
</dd>
<dt><a href="Contact.html#getChat">getChat()</a></dt>
<dd>
</dd>
@@ -105,15 +108,23 @@
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Contact.html#getProfilePicUrl">getProfilePicUrl()</a></dt>
<dt><a href="Contact.html#getCountryCode">getCountryCode()</a></dt>
<dd>
</dd>
<dt><a href="Contact.html#unblock">unblock()</a></dt>
<dt><a href="Contact.html#getFormattedNumber">getFormattedNumber()</a></dt>
<dd>
</dd>
<dt><a href="Contact.html#getProfilePicUrl">getProfilePicUrl()</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Contact.html#unblock">unblock()</a></dt>
<dd>
</dd>
</dl>
</div>
</div>
</div>
@@ -129,7 +140,7 @@
<h2>Properties</h2>
<section>
<h3 id="id"><span class="symbol-name">id</span><small class="property-type">
&nbsp;object</small></h3>
&nbsp;<a href="global.html#ContactId">ContactId</a></small></h3>
<p>ID that represents the contact</p>
<dl class="dl-compact">
</dl>
@@ -206,6 +217,15 @@
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getAbout"><span class="symbol-name">getAbout</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing nullable string</span></span></h3>
<p>Gets the Contact's current &quot;about&quot; info. Returns null if you don't have permission to read their status.</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing nullable string</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getChat"><span class="symbol-name">getChat</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="Chat.html">Chat</a></span></span></h3>
<p>Returns the Chat that corresponds to this Contact.
Will return null when getting chat for currently logged in user.</p>
@@ -216,6 +236,24 @@
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getCountryCode"><span class="symbol-name">getCountryCode</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Returns the contact's countrycode, (1541859685@c.us) =&gt; (1)</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing string</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getFormattedNumber"><span class="symbol-name">getFormattedNumber</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Returns the contact's formatted phone number, (12345678901@c.us) =&gt; (+1 (234) 5678-901)</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing string</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getProfilePicUrl"><span class="symbol-name">getProfilePicUrl</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Returns the contact's profile picture URL, if privacy settings allow it</p>
<dl class="dl-compact">
@@ -243,7 +281,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: GroupChat</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: GroupChat</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -26,7 +26,7 @@
<header class="page-header">
<div class="symbol-detail-labels"><span class="label label-kind">class</span></div>
<h1><small></small><span class="symbol-name">GroupChat</span></h1>
<p class="source-link">Source: <a href="structures_GroupChat.js.html#source-line-9">structures/<wbr>GroupChat.<wbr>js:9</a></p>
<p class="source-link">Source: <a href="structures_GroupChat.js.html#source-line-17">structures/<wbr>GroupChat.<wbr>js:17</a></p>
<div class="symbol-classdesc">
<p>Represents a Group Chat on WhatsApp</p>
</div>
@@ -125,6 +125,9 @@
<dt><a href="GroupChat.html#getInviteCode">getInviteCode()</a></dt>
<dd>
</dd>
<dt><a href="GroupChat.html#getLabels">getLabels()</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
@@ -132,6 +135,9 @@
<dt><a href="GroupChat.html#leave">leave()</a></dt>
<dd>
</dd>
<dt><a href="GroupChat.html#markUnread">markUnread()</a></dt>
<dd>
</dd>
<dt><a href="GroupChat.html#mute">mute(unmuteDate)</a></dt>
<dd>
</dd>
@@ -258,12 +264,13 @@
<dt>Inherited from</dt>
<dd><a href="Chat.html#name">Chat#name</a></dd>
</dl>
<h3 id="owner"><span class="symbol-name">owner</span></h3>
<h3 id="owner"><span class="symbol-name">owner</span><small class="property-type">
&nbsp;<a href="global.html#ContactId">ContactId</a></small></h3>
<p>Gets the group owner</p>
<dl class="dl-compact">
</dl>
<h3 id="participants"><span class="symbol-name">participants</span><small class="property-type">
&nbsp;array</small></h3>
&nbsp;Array of <a href="global.html#GroupParticipant">GroupParticipant</a></small></h3>
<p>Gets the group participants</p>
<dl class="dl-compact">
</dl>
@@ -292,7 +299,7 @@
<h2>Methods</h2>
<section>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="addParticipants"><span class="symbol-name">addParticipants</span><span class="signature"><span class="signature-params">(participantIds)</span></span></h3>
<h3 id="addParticipants"><span class="symbol-name">addParticipants</span><span class="signature"><span class="signature-params">(participantIds)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Object</span></span></h3>
<p>Adds a list of participants by ID to the group</p>
<section>
<h4>Parameter</h4>
@@ -323,6 +330,10 @@
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing Object</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="archive"><span class="symbol-name">archive</span><span class="signature"><span class="signature-params">()</span></span></h3>
@@ -361,7 +372,7 @@
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="demoteParticipants"><span class="symbol-name">demoteParticipants</span><span class="signature"><span class="signature-params">(participantIds)</span></span></h3>
<h3 id="demoteParticipants"><span class="symbol-name">demoteParticipants</span><span class="signature"><span class="signature-params">(participantIds)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing {status: number}</span></span></h3>
<p>Demotes participants by IDs to regular users</p>
<section>
<h4>Parameter</h4>
@@ -392,6 +403,12 @@
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing {status: number}</code> 
<p>Object with status code indicating if the operation was successful</p>
</p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="fetchMessages"><span class="symbol-name">fetchMessages</span><span class="signature"><span class="signature-params">(searchOptions)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Array of <a href="Message.html">Message</a></span></span></h3>
@@ -442,8 +459,7 @@
<p>Yes</p>
</td>
<td>
<p>The amount of messages to return. Note that the actual number of returned messages may be smaller if there aren't enough messages in the conversation. Set this to Infinity to load all messages.</p>
<p>Defaults to <code>50</code>.</p>
<p>The amount of messages to return. If no limit is specified, the available messages will be returned. Note that the actual number of returned messages may be smaller if there aren't enough messages in the conversation. Set this to Infinity to load all messages.</p>
</td>
</tr>
</tbody>
@@ -469,18 +485,44 @@
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getInviteCode"><span class="symbol-name">getInviteCode</span><span class="signature"><span class="signature-params">()</span></span></h3>
<h3 id="getInviteCode"><span class="symbol-name">getInviteCode</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Gets the invite code for a specific group</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing string</code> 
<p>Group's invite code</p>
</p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="leave"><span class="symbol-name">leave</span><span class="signature"><span class="signature-params">()</span></span></h3>
<h3 id="getLabels"><span class="symbol-name">getLabels</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Array of <a href="Label.html">Label</a></span></span></h3>
<p>Returns array of all Labels assigned to this Chat</p>
<dl class="dl-compact">
<dt>Inherited from</dt>
<dd><a href="Chat.html#getLabels">Chat#getLabels</a></dd>
<dt>Returns</dt>
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="leave"><span class="symbol-name">leave</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise</span></span></h3>
<p>Makes the bot leave the group</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="markUnread"><span class="symbol-name">markUnread</span><span class="signature"><span class="signature-params">()</span></span></h3>
<p>Mark this chat as unread</p>
<dl class="dl-compact">
<dt>Inherited from</dt>
<dd><a href="Chat.html#markUnread">Chat#markUnread</a></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="mute"><span class="symbol-name">mute</span><span class="signature"><span class="signature-params">(unmuteDate)</span></span></h3>
<p>Mutes this chat until a specified date</p>
<p>Mutes this chat forever, unless a date is specified</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
@@ -504,7 +546,8 @@
<p>&nbsp;</p>
</td>
<td>
<p>Date at which the Chat will be unmuted</p>
<p>Date at which the Chat will be unmuted, leave as is to mute forever</p>
<p>Value can be null.</p>
</td>
</tr>
</tbody>
@@ -526,7 +569,7 @@
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="promoteParticipants"><span class="symbol-name">promoteParticipants</span><span class="signature"><span class="signature-params">(participantIds)</span></span></h3>
<h3 id="promoteParticipants"><span class="symbol-name">promoteParticipants</span><span class="signature"><span class="signature-params">(participantIds)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing {status: number}</span></span></h3>
<p>Promotes participants by IDs to admins</p>
<section>
<h4>Parameter</h4>
@@ -557,9 +600,15 @@
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing {status: number}</code> 
<p>Object with status code indicating if the operation was successful</p>
</p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="removeParticipants"><span class="symbol-name">removeParticipants</span><span class="signature"><span class="signature-params">(participantIds)</span></span></h3>
<h3 id="removeParticipants"><span class="symbol-name">removeParticipants</span><span class="signature"><span class="signature-params">(participantIds)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Object</span></span></h3>
<p>Removes a list of participants by ID to the group</p>
<section>
<h4>Parameter</h4>
@@ -590,11 +639,19 @@
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing Object</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="revokeInvite"><span class="symbol-name">revokeInvite</span><span class="signature"><span class="signature-params">()</span></span></h3>
<h3 id="revokeInvite"><span class="symbol-name">revokeInvite</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise</span></span></h3>
<p>Invalidates the current group invite code and generates a new one</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="sendMessage"><span class="symbol-name">sendMessage</span><span class="signature"><span class="signature-params">(content[, options])</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="Message.html">Message</a></span></span></h3>
@@ -674,7 +731,7 @@
<dd><a href="Chat.html#sendStateTyping">Chat#sendStateTyping</a></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="setDescription"><span class="symbol-name">setDescription</span><span class="signature"><span class="signature-params">(description)</span></span></h3>
<h3 id="setDescription"><span class="symbol-name">setDescription</span><span class="signature"><span class="signature-params">(description)</span>&nbsp;&rarr; <span class="signature-returns"> Promise</span></span></h3>
<p>Updates the group description</p>
<section>
<h4>Parameter</h4>
@@ -705,6 +762,10 @@
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="setInfoAdminsOnly"><span class="symbol-name">setInfoAdminsOnly</span><span class="signature"><span class="signature-params">([adminsOnly])</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing boolean</span></span></h3>
@@ -789,7 +850,7 @@
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="setSubject"><span class="symbol-name">setSubject</span><span class="signature"><span class="signature-params">(subject)</span></span></h3>
<h3 id="setSubject"><span class="symbol-name">setSubject</span><span class="signature"><span class="signature-params">(subject)</span>&nbsp;&rarr; <span class="signature-returns"> Promise</span></span></h3>
<p>Updates the group subject</p>
<section>
<h4>Parameter</h4>
@@ -820,6 +881,10 @@
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="unarchive"><span class="symbol-name">unarchive</span><span class="signature"><span class="signature-params">()</span></span></h3>
@@ -856,7 +921,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: GroupNotification</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: GroupNotification</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -233,7 +233,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: InterfaceController</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: InterfaceController</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -39,26 +39,46 @@
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="InterfaceController.html#checkFeatureStatus">checkFeatureStatus(feature)</a></dt>
<dd>
</dd>
<dt><a href="InterfaceController.html#closeRightDrawer">closeRightDrawer()</a></dt>
<dd>
</dd>
<dt><a href="InterfaceController.html#openChatDrawer">openChatDrawer(chatId)</a></dt>
<dt><a href="InterfaceController.html#disableFeatures">disableFeatures(features)</a></dt>
<dd>
</dd>
<dt><a href="InterfaceController.html#enableFeatures">enableFeatures(features)</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="InterfaceController.html#getFeatures">getFeatures()</a></dt>
<dd>
</dd>
<dt><a href="InterfaceController.html#openChatDrawer">openChatDrawer(chatId)</a></dt>
<dd>
</dd>
<dt><a href="InterfaceController.html#openChatSearch">openChatSearch(chatId)</a></dt>
<dd>
</dd>
<dt><a href="InterfaceController.html#openChatWindow">openChatWindow(chatId)</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="InterfaceController.html#openChatWindowAt">openChatWindowAt(msgId)</a></dt>
<dd>
</dd>
<dt><a href="InterfaceController.html#openMessageDrawer">openMessageDrawer(msgId)</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
</div>
</div>
</div>
</section>
@@ -70,12 +90,119 @@
<section>
<h2>Methods</h2>
<section>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="checkFeatureStatus"><span class="symbol-name">checkFeatureStatus</span><span class="signature"><span class="signature-params">(feature)</span></span></h3>
<p>Check if Feature is enabled</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>feature</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>status to check</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="closeRightDrawer"><span class="symbol-name">closeRightDrawer</span><span class="signature"><span class="signature-params">()</span></span></h3>
<p>Closes the Right Drawer</p>
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="disableFeatures"><span class="symbol-name">disableFeatures</span><span class="signature"><span class="signature-params">(features)</span></span></h3>
<p>Disable Features</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>features</p>
</td>
<td>
<p>Array of string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>to be disabled</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="enableFeatures"><span class="symbol-name">enableFeatures</span><span class="signature"><span class="signature-params">(features)</span></span></h3>
<p>Enable Features</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>features</p>
</td>
<td>
<p>Array of string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>to be enabled</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getFeatures"><span class="symbol-name">getFeatures</span><span class="signature"><span class="signature-params">()</span></span></h3>
<p>Get all Features</p>
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="openChatDrawer"><span class="symbol-name">openChatDrawer</span><span class="signature"><span class="signature-params">(chatId)</span></span></h3>
<p>Opens the Chat Drawer</p>
<section>
@@ -110,6 +237,40 @@
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="openChatSearch"><span class="symbol-name">openChatSearch</span><span class="signature"><span class="signature-params">(chatId)</span></span></h3>
<p>Opens the Chat Search</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>chatId</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>ID of the chat search that will be opened</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="openChatWindow"><span class="symbol-name">openChatWindow</span><span class="signature"><span class="signature-params">(chatId)</span></span></h3>
<p>Opens the Chat Window</p>
<section>
@@ -144,6 +305,40 @@
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="openChatWindowAt"><span class="symbol-name">openChatWindowAt</span><span class="signature"><span class="signature-params">(msgId)</span></span></h3>
<p>Opens or Scrolls the Chat Window to the position of the message</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>msgId</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>ID of the message that will be scrolled to</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="openMessageDrawer"><span class="symbol-name">openMessageDrawer</span><span class="signature"><span class="signature-params">(msgId)</span></span></h3>
<p>Opens the Message Drawer</p>
<section>
@@ -187,7 +382,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

178
docs/Label.html Normal file
View File

@@ -0,0 +1,178 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Class: Label</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-main" role="main">
<header class="page-header">
<div class="symbol-detail-labels"><span class="label label-kind">class</span></div>
<h1><small></small><span class="symbol-name">Label</span></h1>
<p class="source-link">Source: <a href="structures_Label.js.html#source-line-10">structures/<wbr>Label.<wbr>js:10</a></p>
<div class="symbol-classdesc">
<p>WhatsApp Business Label information</p>
</div>
<dl class="dl-compact">
</dl>
</header>
<section id="summary">
<div class="summary-callout">
<h2 class="summary-callout-heading">Properties</h2>
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Label.html#hexColor">hexColor</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Label.html#id">id</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Label.html#name">name</a></dt>
<dd>
</dd>
</dl>
</div>
</div>
</div>
<div class="summary-callout">
<h2 class="summary-callout-heading">Method</h2>
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Label.html#getChats">getChats()</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
</div>
<div class="summary-column">
</div>
</div>
</div>
</section>
<section>
<h2 id="Label">new&nbsp;<span class="symbol-name">Label</span><span class="signature"><span class="signature-params">(client, labelData)</span></span></h2>
<section>
<h3>Parameters</h3>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>client</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>labelData</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
</section>
<section>
<h2>Properties</h2>
<section>
<h3 id="hexColor"><span class="symbol-name">hexColor</span><small class="property-type">
&nbsp;string</small></h3>
<p>Label hex color</p>
<dl class="dl-compact">
</dl>
<h3 id="id"><span class="symbol-name">id</span><small class="property-type">
&nbsp;string</small></h3>
<p>Label ID</p>
<dl class="dl-compact">
</dl>
<h3 id="name"><span class="symbol-name">name</span><small class="property-type">
&nbsp;string</small></h3>
<p>Label name</p>
<dl class="dl-compact">
</dl>
</section>
<h2>Method</h2>
<section>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getChats"><span class="symbol-name">getChats</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Array of <a href="Chat.html">Chat</a></span></span></h3>
<p>Get all chats that have been assigned this Label</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing Array of <a href="Chat.html">Chat</a></code> </p>
</dd>
</dl>
</section>
</section>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

271
docs/List.html Normal file
View File

@@ -0,0 +1,271 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Class: List</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-main" role="main">
<header class="page-header">
<div class="symbol-detail-labels"><span class="label label-kind">class</span></div>
<h1><small></small><span class="symbol-name">List</span></h1>
<p class="source-link">Source: <a href="structures_List.js.html#source-line-8">structures/<wbr>List.<wbr>js:8</a></p>
<div class="symbol-classdesc">
<p>Message type List</p>
</div>
<dl class="dl-compact">
</dl>
</header>
<section id="summary">
<div class="summary-callout">
<h2 class="summary-callout-heading">Properties</h2>
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="List.html#buttonText">buttonText</a></dt>
<dd>
</dd>
<dt><a href="List.html#description">description</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="List.html#footer">footer</a></dt>
<dd>
</dd>
<dt><a href="List.html#sections">sections</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="List.html#title">title</a></dt>
<dd>
</dd>
</dl>
</div>
</div>
</div>
<div class="summary-callout">
<h2 class="summary-callout-heading">Method</h2>
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="List.html#_format">_format(sections)</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
</div>
<div class="summary-column">
</div>
</div>
</div>
</section>
<section>
<h2 id="List">new&nbsp;<span class="symbol-name">List</span><span class="signature"><span class="signature-params">(body, buttonText, sections, title, footer)</span></span></h2>
<section>
<h3>Parameters</h3>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>body</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>buttonText</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>sections</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>title</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Value can be null.</p>
</td>
</tr>
<tr>
<td>
<p>footer</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Value can be null.</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
</section>
<section>
<h2>Properties</h2>
<section>
<h3 id="buttonText"><span class="symbol-name">buttonText</span><small class="property-type">
&nbsp;string</small></h3>
<p>List button text</p>
<dl class="dl-compact">
</dl>
<h3 id="description"><span class="symbol-name">description</span><small class="property-type">
&nbsp;string</small></h3>
<p>Message body</p>
<dl class="dl-compact">
</dl>
<h3 id="footer"><span class="symbol-name">footer</span><small class="property-type">
&nbsp;string</small></h3>
<p>footer of message</p>
<dl class="dl-compact">
</dl>
<h3 id="sections"><span class="symbol-name">sections</span><small class="property-type">
&nbsp;Array of any</small></h3>
<p>sections of message</p>
<dl class="dl-compact">
</dl>
<h3 id="title"><span class="symbol-name">title</span><small class="property-type">
&nbsp;string</small></h3>
<p>title of message</p>
<dl class="dl-compact">
</dl>
</section>
<h2>Method</h2>
<section>
<h3 id="_format"><span class="symbol-name">_format</span><span class="signature"><span class="signature-params">(sections)</span>&nbsp;&rarr; <span class="signature-returns"> Array of any</span></span></h3>
<p>Creates section array from simple array</p>
<section>
<h4>
Example
</h4>
<div>
<pre class="prettyprint"><code>Input: [{title:&#x27;sectionTitle&#x27;,rows:[{id:&#x27;customId&#x27;, title:&#x27;ListItem2&#x27;, description: &#x27;desc&#x27;},{title:&#x27;ListItem2&#x27;}]}}]
Returns: [{&#x27;title&#x27;:&#x27;sectionTitle&#x27;,&#x27;rows&#x27;:[{&#x27;rowId&#x27;:&#x27;customId&#x27;,&#x27;title&#x27;:&#x27;ListItem1&#x27;,&#x27;description&#x27;:&#x27;desc&#x27;},{&#x27;rowId&#x27;:&#x27;oGSRoD&#x27;,&#x27;title&#x27;:&#x27;ListItem2&#x27;,&#x27;description&#x27;:&#x27;&#x27;}]}]</code></pre>
</div>
</section>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>sections</p>
</td>
<td>
<p>Array of any</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Array of any</code> </p>
</dd>
</dl>
</section>
</section>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: Location</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: Location</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -149,7 +149,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: Message</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: Message</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -26,7 +26,7 @@
<header class="page-header">
<div class="symbol-detail-labels"><span class="label label-kind">class</span></div>
<h1><small></small><span class="symbol-name">Message</span></h1>
<p class="source-link">Source: <a href="structures_Message.js.html#source-line-12">structures/<wbr>Message.<wbr>js:12</a></p>
<p class="source-link">Source: <a href="structures_Message.js.html#source-line-14">structures/<wbr>Message.<wbr>js:14</a></p>
<div class="symbol-classdesc">
<p>Represents a Message on WhatsApp</p>
</div>
@@ -51,50 +51,77 @@
<dt><a href="Message.html#broadcast">broadcast</a></dt>
<dd>
</dd>
<dt><a href="Message.html#deviceType">deviceType</a></dt>
<dd>
</dd>
<dt><a href="Message.html#forwardingScore">forwardingScore</a></dt>
<dd>
</dd>
<dt><a href="Message.html#from">from</a></dt>
<dd>
</dd>
<dt><a href="Message.html#fromMe">fromMe</a></dt>
<dd>
</dd>
<dt><a href="Message.html#hasMedia">hasMedia</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Message.html#hasMedia">hasMedia</a></dt>
<dd>
</dd>
<dt><a href="Message.html#hasQuotedMsg">hasQuotedMsg</a></dt>
<dd>
</dd>
<dt><a href="Message.html#id">id</a></dt>
<dd>
</dd>
<dt><a href="Message.html#inviteV4">inviteV4</a></dt>
<dd>
</dd>
<dt><a href="Message.html#isEphemeral">isEphemeral</a></dt>
<dd>
</dd>
<dt><a href="Message.html#isForwarded">isForwarded</a></dt>
<dd>
</dd>
<dt><a href="Message.html#isGif">isGif</a></dt>
<dd>
</dd>
<dt><a href="Message.html#isStarred">isStarred</a></dt>
<dd>
</dd>
<dt><a href="Message.html#isStatus">isStatus</a></dt>
<dd>
</dd>
<dt><a href="Message.html#location">location</a></dt>
<dt><a href="Message.html#links">links</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Message.html#location">location</a></dt>
<dd>
</dd>
<dt><a href="Message.html#mediaKey">mediaKey</a></dt>
<dd>
</dd>
<dt><a href="Message.html#mentionedIds">mentionedIds</a></dt>
<dd>
</dd>
<dt><a href="Message.html#orderId">orderId</a></dt>
<dd>
</dd>
<dt><a href="Message.html#timestamp">timestamp</a></dt>
<dd>
</dd>
<dt><a href="Message.html#to">to</a></dt>
<dd>
</dd>
<dt><a href="Message.html#token">token</a></dt>
<dd>
</dd>
<dt><a href="Message.html#type">type</a></dt>
<dd>
</dd>
@@ -110,6 +137,9 @@
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Message.html#acceptGroupV4Invite">acceptGroupV4Invite()</a></dt>
<dd>
</dd>
<dt><a href="Message.html#delete">delete(everyone)</a></dt>
<dd>
</dd>
@@ -119,19 +149,28 @@
<dt><a href="Message.html#forward">forward(chat)</a></dt>
<dd>
</dd>
<dt><a href="Message.html#getChat">getChat()</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Message.html#getChat">getChat()</a></dt>
<dd>
</dd>
<dt><a href="Message.html#getContact">getContact()</a></dt>
<dd>
</dd>
<dt><a href="Message.html#getInfo">getInfo()</a></dt>
<dd>
</dd>
<dt><a href="Message.html#getMentions">getMentions()</a></dt>
<dd>
</dd>
<dt><a href="Message.html#getOrder">getOrder()</a></dt>
<dd>
</dd>
<dt><a href="Message.html#getPayment">getPayment()</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
@@ -142,6 +181,12 @@
<dt><a href="Message.html#reply">reply(content[, chatId][, options])</a></dt>
<dd>
</dd>
<dt><a href="Message.html#star">star()</a></dt>
<dd>
</dd>
<dt><a href="Message.html#unstar">unstar()</a></dt>
<dd>
</dd>
</dl>
</div>
</div>
@@ -177,6 +222,17 @@
<p>Indicates if the message was a broadcast</p>
<dl class="dl-compact">
</dl>
<h3 id="deviceType"><span class="symbol-name">deviceType</span><small class="property-type">
&nbsp;string</small></h3>
<p>String that represents from which device type the message was sent</p>
<dl class="dl-compact">
</dl>
<h3 id="forwardingScore"><span class="symbol-name">forwardingScore</span><small class="property-type">
&nbsp;number</small></h3>
<p>Indicates how many times the message was forwarded.</p>
<p>The maximum value is 127.</p>
<dl class="dl-compact">
</dl>
<h3 id="from"><span class="symbol-name">from</span><small class="property-type">
&nbsp;string</small></h3>
<p>ID for the Chat that this message was sent to, except if the message was sent by the current user.</p>
@@ -202,16 +258,41 @@
<p>ID that represents the message</p>
<dl class="dl-compact">
</dl>
<h3 id="inviteV4"><span class="symbol-name">inviteV4</span><small class="property-type">
&nbsp;object</small></h3>
<p>Group Invite Data</p>
<dl class="dl-compact">
</dl>
<h3 id="isEphemeral"><span class="symbol-name">isEphemeral</span><small class="property-type">
&nbsp;boolean</small></h3>
<p>Indicates if the message will disappear after it expires</p>
<dl class="dl-compact">
</dl>
<h3 id="isForwarded"><span class="symbol-name">isForwarded</span><small class="property-type">
&nbsp;boolean</small></h3>
<p>Indicates if the message was forwarded</p>
<dl class="dl-compact">
</dl>
<h3 id="isGif"><span class="symbol-name">isGif</span><small class="property-type">
&nbsp;boolean</small></h3>
<p>Indicates whether the message is a Gif</p>
<dl class="dl-compact">
</dl>
<h3 id="isStarred"><span class="symbol-name">isStarred</span><small class="property-type">
&nbsp;boolean</small></h3>
<p>Indicates if the message was starred</p>
<dl class="dl-compact">
</dl>
<h3 id="isStatus"><span class="symbol-name">isStatus</span><small class="property-type">
&nbsp;boolean</small></h3>
<p>Indicates if the message is a status update</p>
<dl class="dl-compact">
</dl>
<h3 id="links"><span class="symbol-name">links</span><small class="property-type">
&nbsp;Array of {link: string, isSuspicious: boolean}</small></h3>
<p>Links included in the message.</p>
<dl class="dl-compact">
</dl>
<h3 id="location"><span class="symbol-name">location</span><small class="property-type">
&nbsp;<a href="Location.html">Location</a></small></h3>
<p>Location information contained in the message, if the message is type &quot;location&quot;</p>
@@ -227,6 +308,11 @@
<p>Indicates the mentions in the message body.</p>
<dl class="dl-compact">
</dl>
<h3 id="orderId"><span class="symbol-name">orderId</span><small class="property-type">
&nbsp;string</small></h3>
<p>Order ID for message type ORDER</p>
<dl class="dl-compact">
</dl>
<h3 id="timestamp"><span class="symbol-name">timestamp</span><small class="property-type">
&nbsp;number</small></h3>
<p>Unix timestamp for when the message was created</p>
@@ -239,6 +325,11 @@
If the message is sent by another user, it will be the ID for the current user.</p>
<dl class="dl-compact">
</dl>
<h3 id="token"><span class="symbol-name">token</span><small class="property-type">
&nbsp;string</small></h3>
<p>Order Token for message type ORDER</p>
<dl class="dl-compact">
</dl>
<h3 id="type"><span class="symbol-name">type</span><small class="property-type">
&nbsp;<a href="global.html#MessageTypes">MessageTypes</a></small></h3>
<p>Message type</p>
@@ -252,6 +343,15 @@
</section>
<h2>Methods</h2>
<section>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="acceptGroupV4Invite"><span class="symbol-name">acceptGroupV4Invite</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Object</span></span></h3>
<p>Accept Group V4 Invite</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing Object</code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="delete"><span class="symbol-name">delete</span><span class="signature"><span class="signature-params">(everyone)</span></span></h3>
<p>Deletes a message from the chat</p>
@@ -351,6 +451,15 @@
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getInfo"><span class="symbol-name">getInfo</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing nullable <a href="global.html#MessageInfo">MessageInfo</a></span></span></h3>
<p>Get information about message delivery status. May return null if the message does not exist or is not sent by you.</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing nullable <a href="global.html#MessageInfo">MessageInfo</a></code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getMentions"><span class="symbol-name">getMentions</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Array of <a href="Contact.html">Contact</a></span></span></h3>
<p>Returns the Contacts mentioned in this message</p>
<dl class="dl-compact">
@@ -360,6 +469,24 @@
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getOrder"><span class="symbol-name">getOrder</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="Order.html">Order</a></span></span></h3>
<p>Gets the order associated with a given message</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing <a href="Order.html">Order</a></code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getPayment"><span class="symbol-name">getPayment</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="Payment.html">Payment</a></span></span></h3>
<p>Gets the payment details associated with a given message</p>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing <a href="Payment.html">Payment</a></code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getQuotedMessage"><span class="symbol-name">getQuotedMessage</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="Message.html">Message</a></span></span></h3>
<p>Returns the quoted message, if any</p>
<dl class="dl-compact">
@@ -433,6 +560,16 @@
<p><code>Promise containing <a href="Message.html">Message</a></code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="star"><span class="symbol-name">star</span><span class="signature"><span class="signature-params">()</span></span></h3>
<p>Stars this message</p>
<dl class="dl-compact">
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="unstar"><span class="symbol-name">unstar</span><span class="signature"><span class="signature-params">()</span></span></h3>
<p>Unstars this message</p>
<dl class="dl-compact">
</dl>
</section>
</section>
</div>
@@ -443,7 +580,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: MessageMedia</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: MessageMedia</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -26,7 +26,7 @@
<header class="page-header">
<div class="symbol-detail-labels"><span class="label label-kind">class</span></div>
<h1><small></small><span class="symbol-name">MessageMedia</span></h1>
<p class="source-link">Source: <a href="structures_MessageMedia.js.html#source-line-13">structures/<wbr>MessageMedia.<wbr>js:13</a></p>
<p class="source-link">Source: <a href="structures_MessageMedia.js.html#source-line-15">structures/<wbr>MessageMedia.<wbr>js:15</a></p>
<div class="symbol-classdesc">
<p>Media attached to a message</p>
</div>
@@ -61,7 +61,7 @@
</div>
</div>
<div class="summary-callout">
<h2 class="summary-callout-heading">Method</h2>
<h2 class="summary-callout-heading">Methods</h2>
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
@@ -71,6 +71,11 @@
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="MessageMedia.html#.fromUrl">fromUrl(url[, options])</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
</div>
@@ -159,7 +164,7 @@
<dl class="dl-compact">
</dl>
</section>
<h2>Method</h2>
<h2>Methods</h2>
<section>
<div class="symbol-detail-labels"><span class="label label-static">static</span></div>
<h3 id=".fromFilePath"><span class="symbol-name">fromFilePath</span><span class="signature"><span class="signature-params">(filePath)</span>&nbsp;&rarr; <span class="signature-returns"> <a href="MessageMedia.html">MessageMedia</a></span></span></h3>
@@ -198,6 +203,136 @@
<p><code><a href="MessageMedia.html">MessageMedia</a></code> </p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span>&nbsp;<span class="label label-static">static</span></div>
<h3 id=".fromUrl"><span class="symbol-name">fromUrl</span><span class="signature"><span class="signature-params">(url[, options])</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="MessageMedia.html">MessageMedia</a></span></span></h3>
<p>Creates a MessageMedia instance from a URL</p>
<section>
<h4>Parameters</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>url</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>options</p>
</td>
<td>
<p>Object</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>Values in <code>options</code> have the following properties:</p>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>unsafeMime</p>
</td>
<td>
<p>boolean</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>Defaults to <code>false</code>.</p>
</td>
</tr>
<tr>
<td>
<p>filename</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>client</p>
</td>
<td>
<p>object</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>reqOptions</p>
</td>
<td>
<p>object</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>reqOptions.size</p>
</td>
<td>
<p>number</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>Defaults to <code>0</code>.</p>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing <a href="MessageMedia.html">MessageMedia</a></code> </p>
</dd>
</dl>
</section>
</section>
</div>
@@ -208,7 +343,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

117
docs/Order.html Normal file
View File

@@ -0,0 +1,117 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Class: Order</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-main" role="main">
<header class="page-header">
<div class="symbol-detail-labels"><span class="label label-kind">class</span></div>
<h1><small></small><span class="symbol-name">Order</span></h1>
<p class="source-link">Source: <a href="structures_Order.js.html#source-line-10">structures/<wbr>Order.<wbr>js:10</a></p>
<div class="symbol-classdesc">
<p>Represents a Order on WhatsApp</p>
</div>
<dl class="dl-compact">
</dl>
</header>
<section id="summary">
<div class="summary-callout">
<h2 class="summary-callout-heading">Properties</h2>
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Order.html#createdAt">createdAt</a></dt>
<dd>
</dd>
<dt><a href="Order.html#currency">currency</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Order.html#subtotal">subtotal</a></dt>
<dd>
</dd>
<dt><a href="Order.html#total">total</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
</div>
</div>
</div>
</section>
<section>
<h2 id="Order">new&nbsp;<span class="symbol-name">Order</span><span class="signature"><span class="signature-params">()</span></span></h2>
<dl class="dl-compact">
<dt>Extends</dt>
<dd><a href="Base.html">Base</a></dd>
</dl>
</section>
<section>
<h2>Properties</h2>
<section>
<h3 id="createdAt"><span class="symbol-name">createdAt</span><small class="property-type">
&nbsp;number</small></h3>
<p>Order Created At</p>
<dl class="dl-compact">
</dl>
<h3 id="currency"><span class="symbol-name">currency</span><small class="property-type">
&nbsp;string</small></h3>
<p>Order Currency</p>
<dl class="dl-compact">
</dl>
<h3 id="subtotal"><span class="symbol-name">subtotal</span><small class="property-type">
&nbsp;string</small></h3>
<p>Order Subtotal</p>
<dl class="dl-compact">
</dl>
<h3 id="total"><span class="symbol-name">total</span><small class="property-type">
&nbsp;string</small></h3>
<p>Order Total</p>
<dl class="dl-compact">
</dl>
</section>
</section>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: PrivateChat</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: PrivateChat</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -101,11 +101,17 @@
<dt><a href="PrivateChat.html#fetchMessages">fetchMessages(searchOptions)</a></dt>
<dd>
</dd>
<dt><a href="PrivateChat.html#getContact">getContact()</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="PrivateChat.html#getContact">getContact()</a></dt>
<dt><a href="PrivateChat.html#getLabels">getLabels()</a></dt>
<dd>
</dd>
<dt><a href="PrivateChat.html#markUnread">markUnread()</a></dt>
<dd>
</dd>
<dt><a href="PrivateChat.html#mute">mute(unmuteDate)</a></dt>
@@ -312,8 +318,7 @@
<p>Yes</p>
</td>
<td>
<p>The amount of messages to return. Note that the actual number of returned messages may be smaller if there aren't enough messages in the conversation. Set this to Infinity to load all messages.</p>
<p>Defaults to <code>50</code>.</p>
<p>The amount of messages to return. If no limit is specified, the available messages will be returned. Note that the actual number of returned messages may be smaller if there aren't enough messages in the conversation. Set this to Infinity to load all messages.</p>
</td>
</tr>
</tbody>
@@ -339,8 +344,24 @@
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getLabels"><span class="symbol-name">getLabels</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing Array of <a href="Label.html">Label</a></span></span></h3>
<p>Returns array of all Labels assigned to this Chat</p>
<dl class="dl-compact">
<dt>Inherited from</dt>
<dd><a href="Chat.html#getLabels">Chat#getLabels</a></dd>
<dt>Returns</dt>
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="markUnread"><span class="symbol-name">markUnread</span><span class="signature"><span class="signature-params">()</span></span></h3>
<p>Mark this chat as unread</p>
<dl class="dl-compact">
<dt>Inherited from</dt>
<dd><a href="Chat.html#markUnread">Chat#markUnread</a></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="mute"><span class="symbol-name">mute</span><span class="signature"><span class="signature-params">(unmuteDate)</span></span></h3>
<p>Mutes this chat until a specified date</p>
<p>Mutes this chat forever, unless a date is specified</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
@@ -364,7 +385,8 @@
<p>&nbsp;</p>
</td>
<td>
<p>Date at which the Chat will be unmuted</p>
<p>Date at which the Chat will be unmuted, leave as is to mute forever</p>
<p>Value can be null.</p>
</td>
</tr>
</tbody>
@@ -497,7 +519,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: PrivateContact</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: PrivateContact</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -98,6 +98,9 @@
<dt><a href="PrivateContact.html#block">block()</a></dt>
<dd>
</dd>
<dt><a href="PrivateContact.html#getAbout">getAbout()</a></dt>
<dd>
</dd>
<dt><a href="PrivateContact.html#getChat">getChat()</a></dt>
<dd>
</dd>
@@ -105,15 +108,23 @@
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="PrivateContact.html#getProfilePicUrl">getProfilePicUrl()</a></dt>
<dt><a href="PrivateContact.html#getCountryCode">getCountryCode()</a></dt>
<dd>
</dd>
<dt><a href="PrivateContact.html#unblock">unblock()</a></dt>
<dt><a href="PrivateContact.html#getFormattedNumber">getFormattedNumber()</a></dt>
<dd>
</dd>
<dt><a href="PrivateContact.html#getProfilePicUrl">getProfilePicUrl()</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="PrivateContact.html#unblock">unblock()</a></dt>
<dd>
</dd>
</dl>
</div>
</div>
</div>
@@ -232,6 +243,15 @@
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getAbout"><span class="symbol-name">getAbout</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing nullable string</span></span></h3>
<p>Gets the Contact's current &quot;about&quot; info. Returns null if you don't have permission to read their status.</p>
<dl class="dl-compact">
<dt>Inherited from</dt>
<dd><a href="Contact.html#getAbout">Contact#getAbout</a></dd>
<dt>Returns</dt>
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getChat"><span class="symbol-name">getChat</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="Chat.html">Chat</a></span></span></h3>
<p>Returns the Chat that corresponds to this Contact.
Will return null when getting chat for currently logged in user.</p>
@@ -242,6 +262,24 @@
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getCountryCode"><span class="symbol-name">getCountryCode</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Returns the contact's countrycode, (1541859685@c.us) =&gt; (1)</p>
<dl class="dl-compact">
<dt>Inherited from</dt>
<dd><a href="Contact.html#getCountryCode">Contact#getCountryCode</a></dd>
<dt>Returns</dt>
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getFormattedNumber"><span class="symbol-name">getFormattedNumber</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Returns the contact's formatted phone number, (12345678901@c.us) =&gt; (+1 (234) 5678-901)</p>
<dl class="dl-compact">
<dt>Inherited from</dt>
<dd><a href="Contact.html#getFormattedNumber">Contact#getFormattedNumber</a></dd>
<dt>Returns</dt>
<dd></dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span></div>
<h3 id="getProfilePicUrl"><span class="symbol-name">getProfilePicUrl</span><span class="signature"><span class="signature-params">()</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing string</span></span></h3>
<p>Returns the contact's profile picture URL, if privacy settings allow it</p>
<dl class="dl-compact">
@@ -269,7 +307,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

142
docs/Product.html Normal file
View File

@@ -0,0 +1,142 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Class: Product</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-main" role="main">
<header class="page-header">
<div class="symbol-detail-labels"><span class="label label-kind">class</span></div>
<h1><small></small><span class="symbol-name">Product</span></h1>
<p class="source-link">Source: <a href="structures_Product.js.html#source-line-10">structures/<wbr>Product.<wbr>js:10</a></p>
<div class="symbol-classdesc">
<p>Represents a Product on WhatsAppBusiness</p>
</div>
<dl class="dl-compact">
</dl>
</header>
<section id="summary">
<div class="summary-callout">
<h2 class="summary-callout-heading">Properties</h2>
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Product.html#currency">currency</a></dt>
<dd>
</dd>
<dt><a href="Product.html#data">data</a></dt>
<dd>
</dd>
<dt><a href="Product.html#id">id</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Product.html#name">name</a></dt>
<dd>
</dd>
<dt><a href="Product.html#price">price</a></dt>
<dd>
</dd>
<dt><a href="Product.html#quantity">quantity</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Product.html#thumbnailUrl">thumbnailUrl</a></dt>
<dd>
</dd>
</dl>
</div>
</div>
</div>
</section>
<section>
<h2 id="Product">new&nbsp;<span class="symbol-name">Product</span><span class="signature"><span class="signature-params">()</span></span></h2>
<dl class="dl-compact">
<dt>Extends</dt>
<dd><a href="Base.html">Base</a></dd>
</dl>
</section>
<section>
<h2>Properties</h2>
<section>
<h3 id="currency"><span class="symbol-name">currency</span><small class="property-type">
&nbsp;string</small></h3>
<p>Currency</p>
<dl class="dl-compact">
</dl>
<h3 id="data"><span class="symbol-name">data</span></h3>
<p>Product metadata</p>
<dl class="dl-compact">
</dl>
<h3 id="id"><span class="symbol-name">id</span><small class="property-type">
&nbsp;string</small></h3>
<p>Product ID</p>
<dl class="dl-compact">
</dl>
<h3 id="name"><span class="symbol-name">name</span><small class="property-type">
&nbsp;string</small></h3>
<p>Product Name</p>
<dl class="dl-compact">
</dl>
<h3 id="price"><span class="symbol-name">price</span><small class="property-type">
&nbsp;string</small></h3>
<p>Price</p>
<dl class="dl-compact">
</dl>
<h3 id="quantity"><span class="symbol-name">quantity</span><small class="property-type">
&nbsp;number</small></h3>
<p>Product Quantity</p>
<dl class="dl-compact">
</dl>
<h3 id="thumbnailUrl"><span class="symbol-name">thumbnailUrl</span><small class="property-type">
&nbsp;string</small></h3>
<p>Product Thumbnail</p>
<dl class="dl-compact">
</dl>
</section>
</section>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Class: Util</title>
<title>whatsapp-web.js 1.15.7 &raquo; Class: Util</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -26,7 +26,7 @@
<header class="page-header">
<div class="symbol-detail-labels"><span class="label label-kind">class</span></div>
<h1><small></small><span class="symbol-name">Util</span></h1>
<p class="source-link">Source: <a href="util_Util.js.html#source-line-8">util/<wbr>Util.<wbr>js:8</a></p>
<p class="source-link">Source: <a href="util_Util.js.html#source-line-16">util/<wbr>Util.<wbr>js:16</a></p>
<div class="symbol-classdesc">
<p>Utility methods</p>
</div>
@@ -34,6 +34,33 @@
</dl>
</header>
<section id="summary">
<div class="summary-callout">
<h2 class="summary-callout-heading">Methods</h2>
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Util.html#.formatImageToWebpSticker">formatImageToWebpSticker(media)</a></dt>
<dd>
</dd>
<dt><a href="Util.html#.formatToWebpSticker">formatToWebpSticker(media, metadata)</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="Util.html#.formatVideoToWebpSticker">formatVideoToWebpSticker(media)</a></dt>
<dd>
</dd>
<dt><a href="Util.html#.setFfmpegPath">setFfmpegPath(path)</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
</div>
</div>
</div>
</section>
<section>
<h2 id="Util">new&nbsp;<span class="symbol-name">Util</span><span class="signature"><span class="signature-params">()</span></span></h2>
@@ -41,6 +68,172 @@
</dl>
</section>
<section>
<h2>Methods</h2>
<section>
<div class="symbol-detail-labels"><span class="label label-async">async</span>&nbsp;<span class="label label-static">static</span></div>
<h3 id=".formatImageToWebpSticker"><span class="symbol-name">formatImageToWebpSticker</span><span class="signature"><span class="signature-params">(media)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="MessageMedia.html">MessageMedia</a></span></span></h3>
<p>Formats a image to webp</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>media</p>
</td>
<td>
<p><a href="MessageMedia.html">MessageMedia</a></p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing <a href="MessageMedia.html">MessageMedia</a></code> 
<p>media in webp format</p>
</p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span>&nbsp;<span class="label label-static">static</span></div>
<h3 id=".formatToWebpSticker"><span class="symbol-name">formatToWebpSticker</span><span class="signature"><span class="signature-params">(media, metadata)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="MessageMedia.html">MessageMedia</a></span></span></h3>
<p>Formats a media to webp</p>
<section>
<h4>Parameters</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>media</p>
</td>
<td>
<p><a href="MessageMedia.html">MessageMedia</a></p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>metadata</p>
</td>
<td>
<p><a href="global.html#StickerMetadata">StickerMetadata</a></p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing <a href="MessageMedia.html">MessageMedia</a></code> 
<p>media in webp format</p>
</p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-async">async</span>&nbsp;<span class="label label-static">static</span></div>
<h3 id=".formatVideoToWebpSticker"><span class="symbol-name">formatVideoToWebpSticker</span><span class="signature"><span class="signature-params">(media)</span>&nbsp;&rarr; <span class="signature-returns"> Promise containing <a href="MessageMedia.html">MessageMedia</a></span></span></h3>
<p>Formats a video to webp</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>media</p>
</td>
<td>
<p><a href="MessageMedia.html">MessageMedia</a></p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
<dt>Returns</dt>
<dd>
<p><code>Promise containing <a href="MessageMedia.html">MessageMedia</a></code> 
<p>media in webp format</p>
</p>
</dd>
</dl>
<div class="symbol-detail-labels"><span class="label label-static">static</span></div>
<h3 id=".setFfmpegPath"><span class="symbol-name">setFfmpegPath</span><span class="signature"><span class="signature-params">(path)</span></span></h3>
<p>Configure ffmpeg path</p>
<section>
<h4>Parameter</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>path</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
</section>
</section>
</div>
</div>
@@ -50,7 +243,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Globals</title>
<title>whatsapp-web.js 1.15.7 &raquo; Globals</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -64,18 +64,40 @@
</div>
</div>
<div class="summary-callout">
<h2 class="summary-callout-heading">Abstract type</h2>
<h2 class="summary-callout-heading">Abstract types</h2>
<div class="summary-content">
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="global.html#ButtonSpec">ButtonSpec</a></dt>
<dd>
</dd>
<dt><a href="global.html#ContactId">ContactId</a></dt>
<dd>
</dd>
<dt><a href="global.html#FormattedButtonSpec">FormattedButtonSpec</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="global.html#GroupParticipant">GroupParticipant</a></dt>
<dd>
</dd>
<dt><a href="global.html#MessageInfo">MessageInfo</a></dt>
<dd>
</dd>
<dt><a href="global.html#MessageSendOptions">MessageSendOptions</a></dt>
<dd>
</dd>
</dl>
</div>
<div class="summary-column">
</div>
<div class="summary-column">
<dl class="dl-summary-callout">
<dt><a href="global.html#StickerMetadata">StickerMetadata</a></dt>
<dd>
</dd>
</dl>
</div>
</div>
</div>
@@ -367,6 +389,19 @@
<td>
</td>
</tr>
<tr>
<td>
<p>INCOMING_CALL</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
@@ -755,6 +790,19 @@
<td>
</td>
</tr>
<tr>
<td>
<p>ORDER</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>REVOKED</p>
@@ -768,6 +816,19 @@
<td>
</td>
</tr>
<tr>
<td>
<p>PRODUCT</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>UNKNOWN</p>
@@ -781,6 +842,279 @@
<td>
</td>
</tr>
<tr>
<td>
<p>GROUP_INVITE</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>LIST</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>LIST_RESPONSE</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>BUTTONS_RESPONSE</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>PAYMENT</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>BROADCAST_NOTIFICATION</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>CALL_LOG</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>CIPHERTEXT</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>DEBUG</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>E2E_NOTIFICATION</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>GP2</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>GROUP_NOTIFICATION</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>HSM</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>INTERACTIVE</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>NATIVE_FLOW</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>NOTIFICATION</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>NOTIFICATION_TEMPLATE</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>OVERSIZED</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>PROTOCOL</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>REACTION</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>TEMPLATE_BUTTON_REPLY</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
@@ -1024,8 +1358,336 @@
<dl class="dl-compact">
</dl>
</section>
<h2>Abstract type</h2>
<h2>Abstract types</h2>
<section>
<h3 id="ButtonSpec"><span class="symbol-name">ButtonSpec</span><small class="property-type">
&nbsp;Object</small></h3>
<p>Button spec used in Buttons constructor</p>
<section>
<h4>Properties</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>id</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>Custom ID to set on the button. A random one will be generated if one is not passed.</p>
</td>
</tr>
<tr>
<td>
<p>body</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>The text to show on the button.</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
<h3 id="ContactId"><span class="symbol-name">ContactId</span><small class="property-type">
&nbsp;Object</small></h3>
<p>ID that represents a contact</p>
<section>
<h4>Properties</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>server</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>user</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>_serialized</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
<h3 id="FormattedButtonSpec"><span class="symbol-name">FormattedButtonSpec</span><small class="property-type">
&nbsp;Object</small></h3>
<section>
<h4>Properties</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>buttonId</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>type</p>
</td>
<td>
<p>number</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>buttonText</p>
</td>
<td>
<p>Object</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
<h3 id="GroupParticipant"><span class="symbol-name">GroupParticipant</span><small class="property-type">
&nbsp;Object</small></h3>
<p>Group participant information</p>
<section>
<h4>Properties</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>id</p>
</td>
<td>
<p><a href="global.html#ContactId">ContactId</a></p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>isAdmin</p>
</td>
<td>
<p>boolean</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>isSuperAdmin</p>
</td>
<td>
<p>boolean</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
<h3 id="MessageInfo"><span class="symbol-name">MessageInfo</span><small class="property-type">
&nbsp;Object</small></h3>
<p>Message Info</p>
<section>
<h4>Properties</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>delivery</p>
</td>
<td>
<p>Array of {id: <a href="global.html#ContactId">ContactId</a>, t: number}</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Contacts to which the message has been delivered to</p>
</td>
</tr>
<tr>
<td>
<p>deliveryRemaining</p>
</td>
<td>
<p>number</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Amount of people to whom the message has not been delivered to</p>
</td>
</tr>
<tr>
<td>
<p>played</p>
</td>
<td>
<p>Array of {id: <a href="global.html#ContactId">ContactId</a>, t: number}</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Contacts who have listened to the voice message</p>
</td>
</tr>
<tr>
<td>
<p>playedRemaining</p>
</td>
<td>
<p>number</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Amount of people who have not listened to the message</p>
</td>
</tr>
<tr>
<td>
<p>read</p>
</td>
<td>
<p>Array of {id: <a href="global.html#ContactId">ContactId</a>, t: number}</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Contacts who have read the message</p>
</td>
</tr>
<tr>
<td>
<p>readRemaining</p>
</td>
<td>
<p>number</p>
</td>
<td>
<p>&nbsp;</p>
</td>
<td>
<p>Amount of people who have not read the message</p>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
<h3 id="MessageSendOptions"><span class="symbol-name">MessageSendOptions</span><small class="property-type">
&nbsp;Object</small></h3>
<p>Message options.</p>
@@ -1071,6 +1733,51 @@
<p>Defaults to <code>false</code>.</p>
</td>
</tr>
<tr>
<td>
<p>sendVideoAsGif</p>
</td>
<td>
<p>boolean</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>Send video as gif</p>
<p>Defaults to <code>false</code>.</p>
</td>
</tr>
<tr>
<td>
<p>sendMediaAsSticker</p>
</td>
<td>
<p>boolean</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>Send media as a sticker</p>
<p>Defaults to <code>false</code>.</p>
</td>
</tr>
<tr>
<td>
<p>sendMediaAsDocument</p>
</td>
<td>
<p>boolean</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>Send media as a document</p>
<p>Defaults to <code>false</code>.</p>
</td>
</tr>
<tr>
<td>
<p>parseVCards</p>
@@ -1143,12 +1850,54 @@
<p>Defaults to <code>true</code>.</p>
</td>
</tr>
<tr>
<td>
<p>stickerAuthor</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>Sets the author of the sticker, (if sendMediaAsSticker is true).</p>
</td>
</tr>
<tr>
<td>
<p>stickerName</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>Sets the name of the sticker, (if sendMediaAsSticker is true).</p>
</td>
</tr>
<tr>
<td>
<p>stickerCategories</p>
</td>
<td>
<p>Array of string</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
<p>Sets the categories of the sticker, (if sendMediaAsSticker is true). Provide emoji char array, can be null.</p>
</td>
</tr>
<tr>
<td>
<p>media</p>
</td>
<td>
<p>boolean</p>
<p><a href="MessageMedia.html">MessageMedia</a></p>
</td>
<td>
<p>Yes</p>
@@ -1162,6 +1911,65 @@
</section>
<dl class="dl-compact">
</dl>
<h3 id="StickerMetadata"><span class="symbol-name">StickerMetadata</span><small class="property-type">
&nbsp;Object</small></h3>
<p>Sticker metadata.</p>
<section>
<h4>Properties</h4>
<table class="jsdoc-details-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Optional</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>name</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>author</p>
</td>
<td>
<p>string</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
</td>
</tr>
<tr>
<td>
<p>categories</p>
</td>
<td>
<p>Array of string</p>
</td>
<td>
<p>Yes</p>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</section>
<dl class="dl-compact">
</dl>
</section>
</section>
</div>
@@ -1172,7 +1980,7 @@
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
treeNode.tree({
autoEscape: false,
closedIcon: '&#x21e2;',
data: [{"label":"<a href=\"global.html\">Globals</a>","id":"global","children":[]},{"label":"<a href=\"Base.html\">Base</a>","id":"Base","children":[]},{"label":"<a href=\"BusinessContact.html\">BusinessContact</a>","id":"BusinessContact","children":[]},{"label":"<a href=\"Chat.html\">Chat</a>","id":"Chat","children":[]},{"label":"<a href=\"Client.html\">Client</a>","id":"Client","children":[]},{"label":"<a href=\"ClientInfo.html\">ClientInfo</a>","id":"ClientInfo","children":[]},{"label":"<a href=\"Contact.html\">Contact</a>","id":"Contact","children":[]},{"label":"<a href=\"GroupChat.html\">GroupChat</a>","id":"GroupChat","children":[]},{"label":"<a href=\"GroupNotification.html\">GroupNotification</a>","id":"GroupNotification","children":[]},{"label":"<a href=\"InterfaceController.html\">InterfaceController</a>","id":"InterfaceController","children":[]},{"label":"<a href=\"Location.html\">Location</a>","id":"Location","children":[]},{"label":"<a href=\"Message.html\">Message</a>","id":"Message","children":[]},{"label":"<a href=\"MessageMedia.html\">MessageMedia</a>","id":"MessageMedia","children":[]},{"label":"<a href=\"PrivateChat.html\">PrivateChat</a>","id":"PrivateChat","children":[]},{"label":"<a href=\"PrivateContact.html\">PrivateContact</a>","id":"PrivateContact","children":[]},{"label":"<a href=\"Util.html\">Util</a>","id":"Util","children":[]}],
data: [{"label":"<a href=\"global.html\">Globals</a>","id":"global","children":[]},{"label":"<a href=\"Base.html\">Base</a>","id":"Base","children":[]},{"label":"<a href=\"BusinessContact.html\">BusinessContact</a>","id":"BusinessContact","children":[]},{"label":"<a href=\"Buttons.html\">Buttons</a>","id":"Buttons","children":[]},{"label":"<a href=\"Call.html\">Call</a>","id":"Call","children":[]},{"label":"<a href=\"Chat.html\">Chat</a>","id":"Chat","children":[]},{"label":"<a href=\"Client.html\">Client</a>","id":"Client","children":[]},{"label":"<a href=\"ClientInfo.html\">ClientInfo</a>","id":"ClientInfo","children":[]},{"label":"<a href=\"Contact.html\">Contact</a>","id":"Contact","children":[]},{"label":"<a href=\"GroupChat.html\">GroupChat</a>","id":"GroupChat","children":[]},{"label":"<a href=\"GroupNotification.html\">GroupNotification</a>","id":"GroupNotification","children":[]},{"label":"<a href=\"InterfaceController.html\">InterfaceController</a>","id":"InterfaceController","children":[]},{"label":"<a href=\"Label.html\">Label</a>","id":"Label","children":[]},{"label":"<a href=\"List.html\">List</a>","id":"List","children":[]},{"label":"<a href=\"Location.html\">Location</a>","id":"Location","children":[]},{"label":"<a href=\"Message.html\">Message</a>","id":"Message","children":[]},{"label":"<a href=\"MessageMedia.html\">MessageMedia</a>","id":"MessageMedia","children":[]},{"label":"<a href=\"Order.html\">Order</a>","id":"Order","children":[]},{"label":"<a href=\"PrivateChat.html\">PrivateChat</a>","id":"PrivateChat","children":[]},{"label":"<a href=\"PrivateContact.html\">PrivateContact</a>","id":"PrivateContact","children":[]},{"label":"<a href=\"Product.html\">Product</a>","id":"Product","children":[]},{"label":"<a href=\"Util.html\">Util</a>","id":"Util","children":[]}],
openedIcon: ' &#x21e3;',
saveState: false,
useContextMenu: false

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: structures/Base.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/Base.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -60,7 +60,7 @@ module.exports &#x3D; Base;</code></pre>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: structures/BusinessContact.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/BusinessContact.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -59,7 +59,7 @@ module.exports &#x3D; BusinessContact;</code></pre>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -0,0 +1,135 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/Buttons.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-banner" role="banner">
</div>
<div id="jsdoc-main" role="main">
<header class="page-header">
<h1>Source: structures/Buttons.js</h1>
</header>
<article>
<pre class="prettyprint linenums"><code>&#x27;use strict&#x27;;
const MessageMedia &#x3D; require(&#x27;./MessageMedia&#x27;);
const Util &#x3D; require(&#x27;../util/Util&#x27;);
/**
* Button spec used in Buttons constructor
* @typedef {Object} ButtonSpec
* @property {string&#x3D;} id - Custom ID to set on the button. A random one will be generated if one is not passed.
* @property {string} body - The text to show on the button.
*/
/**
* @typedef {Object} FormattedButtonSpec
* @property {string} buttonId
* @property {number} type
* @property {Object} buttonText
*/
/**
* Message type buttons
*/
class Buttons {
/**
* @param {string|MessageMedia} body
* @param {ButtonSpec[]} buttons - See {@link ButtonSpec}
* @param {string?} title
* @param {string?} footer
*/
constructor(body, buttons, title, footer) {
/**
* Message body
* @type {string|MessageMedia}
*/
this.body &#x3D; body;
/**
* title of message
* @type {string}
*/
this.title &#x3D; title;
/**
* footer of message
* @type {string}
*/
this.footer &#x3D; footer;
if (body instanceof MessageMedia) {
this.type &#x3D; &#x27;media&#x27;;
this.title &#x3D; &#x27;&#x27;;
}else{
this.type &#x3D; &#x27;chat&#x27;;
}
/**
* buttons of message
* @type {FormattedButtonSpec[]}
*/
this.buttons &#x3D; this._format(buttons);
if(!this.buttons.length){ throw &#x27;[BT01] No buttons&#x27;;}
}
/**
* Creates button array from simple array
* @param {ButtonSpec[]} buttons
* @returns {FormattedButtonSpec[]}
* @example
* Input: [{id:&#x27;customId&#x27;,body:&#x27;button1&#x27;},{body:&#x27;button2&#x27;},{body:&#x27;button3&#x27;},{body:&#x27;button4&#x27;}]
* Returns: [{ buttonId:&#x27;customId&#x27;,buttonText:{&#x27;displayText&#x27;:&#x27;button1&#x27;},type: 1 },{buttonId:&#x27;n3XKsL&#x27;,buttonText:{&#x27;displayText&#x27;:&#x27;button2&#x27;},type:1},{buttonId:&#x27;NDJk0a&#x27;,buttonText:{&#x27;displayText&#x27;:&#x27;button3&#x27;},type:1}]
*/
_format(buttons){
buttons &#x3D; buttons.slice(0,3); // phone users can only see 3 buttons, so lets limit this
return buttons.map((btn) &#x3D;&gt; {
return {&#x27;buttonId&#x27;:btn.id ? String(btn.id) : Util.generateHash(6),&#x27;buttonText&#x27;:{&#x27;displayText&#x27;:btn.body},&#x27;type&#x27;:1};
});
}
}
module.exports &#x3D; Buttons;</code></pre>
</article>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

View File

@@ -0,0 +1,121 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/Call.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-banner" role="banner">
</div>
<div id="jsdoc-main" role="main">
<header class="page-header">
<h1>Source: structures/Call.js</h1>
</header>
<article>
<pre class="prettyprint linenums"><code>&#x27;use strict&#x27;;
const Base &#x3D; require(&#x27;./Base&#x27;);
/**
* Represents a Call on WhatsApp
* @extends {Base}
*/
class Call extends Base {
constructor(client, data) {
super(client);
if (data) this._patch(data);
}
_patch(data) {
/**
* Call ID
* @type {string}
*/
this.id &#x3D; data.id;
/**
* From
* @type {string}
*/
this.from &#x3D; data.peerJid;
/**
* Unix timestamp for when the call was created
* @type {number}
*/
this.timestamp &#x3D; data.offerTime;
/**
* Is video
* @type {boolean}
*/
this.isVideo &#x3D; data.isVideo;
/**
* Is Group
* @type {boolean}
*/
this.isGroup &#x3D; data.isGroup;
/**
* Indicates if the call was sent by the current user
* @type {boolean}
*/
this.fromMe &#x3D; data.outgoing;
/**
* Indicates if the call can be handled in waweb
* @type {boolean}
*/
this.canHandleLocally &#x3D; data.canHandleLocally;
/**
* Indicates if the call Should be handled in waweb
* @type {boolean}
*/
this.webClientShouldHandle &#x3D; data.webClientShouldHandle;
/**
* Object with participants
* @type {object}
*/
this.participants &#x3D; data.participants;
return super._patch(data);
}
}
module.exports &#x3D; Call;</code></pre>
</article>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: structures/Chat.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/Chat.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -96,7 +96,7 @@ class Chat extends Base {
/**
* Indicates if the chat is muted or not
* @type {number}
* @type {boolean}
*/
this.isMuted &#x3D; data.isMuted;
@@ -178,8 +178,8 @@ class Chat extends Base {
}
/**
* Mutes this chat until a specified date
* @param {Date} unmuteDate Date at which the Chat will be unmuted
* Mutes this chat forever, unless a date is specified
* @param {?Date} unmuteDate Date at which the Chat will be unmuted, leave as is to mute forever
*/
async mute(unmuteDate) {
return this.client.muteChat(this.id._serialized, unmuteDate);
@@ -192,33 +192,42 @@ class Chat extends Base {
return this.client.unmuteChat(this.id._serialized);
}
/**
* Mark this chat as unread
*/
async markUnread(){
return this.client.markChatUnread(this.id._serialized);
}
/**
* Loads chat messages, sorted from earliest to latest.
* @param {Object} searchOptions Options for searching messages. Right now only limit is supported.
* @param {Number} [searchOptions.limit&#x3D;50] The amount of messages to return. Note that the actual number of returned messages may be smaller if there aren&#x27;t enough messages in the conversation. Set this to Infinity to load all messages.
* @param {Number} [searchOptions.limit] The amount of messages to return. If no limit is specified, the available messages will be returned. Note that the actual number of returned messages may be smaller if there aren&#x27;t enough messages in the conversation. Set this to Infinity to load all messages.
* @returns {Promise&amp;lt;Array&amp;lt;Message&gt;&gt;}
*/
async fetchMessages(searchOptions) {
if (!searchOptions || !searchOptions.limit) {
searchOptions &#x3D; { limit: 50 };
}
let messages &#x3D; await this.client.pupPage.evaluate(async (chatId, limit) &#x3D;&gt; {
let messages &#x3D; await this.client.pupPage.evaluate(async (chatId, searchOptions) &#x3D;&gt; {
const msgFilter &#x3D; m &#x3D;&gt; !m.isNotification; // dont include notification messages
const chat &#x3D; window.Store.Chat.get(chatId);
let msgs &#x3D; chat.msgs.models.filter(msgFilter);
while (msgs.length &amp;lt; limit) {
const loadedMessages &#x3D; await chat.loadEarlierMsgs();
if (!loadedMessages) break;
msgs &#x3D; [...loadedMessages.filter(msgFilter), ...msgs];
if (searchOptions &amp;amp;&amp;amp; searchOptions.limit &gt; 0) {
while (msgs.length &amp;lt; searchOptions.limit) {
const loadedMessages &#x3D; await chat.loadEarlierMsgs();
if (!loadedMessages) break;
msgs &#x3D; [...loadedMessages.filter(msgFilter), ...msgs];
}
if (msgs.length &gt; searchOptions.limit) {
msgs.sort((a, b) &#x3D;&gt; (a.t &gt; b.t) ? 1 : -1);
msgs &#x3D; msgs.splice(msgs.length - searchOptions.limit);
}
}
msgs.sort((a, b) &#x3D;&gt; (a.t &gt; b.t) ? 1 : -1);
if (msgs.length &gt; limit) msgs &#x3D; msgs.splice(msgs.length - limit);
return msgs.map(m &#x3D;&gt; window.WWebJS.getMessageModel(m));
}, this.id._serialized, searchOptions.limit);
}, this.id._serialized, searchOptions);
return messages.map(m &#x3D;&gt; new Message(this.client, m));
}
@@ -260,6 +269,14 @@ class Chat extends Base {
async getContact() {
return await this.client.getContactById(this.id._serialized);
}
/**
* Returns array of all Labels assigned to this Chat
* @returns {Promise&amp;lt;Array&amp;lt;Label&gt;&gt;}
*/
async getLabels() {
return this.client.getChatLabels(this.id._serialized);
}
}
module.exports &#x3D; Chat;
@@ -273,7 +290,7 @@ module.exports &#x3D; Chat;
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: structures/ClientInfo.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/ClientInfo.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -108,7 +108,7 @@ module.exports &#x3D; ClientInfo;</code></pre>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: structures/Contact.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/Contact.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -33,6 +33,14 @@
const Base &#x3D; require(&#x27;./Base&#x27;);
/**
* ID that represents a contact
* @typedef {Object} ContactId
* @property {string} server
* @property {string} user
* @property {string} _serialized
*/
/**
* Represents a Contact on WhatsApp
* @extends {Base}
@@ -47,7 +55,7 @@ class Contact extends Base {
_patch(data) {
/**
* ID that represents the contact
* @type {object}
* @type {ContactId}
*/
this.id &#x3D; data.id;
@@ -131,7 +139,7 @@ class Contact extends Base {
* @type {boolean}
*/
this.isBlocked &#x3D; data.isBlocked;
return super._patch(data);
}
@@ -143,6 +151,22 @@ class Contact extends Base {
return await this.client.getProfilePicUrl(this.id._serialized);
}
/**
* Returns the contact&#x27;s formatted phone number, (12345678901@c.us) &#x3D;&gt; (+1 (234) 5678-901)
* @returns {Promise&amp;lt;string&gt;}
*/
async getFormattedNumber() {
return await this.client.getFormattedNumber(this.id._serialized);
}
/**
* Returns the contact&#x27;s countrycode, (1541859685@c.us) &#x3D;&gt; (1)
* @returns {Promise&amp;lt;string&gt;}
*/
async getCountryCode() {
return await this.client.getCountryCode(this.id._serialized);
}
/**
* Returns the Chat that corresponds to this Contact.
* Will return null when getting chat for currently logged in user.
@@ -183,10 +207,26 @@ class Contact extends Base {
return true;
}
/**
* Gets the Contact&#x27;s current &quot;about&quot; info. Returns null if you don&#x27;t have permission to read their status.
* @returns {Promise&amp;lt;?string&gt;}
*/
async getAbout() {
const about &#x3D; await this.client.pupPage.evaluate(async (contactId) &#x3D;&gt; {
return window.Store.Wap.statusFind(contactId);
}, this.id._serialized);
if (typeof about.status !&#x3D;&#x3D; &#x27;string&#x27;)
return null;
return about.status;
}
}
module.exports &#x3D; Contact;</code></pre>
module.exports &#x3D; Contact;
</code></pre>
</article>
</div>
</div>
@@ -196,7 +236,7 @@ module.exports &#x3D; Contact;</code></pre>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: structures/GroupChat.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/GroupChat.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -33,6 +33,14 @@
const Chat &#x3D; require(&#x27;./Chat&#x27;);
/**
* Group participant information
* @typedef {Object} GroupParticipant
* @property {ContactId} id
* @property {boolean} isAdmin
* @property {boolean} isSuperAdmin
*/
/**
* Represents a Group Chat on WhatsApp
* @extends {Chat}
@@ -46,6 +54,7 @@ class GroupChat extends Chat {
/**
* Gets the group owner
* @type {ContactId}
*/
get owner() {
return this.groupMetadata.owner;
@@ -69,7 +78,7 @@ class GroupChat extends Chat {
/**
* Gets the group participants
* @type {array}
* @type {Array&amp;lt;GroupParticipant&gt;}
*/
get participants() {
return this.groupMetadata.participants;
@@ -78,6 +87,7 @@ class GroupChat extends Chat {
/**
* Adds a list of participants by ID to the group
* @param {Array&amp;lt;string&gt;} participantIds
* @returns {Promise&amp;lt;Object&gt;}
*/
async addParticipants(participantIds) {
return await this.client.pupPage.evaluate((chatId, participantIds) &#x3D;&gt; {
@@ -88,6 +98,7 @@ class GroupChat extends Chat {
/**
* Removes a list of participants by ID to the group
* @param {Array&amp;lt;string&gt;} participantIds
* @returns {Promise&amp;lt;Object&gt;}
*/
async removeParticipants(participantIds) {
return await this.client.pupPage.evaluate((chatId, participantIds) &#x3D;&gt; {
@@ -98,6 +109,7 @@ class GroupChat extends Chat {
/**
* Promotes participants by IDs to admins
* @param {Array&amp;lt;string&gt;} participantIds
* @returns {Promise&amp;lt;{ status: number }&gt;} Object with status code indicating if the operation was successful
*/
async promoteParticipants(participantIds) {
return await this.client.pupPage.evaluate((chatId, participantIds) &#x3D;&gt; {
@@ -108,6 +120,7 @@ class GroupChat extends Chat {
/**
* Demotes participants by IDs to regular users
* @param {Array&amp;lt;string&gt;} participantIds
* @returns {Promise&amp;lt;{ status: number }&gt;} Object with status code indicating if the operation was successful
*/
async demoteParticipants(participantIds) {
return await this.client.pupPage.evaluate((chatId, participantIds) &#x3D;&gt; {
@@ -118,6 +131,7 @@ class GroupChat extends Chat {
/**
* Updates the group subject
* @param {string} subject
* @returns {Promise}
*/
async setSubject(subject) {
let res &#x3D; await this.client.pupPage.evaluate((chatId, subject) &#x3D;&gt; {
@@ -132,6 +146,7 @@ class GroupChat extends Chat {
/**
* Updates the group description
* @param {string} description
* @returns {Promise}
*/
async setDescription(description) {
let res &#x3D; await this.client.pupPage.evaluate((chatId, description) &#x3D;&gt; {
@@ -178,6 +193,7 @@ class GroupChat extends Chat {
/**
* Gets the invite code for a specific group
* @returns {Promise&amp;lt;string&gt;} Group&#x27;s invite code
*/
async getInviteCode() {
let res &#x3D; await this.client.pupPage.evaluate(chatId &#x3D;&gt; {
@@ -193,6 +209,7 @@ class GroupChat extends Chat {
/**
* Invalidates the current group invite code and generates a new one
* @returns {Promise}
*/
async revokeInvite() {
return await this.client.pupPage.evaluate(chatId &#x3D;&gt; {
@@ -202,6 +219,7 @@ class GroupChat extends Chat {
/**
* Makes the bot leave the group
* @returns {Promise}
*/
async leave() {
return await this.client.pupPage.evaluate(chatId &#x3D;&gt; {
@@ -221,7 +239,7 @@ module.exports &#x3D; GroupChat;</code></pre>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: structures/GroupNotification.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/GroupNotification.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -74,7 +74,7 @@ class GroupNotification extends Base {
*
* @type {string}
*/
this.chatId &#x3D; typeof (data.from) &#x3D;&#x3D;&#x3D; &#x27;object&#x27; ? data.from._serialized : data.from;
this.chatId &#x3D; typeof (data.to) &#x3D;&#x3D;&#x3D; &#x27;object&#x27; ? data.to._serialized : data.to;
/**
* ContactId for the user that produced the GroupNotification.
@@ -143,7 +143,7 @@ module.exports &#x3D; GroupNotification;
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -0,0 +1,103 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/Label.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-banner" role="banner">
</div>
<div id="jsdoc-main" role="main">
<header class="page-header">
<h1>Source: structures/Label.js</h1>
</header>
<article>
<pre class="prettyprint linenums"><code>&#x27;use strict&#x27;;
const Base &#x3D; require(&#x27;./Base&#x27;);
// eslint-disable-next-line no-unused-vars
const Chat &#x3D; require(&#x27;./Chat&#x27;);
/**
* WhatsApp Business Label information
*/
class Label extends Base {
/**
* @param {Base} client
* @param {object} labelData
*/
constructor(client, labelData){
super(client);
if(labelData) this._patch(labelData);
}
_patch(labelData){
/**
* Label ID
* @type {string}
*/
this.id &#x3D; labelData.id;
/**
* Label name
* @type {string}
*/
this.name &#x3D; labelData.name;
/**
* Label hex color
* @type {string}
*/
this.hexColor &#x3D; labelData.hexColor;
}
/**
* Get all chats that have been assigned this Label
* @returns {Promise&amp;lt;Array&amp;lt;Chat&gt;&gt;}
*/
async getChats(){
return this.client.getChatsByLabelId(this.id);
}
}
module.exports &#x3D; Label;</code></pre>
</article>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

View File

@@ -0,0 +1,133 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/List.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-banner" role="banner">
</div>
<div id="jsdoc-main" role="main">
<header class="page-header">
<h1>Source: structures/List.js</h1>
</header>
<article>
<pre class="prettyprint linenums"><code>&#x27;use strict&#x27;;
const Util &#x3D; require(&#x27;../util/Util&#x27;);
/**
* Message type List
*/
class List {
/**
* @param {string} body
* @param {string} buttonText
* @param {Array&amp;lt;any&gt;} sections
* @param {string?} title
* @param {string?} footer
*/
constructor(body, buttonText, sections, title, footer) {
/**
* Message body
* @type {string}
*/
this.description &#x3D; body;
/**
* List button text
* @type {string}
*/
this.buttonText &#x3D; buttonText;
/**
* title of message
* @type {string}
*/
this.title &#x3D; title;
/**
* footer of message
* @type {string}
*/
this.footer &#x3D; footer;
/**
* sections of message
* @type {Array&amp;lt;any&gt;}
*/
this.sections &#x3D; this._format(sections);
}
/**
* Creates section array from simple array
* @param {Array&amp;lt;any&gt;} sections
* @returns {Array&amp;lt;any&gt;}
* @example
* Input: [{title:&#x27;sectionTitle&#x27;,rows:[{id:&#x27;customId&#x27;, title:&#x27;ListItem2&#x27;, description: &#x27;desc&#x27;},{title:&#x27;ListItem2&#x27;}]}}]
* Returns: [{&#x27;title&#x27;:&#x27;sectionTitle&#x27;,&#x27;rows&#x27;:[{&#x27;rowId&#x27;:&#x27;customId&#x27;,&#x27;title&#x27;:&#x27;ListItem1&#x27;,&#x27;description&#x27;:&#x27;desc&#x27;},{&#x27;rowId&#x27;:&#x27;oGSRoD&#x27;,&#x27;title&#x27;:&#x27;ListItem2&#x27;,&#x27;description&#x27;:&#x27;&#x27;}]}]
*/
_format(sections){
if(!sections.length){throw &#x27;[LT02] List without sections&#x27;;}
if(sections.length &gt; 1 &amp;amp;&amp;amp; sections.filter(s &#x3D;&gt; typeof s.title &#x3D;&#x3D; &#x27;undefined&#x27;).length &gt; 1){throw &#x27;[LT05] You can\&#x27;t have more than one empty title.&#x27;;}
return sections.map( (section) &#x3D;&gt;{
if(!section.rows.length){throw &#x27;[LT03] Section without rows&#x27;;}
return {
title: section.title ? section.title : undefined,
rows: section.rows.map( (row) &#x3D;&gt; {
if(!row.title){throw &#x27;[LT04] Row without title&#x27;;}
return {
rowId: row.id ? row.id : Util.generateHash(6),
title: row.title,
description: row.description ? row.description : &#x27;&#x27;
};
})
};
});
}
}
module.exports &#x3D; List;
</code></pre>
</article>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: structures/Location.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/Location.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -71,7 +71,7 @@ module.exports &#x3D; Location;</code></pre>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: structures/Message.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/Message.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -34,6 +34,8 @@
const Base &#x3D; require(&#x27;./Base&#x27;);
const MessageMedia &#x3D; require(&#x27;./MessageMedia&#x27;);
const Location &#x3D; require(&#x27;./Location&#x27;);
const Order &#x3D; require(&#x27;./Order&#x27;);
const Payment &#x3D; require(&#x27;./Payment&#x27;);
const { MessageTypes } &#x3D; require(&#x27;../util/Constants&#x27;);
/**
@@ -71,7 +73,7 @@ class Message extends Base {
* Indicates if the message has media available for download
* @type {boolean}
*/
this.hasMedia &#x3D; data.clientUrl ? true : false;
this.hasMedia &#x3D; Boolean(data.mediaKey &amp;amp;&amp;amp; data.directPath);
/**
* Message content
@@ -112,18 +114,38 @@ class Message extends Base {
*/
this.author &#x3D; (typeof (data.author) &#x3D;&#x3D;&#x3D; &#x27;object&#x27; &amp;amp;&amp;amp; data.author !&#x3D;&#x3D; null) ? data.author._serialized : data.author;
/**
* String that represents from which device type the message was sent
* @type {string}
*/
this.deviceType &#x3D; data.id.id.length &gt; 21 ? &#x27;android&#x27; : data.id.id.substring(0,2) &#x3D;&#x3D;&#x27;3A&#x27; ? &#x27;ios&#x27; : &#x27;web&#x27;;
/**
* Indicates if the message was forwarded
* @type {boolean}
*/
this.isForwarded &#x3D; data.isForwarded;
/**
* Indicates how many times the message was forwarded.
*
* The maximum value is 127.
* @type {number}
*/
this.forwardingScore &#x3D; data.forwardingScore || 0;
/**
* Indicates if the message is a status update
* @type {boolean}
*/
this.isStatus &#x3D; data.isStatusV3;
/**
* Indicates if the message was starred
* @type {boolean}
*/
this.isStarred &#x3D; data.star;
/**
* Indicates if the message was a broadcast
* @type {boolean}
@@ -154,6 +176,19 @@ class Message extends Base {
*/
this.vCards &#x3D; data.type &#x3D;&#x3D;&#x3D; MessageTypes.CONTACT_CARD_MULTI ? data.vcardList.map((c) &#x3D;&gt; c.vcard) : data.type &#x3D;&#x3D;&#x3D; MessageTypes.CONTACT_CARD ? [data.body] : [];
/**
* Group Invite Data
* @type {object}
*/
this.inviteV4 &#x3D; data.type &#x3D;&#x3D;&#x3D; MessageTypes.GROUP_INVITE ? {
inviteCode: data.inviteCode,
inviteCodeExp: data.inviteCodeExp,
groupId: data.inviteGrp,
groupName: data.inviteGrpName,
fromId: data.from._serialized,
toId: data.to._serialized
} : undefined;
/**
* Indicates the mentions in the message body.
* @type {Array&amp;lt;string&gt;}
@@ -164,6 +199,71 @@ class Message extends Base {
this.mentionedIds &#x3D; data.mentionedJidList;
}
/**
* Order ID for message type ORDER
* @type {string}
*/
this.orderId &#x3D; data.orderId ? data.orderId : undefined;
/**
* Order Token for message type ORDER
* @type {string}
*/
this.token &#x3D; data.token ? data.token : undefined;
/**
* Indicates whether the message is a Gif
* @type {boolean}
*/
this.isGif &#x3D; Boolean(data.isGif);
/**
* Indicates if the message will disappear after it expires
* @type {boolean}
*/
this.isEphemeral &#x3D; data.isEphemeral;
/** Title */
if (data.title) {
this.title &#x3D; data.title;
}
/** Description */
if (data.description) {
this.description &#x3D; data.description;
}
/** Business Owner JID */
if (data.businessOwnerJid) {
this.businessOwnerJid &#x3D; data.businessOwnerJid;
}
/** Product ID */
if (data.productId) {
this.productId &#x3D; data.productId;
}
/**
* Links included in the message.
* @type {Array&amp;lt;{link: string, isSuspicious: boolean}&gt;}
*
*/
this.links &#x3D; data.links;
/** Buttons */
if (data.dynamicReplyButtons) {
this.dynamicReplyButtons &#x3D; data.dynamicReplyButtons;
}
/** Selected Button Id **/
if (data.selectedButtonId) {
this.selectedButtonId &#x3D; data.selectedButtonId;
}
/** Selected List row Id **/
if (data.listResponse &amp;amp;&amp;amp; data.listResponse.singleSelectReply.selectedRowId) {
this.selectedRowId &#x3D; data.listResponse.singleSelectReply.selectedRowId;
}
return super._patch(data);
}
@@ -233,6 +333,14 @@ class Message extends Base {
return this.client.sendMessage(chatId, content, options);
}
/**
* Accept Group V4 Invite
* @returns {Promise&amp;lt;Object&gt;}
*/
async acceptGroupV4Invite() {
return await this.client.acceptGroupV4Invite(this.inviteV4);
}
/**
* Forwards this message to another chat
*
@@ -264,24 +372,39 @@ class Message extends Base {
if (msg.mediaData.mediaStage !&#x3D; &#x27;RESOLVED&#x27;) {
// try to resolve media
await msg.downloadMedia(true, 1);
await msg.downloadMedia({
downloadEvenIfExpensive: true,
rmrReason: 1
});
}
if (msg.mediaData.mediaStage.includes(&#x27;ERROR&#x27;)) {
if (msg.mediaData.mediaStage.includes(&#x27;ERROR&#x27;) || msg.mediaData.mediaStage &#x3D;&#x3D;&#x3D; &#x27;FETCHING&#x27;) {
// media could not be downloaded
return undefined;
}
const buffer &#x3D; await window.WWebJS.downloadBuffer(msg.clientUrl);
const decrypted &#x3D; await window.Store.CryptoLib.decryptE2EMedia(msg.type, buffer, msg.mediaKey, msg.mimetype);
const data &#x3D; await window.WWebJS.readBlobAsync(decrypted._blob);
return {
data: data.split(&#x27;,&#x27;)[1],
mimetype: msg.mimetype,
filename: msg.filename
};
try {
const decryptedMedia &#x3D; await window.Store.DownloadManager.downloadAndDecrypt({
directPath: msg.directPath,
encFilehash: msg.encFilehash,
filehash: msg.filehash,
mediaKey: msg.mediaKey,
mediaKeyTimestamp: msg.mediaKeyTimestamp,
type: msg.type,
signal: (new AbortController).signal
});
const data &#x3D; window.WWebJS.arrayBufferToBase64(decryptedMedia);
return {
data,
mimetype: msg.mimetype,
filename: msg.filename
};
} catch (e) {
if(e.status &amp;amp;&amp;amp; e.status &#x3D;&#x3D;&#x3D; 404) return undefined;
throw e;
}
}, this.id._serialized);
if (!result) return undefined;
@@ -296,13 +419,99 @@ class Message extends Base {
await this.client.pupPage.evaluate((msgId, everyone) &#x3D;&gt; {
let msg &#x3D; window.Store.Msg.get(msgId);
if (everyone &amp;amp;&amp;amp; msg.id.fromMe &amp;amp;&amp;amp; msg.canRevoke()) {
return window.Store.Cmd.sendRevokeMsgs(msg.chat, [msg], true);
if (everyone &amp;amp;&amp;amp; msg.id.fromMe &amp;amp;&amp;amp; msg._canRevoke()) {
return window.Store.Cmd.sendRevokeMsgs(msg.chat, [msg], {type: &#x27;Sender&#x27;});
}
return window.Store.Cmd.sendDeleteMsgs(msg.chat, [msg], true);
}, this.id._serialized, everyone);
}
/**
* Stars this message
*/
async star() {
await this.client.pupPage.evaluate((msgId) &#x3D;&gt; {
let msg &#x3D; window.Store.Msg.get(msgId);
if (msg.canStar()) {
return msg.chat.sendStarMsgs([msg], true);
}
}, this.id._serialized);
}
/**
* Unstars this message
*/
async unstar() {
await this.client.pupPage.evaluate((msgId) &#x3D;&gt; {
let msg &#x3D; window.Store.Msg.get(msgId);
if (msg.canStar()) {
return msg.chat.sendStarMsgs([msg], false);
}
}, this.id._serialized);
}
/**
* Message Info
* @typedef {Object} MessageInfo
* @property {Array&amp;lt;{id: ContactId, t: number}&gt;} delivery Contacts to which the message has been delivered to
* @property {number} deliveryRemaining Amount of people to whom the message has not been delivered to
* @property {Array&amp;lt;{id: ContactId, t: number}&gt;} played Contacts who have listened to the voice message
* @property {number} playedRemaining Amount of people who have not listened to the message
* @property {Array&amp;lt;{id: ContactId, t: number}&gt;} read Contacts who have read the message
* @property {number} readRemaining Amount of people who have not read the message
*/
/**
* Get information about message delivery status. May return null if the message does not exist or is not sent by you.
* @returns {Promise&amp;lt;?MessageInfo&gt;}
*/
async getInfo() {
const info &#x3D; await this.client.pupPage.evaluate(async (msgId) &#x3D;&gt; {
const msg &#x3D; window.Store.Msg.get(msgId);
if(!msg) return null;
return await window.Store.Wap.queryMsgInfo(msg.id);
}, this.id._serialized);
if(info.status) {
return null;
}
return info;
}
/**
* Gets the order associated with a given message
* @return {Promise&amp;lt;Order&gt;}
*/
async getOrder() {
if (this.type &#x3D;&#x3D;&#x3D; MessageTypes.ORDER) {
const result &#x3D; await this.client.pupPage.evaluate((orderId, token) &#x3D;&gt; {
return window.WWebJS.getOrderDetail(orderId, token);
}, this.orderId, this.token);
if (!result) return undefined;
return new Order(this.client, result);
}
return undefined;
}
/**
* Gets the payment details associated with a given message
* @return {Promise&amp;lt;Payment&gt;}
*/
async getPayment() {
if (this.type &#x3D;&#x3D;&#x3D; MessageTypes.PAYMENT) {
const msg &#x3D; await this.client.pupPage.evaluate(async (msgId) &#x3D;&gt; {
const msg &#x3D; window.Store.Msg.get(msgId);
if(!msg) return null;
return msg.serialize();
}, this.id._serialized);
return new Payment(this.client, msg);
}
return undefined;
}
}
module.exports &#x3D; Message;
@@ -316,7 +525,7 @@ module.exports &#x3D; Message;
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: structures/MessageMedia.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/MessageMedia.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -34,6 +34,8 @@
const fs &#x3D; require(&#x27;fs&#x27;);
const path &#x3D; require(&#x27;path&#x27;);
const mime &#x3D; require(&#x27;mime&#x27;);
const fetch &#x3D; require(&#x27;node-fetch&#x27;);
const { URL } &#x3D; require(&#x27;url&#x27;);
/**
* Media attached to a message
@@ -74,9 +76,63 @@ class MessageMedia {
return new MessageMedia(mimetype, b64data, filename);
}
/**
* Creates a MessageMedia instance from a URL
* @param {string} url
* @param {Object} [options]
* @param {boolean} [options.unsafeMime&#x3D;false]
* @param {string} [options.filename]
* @param {object} [options.client]
* @param {object} [options.reqOptions]
* @param {number} [options.reqOptions.size&#x3D;0]
* @returns {Promise&amp;lt;MessageMedia&gt;}
*/
static async fromUrl(url, options &#x3D; {}) {
const pUrl &#x3D; new URL(url);
let mimetype &#x3D; mime.getType(pUrl.pathname);
if (!mimetype &amp;amp;&amp;amp; !options.unsafeMime)
throw new Error(&#x27;Unable to determine MIME type using URL. Set unsafeMime to true to download it anyway.&#x27;);
async function fetchData (url, options) {
const reqOptions &#x3D; Object.assign({ headers: { accept: &#x27;image/* video/* text/* audio/*&#x27; } }, options);
const response &#x3D; await fetch(url, reqOptions);
const mime &#x3D; response.headers.get(&#x27;Content-Type&#x27;);
const contentDisposition &#x3D; response.headers.get(&#x27;Content-Disposition&#x27;);
const name &#x3D; contentDisposition ? contentDisposition.match(/((?&amp;lt;&#x3D;filename&#x3D;&quot;)(.*)(?&#x3D;&quot;))/) : null;
let data &#x3D; &#x27;&#x27;;
if (response.buffer) {
data &#x3D; (await response.buffer()).toString(&#x27;base64&#x27;);
} else {
const bArray &#x3D; new Uint8Array(await response.arrayBuffer());
bArray.forEach((b) &#x3D;&gt; {
data +&#x3D; String.fromCharCode(b);
});
data &#x3D; btoa(data);
}
return { data, mime, name };
}
const res &#x3D; options.client
? (await options.client.pupPage.evaluate(fetchData, url, options.reqOptions))
: (await fetchData(url, options.reqOptions));
const filename &#x3D; options.filename ||
(res.name ? res.name[0] : (pUrl.pathname.split(&#x27;/&#x27;).pop() || &#x27;file&#x27;));
if (!mimetype)
mimetype &#x3D; res.mime;
return new MessageMedia(mimetype, res.data, filename);
}
}
module.exports &#x3D; MessageMedia;</code></pre>
module.exports &#x3D; MessageMedia;
</code></pre>
</article>
</div>
</div>
@@ -86,7 +142,7 @@ module.exports &#x3D; MessageMedia;</code></pre>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -0,0 +1,105 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/Order.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-banner" role="banner">
</div>
<div id="jsdoc-main" role="main">
<header class="page-header">
<h1>Source: structures/Order.js</h1>
</header>
<article>
<pre class="prettyprint linenums"><code>&#x27;use strict&#x27;;
const Base &#x3D; require(&#x27;./Base&#x27;);
const Product &#x3D; require(&#x27;./Product&#x27;);
/**
* Represents a Order on WhatsApp
* @extends {Base}
*/
class Order extends Base {
constructor(client, data) {
super(client);
if (data) this._patch(data);
}
_patch(data) {
/**
* List of products
* @type {Array&amp;lt;Product&gt;}
*/
if (data.products) {
this.products &#x3D; data.products.map(product &#x3D;&gt; new Product(this.client, product));
}
/**
* Order Subtotal
* @type {string}
*/
this.subtotal &#x3D; data.subtotal;
/**
* Order Total
* @type {string}
*/
this.total &#x3D; data.total;
/**
* Order Currency
* @type {string}
*/
this.currency &#x3D; data.currency;
/**
* Order Created At
* @type {number}
*/
this.createdAt &#x3D; data.createdAt;
return super._patch(data);
}
}
module.exports &#x3D; Order;</code></pre>
</article>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

View File

@@ -0,0 +1,133 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/Payment.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-banner" role="banner">
</div>
<div id="jsdoc-main" role="main">
<header class="page-header">
<h1>Source: structures/Payment.js</h1>
</header>
<article>
<pre class="prettyprint linenums"><code>const Base &#x3D; require(&#x27;./Base&#x27;);
class Payment extends Base {
constructor(client, data) {
super(client);
if (data) this._patch(data);
}
_patch(data) {
/**
* The payment Id
* @type {object}
*/
this.id &#x3D; data.id;
/**
* The payment currency
* @type {string}
*/
this.paymentCurrency &#x3D; data.paymentCurrency;
/**
* The payment ammount ( R$ 1.00 &#x3D; 1000 )
* @type {number}
*/
this.paymentAmount1000 &#x3D; data.paymentAmount1000;
/**
* The payment receiver
* @type {object}
*/
this.paymentMessageReceiverJid &#x3D; data.paymentMessageReceiverJid;
/**
* The payment transaction timestamp
* @type {number}
*/
this.paymentTransactionTimestamp &#x3D; data.paymentTransactionTimestamp;
/**
* The paymentStatus
*
* Possible Status
* 0:UNKNOWN_STATUS
* 1:PROCESSING
* 2:SENT
* 3:NEED_TO_ACCEPT
* 4:COMPLETE
* 5:COULD_NOT_COMPLETE
* 6:REFUNDED
* 7:EXPIRED
* 8:REJECTED
* 9:CANCELLED
* 10:WAITING_FOR_PAYER
* 11:WAITING
*
* @type {number}
*/
this.paymentStatus &#x3D; data.paymentStatus;
/**
* Integer that represents the payment Text
* @type {number}
*/
this.paymentTxnStatus &#x3D; data.paymentTxnStatus;
/**
* The note sent with the payment
* @type {string}
*/
this.paymentNote &#x3D; !data.paymentNoteMsg ? undefined : data.paymentNoteMsg.body ? data.paymentNoteMsg.body : undefined ;
return super._patch(data);
}
}
module.exports &#x3D; Payment;
</code></pre>
</article>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: structures/PrivateChat.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/PrivateChat.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -51,7 +51,7 @@ module.exports &#x3D; PrivateChat;</code></pre>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: structures/PrivateContact.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/PrivateContact.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -51,7 +51,7 @@ module.exports &#x3D; PrivateContact;</code></pre>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -0,0 +1,121 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/Product.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-banner" role="banner">
</div>
<div id="jsdoc-main" role="main">
<header class="page-header">
<h1>Source: structures/Product.js</h1>
</header>
<article>
<pre class="prettyprint linenums"><code>&#x27;use strict&#x27;;
const Base &#x3D; require(&#x27;./Base&#x27;);
const ProductMetadata &#x3D; require(&#x27;./ProductMetadata&#x27;);
/**
* Represents a Product on WhatsAppBusiness
* @extends {Base}
*/
class Product extends Base {
constructor(client, data) {
super(client);
if (data) this._patch(data);
}
_patch(data) {
/**
* Product ID
* @type {string}
*/
this.id &#x3D; data.id;
/**
* Price
* @type {string}
*/
this.price &#x3D; data.price ? data.price : &#x27;&#x27;;
/**
* Product Thumbnail
* @type {string}
*/
this.thumbnailUrl &#x3D; data.thumbnailUrl;
/**
* Currency
* @type {string}
*/
this.currency &#x3D; data.currency;
/**
* Product Name
* @type {string}
*/
this.name &#x3D; data.name;
/**
* Product Quantity
* @type {number}
*/
this.quantity &#x3D; data.quantity;
/** Product metadata */
this.data &#x3D; null;
return super._patch(data);
}
async getData() {
if (this.data &#x3D;&#x3D;&#x3D; null) {
let result &#x3D; await this.client.pupPage.evaluate((productId) &#x3D;&gt; {
return window.WWebJS.getProductMetadata(productId);
}, this.id);
if (!result) {
this.data &#x3D; undefined;
} else {
this.data &#x3D; new ProductMetadata(this.client, result);
}
}
return this.data;
}
}
module.exports &#x3D; Product;</code></pre>
</article>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

View File

@@ -0,0 +1,78 @@
<!doctype html>
<html>
<head>
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.15.7 &raquo; Source: structures/ProductMetadata.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
<link href="css/baseline.css" rel="stylesheet">
</head>
<body onload="prettyPrint()">
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
<div id="jsdoc-body-container">
<div id="jsdoc-content">
<div id="jsdoc-content-container">
<div id="jsdoc-banner" role="banner">
</div>
<div id="jsdoc-main" role="main">
<header class="page-header">
<h1>Source: structures/ProductMetadata.js</h1>
</header>
<article>
<pre class="prettyprint linenums"><code>const Base &#x3D; require(&#x27;./Base&#x27;);
class ProductMetadata extends Base {
constructor(client, data) {
super(client);
if (data) this._patch(data);
}
_patch(data) {
/** Product ID */
this.id &#x3D; data.id;
/** Retailer ID */
this.retailer_id &#x3D; data.retailer_id;
/** Product Name */
this.name &#x3D; data.name;
/** Product Description */
this.description &#x3D; data.description;
return super._patch(data);
}
}
module.exports &#x3D; ProductMetadata;</code></pre>
</article>
</div>
</div>
<nav id="jsdoc-toc-nav" role="navigation"></nav>
</div>
</div>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>
<script src="scripts/jquery.min.js"></script>
<script src="scripts/tree.jquery.js"></script>
<script src="scripts/prettify.js"></script>
<script src="scripts/jsdoc-toc.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/scrollanchor.js"></script>
</body>
</html>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: util/Constants.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: util/Constants.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -42,9 +42,12 @@ exports.DefaultOptions &#x3D; {
qrTimeoutMs: 45000,
qrRefreshIntervalMs: 20000,
authTimeoutMs: 45000,
qrMaxRetries: 0,
takeoverOnConflict: false,
takeoverTimeoutMs: 0,
userAgent: &#x27;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36&#x27;
userAgent: &#x27;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36&#x27;,
ffmpegPath: &#x27;ffmpeg&#x27;,
bypassCSP: false
};
/**
@@ -79,7 +82,8 @@ exports.Events &#x3D; {
QR_RECEIVED: &#x27;qr&#x27;,
DISCONNECTED: &#x27;disconnected&#x27;,
STATE_CHANGED: &#x27;change_state&#x27;,
BATTERY_CHANGED: &#x27;change_battery&#x27;
BATTERY_CHANGED: &#x27;change_battery&#x27;,
INCOMING_CALL: &#x27;incoming_call&#x27;
};
/**
@@ -98,8 +102,31 @@ exports.MessageTypes &#x3D; {
LOCATION: &#x27;location&#x27;,
CONTACT_CARD: &#x27;vcard&#x27;,
CONTACT_CARD_MULTI: &#x27;multi_vcard&#x27;,
ORDER: &#x27;order&#x27;,
REVOKED: &#x27;revoked&#x27;,
UNKNOWN: &#x27;unknown&#x27;
PRODUCT: &#x27;product&#x27;,
UNKNOWN: &#x27;unknown&#x27;,
GROUP_INVITE: &#x27;groups_v4_invite&#x27;,
LIST: &#x27;list&#x27;,
LIST_RESPONSE: &#x27;list_response&#x27;,
BUTTONS_RESPONSE: &#x27;buttons_response&#x27;,
PAYMENT: &#x27;payment&#x27;,
BROADCAST_NOTIFICATION: &#x27;broadcast_notification&#x27;,
CALL_LOG: &#x27;call_log&#x27;,
CIPHERTEXT: &#x27;ciphertext&#x27;,
DEBUG: &#x27;debug&#x27;,
E2E_NOTIFICATION: &#x27;e2e_notification&#x27;,
GP2: &#x27;gp2&#x27;,
GROUP_NOTIFICATION: &#x27;group_notification&#x27;,
HSM: &#x27;hsm&#x27;,
INTERACTIVE: &#x27;interactive&#x27;,
NATIVE_FLOW: &#x27;native_flow&#x27;,
NOTIFICATION: &#x27;notification&#x27;,
NOTIFICATION_TEMPLATE: &#x27;notification_template&#x27;,
OVERSIZED: &#x27;oversized&#x27;,
PROTOCOL: &#x27;protocol&#x27;,
REACTION: &#x27;reaction&#x27;,
TEMPLATE_BUTTON_REPLY: &#x27;template_button_reply&#x27;,
};
/**
@@ -173,7 +200,7 @@ exports.MessageAck &#x3D; {
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: util/InterfaceController.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: util/InterfaceController.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -46,7 +46,8 @@ class InterfaceController {
*/
async openChatWindow(chatId) {
await this.pupPage.evaluate(async chatId &#x3D;&gt; {
let chat &#x3D; await window.Store.Chat.get(chatId);
let chatWid &#x3D; window.Store.WidFactory.createWid(chatId);
let chat &#x3D; await window.Store.Chat.find(chatWid);
await window.Store.Cmd.openChatAt(chat);
}, chatId);
}
@@ -58,10 +59,32 @@ class InterfaceController {
async openChatDrawer(chatId) {
await this.pupPage.evaluate(async chatId &#x3D;&gt; {
let chat &#x3D; await window.Store.Chat.get(chatId);
await window.Store.Cmd.chatInfoDrawer(chat);
await window.Store.Cmd.openDrawerMid(chat);
}, chatId);
}
/**
* Opens the Chat Search
* @param {string} chatId ID of the chat search that will be opened
*/
async openChatSearch(chatId) {
await this.pupPage.evaluate(async chatId &#x3D;&gt; {
let chat &#x3D; await window.Store.Chat.get(chatId);
await window.Store.Cmd.chatSearch(chat);
}, chatId);
}
/**
* Opens or Scrolls the Chat Window to the position of the message
* @param {string} msgId ID of the message that will be scrolled to
*/
async openChatWindowAt(msgId) {
await this.pupPage.evaluate(async msgId &#x3D;&gt; {
let msg &#x3D; await window.Store.Msg.get(msgId);
await window.Store.Cmd.openChatAt(msg.chat, msg.chat.getSearchContext(msg));
}, msgId);
}
/**
* Opens the Message Drawer
* @param {string} msgId ID of the message drawer that will be opened
@@ -81,10 +104,53 @@ class InterfaceController {
await window.Store.Cmd.closeDrawerRight();
});
}
/**
* Get all Features
*/
async getFeatures() {
return await this.pupPage.evaluate(() &#x3D;&gt; {
return window.Store.Features.F;
});
}
/**
* Check if Feature is enabled
* @param {string} feature status to check
*/
async checkFeatureStatus(feature) {
return await this.pupPage.evaluate((feature) &#x3D;&gt; {
return window.Store.Features.supportsFeature(feature);
}, feature);
}
/**
* Enable Features
* @param {string[]} features to be enabled
*/
async enableFeatures(features) {
await this.pupPage.evaluate((features) &#x3D;&gt; {
for (const feature in features) {
window.Store.Features.setFeature(features[feature], true);
}
}, features);
}
/**
* Disable Features
* @param {string[]} features to be disabled
*/
async disableFeatures(features) {
await this.pupPage.evaluate((features) &#x3D;&gt; {
for (const feature in features) {
window.Store.Features.setFeature(features[feature], false);
}
}, features);
}
}
module.exports &#x3D; InterfaceController;</code></pre>
module.exports &#x3D; InterfaceController;
</code></pre>
</article>
</div>
</div>
@@ -94,7 +160,7 @@ module.exports &#x3D; InterfaceController;</code></pre>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -2,9 +2,9 @@
<html>
<head>
<meta name="generator" content="JSDoc 3.6.6">
<meta name="generator" content="JSDoc 3.6.7">
<meta charset="utf-8">
<title>whatsapp-web.js 1.11.2 &raquo; Source: util/Util.js</title>
<title>whatsapp-web.js 1.15.7 &raquo; Source: util/Util.js</title>
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Karla:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Noto+Serif:400,400i,700,700i" type="text/css">
<link rel="stylesheet" href="https://brick.a.ssl.fastly.net/Inconsolata:500" type="text/css">
@@ -15,7 +15,7 @@
<nav id="jsdoc-navbar" role="navigation" class="jsdoc-navbar">
<div id="jsdoc-navbar-container">
<div id="jsdoc-navbar-content">
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>11.<wbr>2</a>
<a href="index.html" class="jsdoc-navbar-package-name">whatsapp-web.<wbr>js 1.<wbr>15.<wbr>7</a>
</div>
</div>
</nav>
@@ -31,6 +31,14 @@
<article>
<pre class="prettyprint linenums"><code>&#x27;use strict&#x27;;
const sharp &#x3D; require(&#x27;sharp&#x27;);
const path &#x3D; require(&#x27;path&#x27;);
const Crypto &#x3D; require(&#x27;crypto&#x27;);
const { tmpdir } &#x3D; require(&#x27;os&#x27;);
const ffmpeg &#x3D; require(&#x27;fluent-ffmpeg&#x27;);
const webp &#x3D; require(&#x27;node-webpmux&#x27;);
const fs &#x3D; require(&#x27;fs&#x27;).promises;
const has &#x3D; (o, k) &#x3D;&gt; Object.prototype.hasOwnProperty.call(o, k);
/**
@@ -42,6 +50,16 @@ class Util {
throw new Error(&#x60;The ${this.constructor.name} class may not be instantiated.&#x60;);
}
static generateHash(length) {
var result &#x3D; &#x27;&#x27;;
var characters &#x3D; &#x27;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&#x27;;
var charactersLength &#x3D; characters.length;
for ( var i &#x3D; 0; i &amp;lt; length; i++ ) {
result +&#x3D; characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
/**
* Sets default properties on an object that aren&#x27;t already specified.
* @param {Object} def Default properties
@@ -61,9 +79,160 @@ class Util {
return given;
}
/**
* Formats a image to webp
* @param {MessageMedia} media
*
* @returns {Promise&amp;lt;MessageMedia&gt;} media in webp format
*/
static async formatImageToWebpSticker(media) {
if (!media.mimetype.includes(&#x27;image&#x27;))
throw new Error(&#x27;media is not a image&#x27;);
if (media.mimetype.includes(&#x27;webp&#x27;)) {
return media;
}
const buff &#x3D; Buffer.from(media.data, &#x27;base64&#x27;);
let sharpImg &#x3D; sharp(buff);
sharpImg &#x3D; sharpImg.webp();
sharpImg &#x3D; sharpImg.resize(512, 512, {
fit: &#x27;contain&#x27;,
background: { r: 0, g: 0, b: 0, alpha: 0 },
});
let webpBase64 &#x3D; (await sharpImg.toBuffer()).toString(&#x27;base64&#x27;);
return {
mimetype: &#x27;image/webp&#x27;,
data: webpBase64,
filename: media.filename,
};
}
/**
* Formats a video to webp
* @param {MessageMedia} media
*
* @returns {Promise&amp;lt;MessageMedia&gt;} media in webp format
*/
static async formatVideoToWebpSticker(media) {
if (!media.mimetype.includes(&#x27;video&#x27;))
throw new Error(&#x27;media is not a video&#x27;);
const videoType &#x3D; media.mimetype.split(&#x27;/&#x27;)[1];
const tempFile &#x3D; path.join(
tmpdir(),
&#x60;${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp&#x60;
);
const stream &#x3D; new (require(&#x27;stream&#x27;).Readable)();
const buffer &#x3D; Buffer.from(
media.data.replace(&#x60;data:${media.mimetype};base64,&#x60;, &#x27;&#x27;),
&#x27;base64&#x27;
);
stream.push(buffer);
stream.push(null);
await new Promise((resolve, reject) &#x3D;&gt; {
ffmpeg(stream)
.inputFormat(videoType)
.on(&#x27;error&#x27;, reject)
.on(&#x27;end&#x27;, () &#x3D;&gt; resolve(true))
.addOutputOptions([
&#x27;-vcodec&#x27;,
&#x27;libwebp&#x27;,
&#x27;-vf&#x27;,
// eslint-disable-next-line no-useless-escape
&#x27;scale&#x3D;\&#x27;iw*min(300/iw\,300/ih)\&#x27;:\&#x27;ih*min(300/iw\,300/ih)\&#x27;,format&#x3D;rgba,pad&#x3D;300:300:\&#x27;(300-iw)/2\&#x27;:\&#x27;(300-ih)/2\&#x27;:\&#x27;#00000000\&#x27;,setsar&#x3D;1,fps&#x3D;10&#x27;,
&#x27;-loop&#x27;,
&#x27;0&#x27;,
&#x27;-ss&#x27;,
&#x27;00:00:00.0&#x27;,
&#x27;-t&#x27;,
&#x27;00:00:05.0&#x27;,
&#x27;-preset&#x27;,
&#x27;default&#x27;,
&#x27;-an&#x27;,
&#x27;-vsync&#x27;,
&#x27;0&#x27;,
&#x27;-s&#x27;,
&#x27;512:512&#x27;,
])
.toFormat(&#x27;webp&#x27;)
.save(tempFile);
});
const data &#x3D; await fs.readFile(tempFile, &#x27;base64&#x27;);
await fs.unlink(tempFile);
return {
mimetype: &#x27;image/webp&#x27;,
data: data,
filename: media.filename,
};
}
/**
* Sticker metadata.
* @typedef {Object} StickerMetadata
* @property {string} [name]
* @property {string} [author]
* @property {string[]} [categories]
*/
/**
* Formats a media to webp
* @param {MessageMedia} media
* @param {StickerMetadata} metadata
*
* @returns {Promise&amp;lt;MessageMedia&gt;} media in webp format
*/
static async formatToWebpSticker(media, metadata) {
let webpMedia;
if (media.mimetype.includes(&#x27;image&#x27;))
webpMedia &#x3D; await this.formatImageToWebpSticker(media);
else if (media.mimetype.includes(&#x27;video&#x27;))
webpMedia &#x3D; await this.formatVideoToWebpSticker(media);
else
throw new Error(&#x27;Invalid media format&#x27;);
if (metadata.name || metadata.author) {
const img &#x3D; new webp.Image();
const hash &#x3D; this.generateHash(32);
const stickerPackId &#x3D; hash;
const packname &#x3D; metadata.name;
const author &#x3D; metadata.author;
const categories &#x3D; metadata.categories || [&#x27;&#x27;];
const json &#x3D; { &#x27;sticker-pack-id&#x27;: stickerPackId, &#x27;sticker-pack-name&#x27;: packname, &#x27;sticker-pack-publisher&#x27;: author, &#x27;emojis&#x27;: categories };
let exifAttr &#x3D; Buffer.from([0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00]);
let jsonBuffer &#x3D; Buffer.from(JSON.stringify(json), &#x27;utf8&#x27;);
let exif &#x3D; Buffer.concat([exifAttr, jsonBuffer]);
exif.writeUIntLE(jsonBuffer.length, 14, 4);
await img.load(Buffer.from(webpMedia.data, &#x27;base64&#x27;));
img.exif &#x3D; exif;
webpMedia.data &#x3D; (await img.save(null)).toString(&#x27;base64&#x27;);
}
return webpMedia;
}
/**
* Configure ffmpeg path
* @param {string} path
*/
static setFfmpegPath(path) {
ffmpeg.setFfmpegPath(path);
}
}
module.exports &#x3D; Util;</code></pre>
module.exports &#x3D; Util;
</code></pre>
</article>
</div>
</div>
@@ -73,7 +242,7 @@ module.exports &#x3D; Util;</code></pre>
<footer id="jsdoc-footer" class="jsdoc-footer">
<div id="jsdoc-footer-container">
<p>
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.6 on December 21, 2020.
Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc</a> 3.6.7 on February 19, 2022.
</p>
</div>
</footer>

View File

@@ -1,5 +1,5 @@
const fs = require('fs');
const { Client, Location } = require('./index');
const { Client, Location, List, Buttons } = require('./index');
const SESSION_FILE_PATH = './session.json';
let sessionCfg;
@@ -11,6 +11,13 @@ const client = new Client({ puppeteer: { headless: false }, session: sessionCfg
// You can use an existing session and avoid scanning a QR code by adding a "session" object to the client options.
// This object must include WABrowserId, WASecretBundle, WAToken1 and WAToken2.
// You also could connect to an existing instance of a browser
// {
// puppeteer: {
// browserWSEndpoint: `ws://localhost:3000`
// }
// }
client.initialize();
client.on('qr', (qr) => {
@@ -40,11 +47,11 @@ client.on('ready', () => {
client.on('message', async msg => {
console.log('MESSAGE RECEIVED', msg);
if (msg.body == '!ping reply') {
if (msg.body === '!ping reply') {
// Send a new message as a reply to the current one
msg.reply('pong');
} else if (msg.body == '!ping') {
} else if (msg.body === '!ping') {
// Send a new message to the same chat
client.sendMessage(msg.from, 'pong');
@@ -79,7 +86,7 @@ client.on('message', async msg => {
} else {
msg.reply('This command can only be used in a group!');
}
} else if (msg.body == '!leave') {
} else if (msg.body === '!leave') {
// Leave the group
let chat = await msg.getChat();
if (chat.isGroup) {
@@ -95,7 +102,7 @@ client.on('message', async msg => {
} catch (e) {
msg.reply('That invite code seems to be invalid.');
}
} else if (msg.body == '!groupinfo') {
} else if (msg.body === '!groupinfo') {
let chat = await msg.getChat();
if (chat.isGroup) {
msg.reply(`
@@ -109,10 +116,10 @@ client.on('message', async msg => {
} else {
msg.reply('This command can only be used in a group!');
}
} else if (msg.body == '!chats') {
} else if (msg.body === '!chats') {
const chats = await client.getChats();
client.sendMessage(msg.from, `The bot has ${chats.length} chats open.`);
} else if (msg.body == '!info') {
} else if (msg.body === '!info') {
let info = client.info;
client.sendMessage(msg.from, `
*Connection info*
@@ -121,7 +128,7 @@ client.on('message', async msg => {
Platform: ${info.platform}
WhatsApp version: ${info.phone.wa_version}
`);
} else if (msg.body == '!mediainfo' && msg.hasMedia) {
} else if (msg.body === '!mediainfo' && msg.hasMedia) {
const attachmentData = await msg.downloadMedia();
msg.reply(`
*Media info*
@@ -129,7 +136,7 @@ client.on('message', async msg => {
Filename: ${attachmentData.filename}
Data (length): ${attachmentData.data.length}
`);
} else if (msg.body == '!quoteinfo' && msg.hasQuotedMsg) {
} else if (msg.body === '!quoteinfo' && msg.hasQuotedMsg) {
const quotedMsg = await msg.getQuotedMessage();
quotedMsg.reply(`
@@ -139,13 +146,13 @@ client.on('message', async msg => {
Timestamp: ${quotedMsg.timestamp}
Has Media? ${quotedMsg.hasMedia}
`);
} else if (msg.body == '!resendmedia' && msg.hasQuotedMsg) {
} else if (msg.body === '!resendmedia' && msg.hasQuotedMsg) {
const quotedMsg = await msg.getQuotedMessage();
if (quotedMsg.hasMedia) {
const attachmentData = await quotedMsg.downloadMedia();
client.sendMessage(msg.from, attachmentData, { caption: 'Here\'s your requested media.' });
}
} else if (msg.body == '!location') {
} else if (msg.body === '!location') {
msg.reply(new Location(37.422, -122.084, 'Googleplex\nGoogle Headquarters'));
} else if (msg.location) {
msg.reply(msg.location);
@@ -153,18 +160,20 @@ client.on('message', async msg => {
const newStatus = msg.body.split(' ')[1];
await client.setStatus(newStatus);
msg.reply(`Status was updated to *${newStatus}*`);
} else if (msg.body == '!mention') {
} else if (msg.body === '!mention') {
const contact = await msg.getContact();
const chat = await msg.getChat();
chat.sendMessage(`Hi @${contact.number}!`, {
mentions: [contact]
});
} else if (msg.body == '!delete' && msg.hasQuotedMsg) {
const quotedMsg = await msg.getQuotedMessage();
if (quotedMsg.fromMe) {
quotedMsg.delete(true);
} else {
msg.reply('I can only delete my own messages');
} else if (msg.body === '!delete') {
if (msg.hasQuotedMsg) {
const quotedMsg = await msg.getQuotedMessage();
if (quotedMsg.fromMe) {
quotedMsg.delete(true);
} else {
msg.reply('I can only delete my own messages');
}
}
} else if (msg.body === '!pin') {
const chat = await msg.getChat();
@@ -181,15 +190,27 @@ client.on('message', async msg => {
} else if (msg.body === '!typing') {
const chat = await msg.getChat();
// simulates typing in the chat
chat.sendStateTyping();
chat.sendStateTyping();
} else if (msg.body === '!recording') {
const chat = await msg.getChat();
// simulates recording audio in the chat
chat.sendStateRecording();
chat.sendStateRecording();
} else if (msg.body === '!clearstate') {
const chat = await msg.getChat();
// stops typing or recording in the chat
chat.clearState();
chat.clearState();
} else if (msg.body === '!jumpto') {
if (msg.hasQuotedMsg) {
const quotedMsg = await msg.getQuotedMessage();
client.interface.openChatWindowAt(quotedMsg.id._serialized);
}
} else if (msg.body === '!buttons') {
let button = new Buttons('Button body',[{body:'bt1'},{body:'bt2'},{body:'bt3'}],'title','footer');
client.sendMessage(msg.from, button);
} else if (msg.body === '!list') {
let sections = [{title:'sectionTitle',rows:[{title:'ListItem1', description: 'desc'},{title:'ListItem2'}]}];
let list = new List('List body','btnText',sections,'Title','footer');
client.sendMessage(msg.from, list);
}
});
@@ -252,6 +273,10 @@ client.on('change_battery', (batteryInfo) => {
console.log(`Battery: ${battery}% - Charging? ${plugged}`);
});
client.on('change_state', state => {
console.log('CHANGE STATE', state );
});
client.on('disconnected', (reason) => {
console.log('Client was logged out', reason);
});

484
index.d.ts vendored
View File

@@ -1,6 +1,7 @@
import { EventEmitter } from 'events'
import puppeteer = require('puppeteer')
import { RequestInit } from 'node-fetch'
import puppeteer from 'puppeteer'
declare namespace WAWebJS {
@@ -10,8 +11,17 @@ declare namespace WAWebJS {
/** Current connection information */
public info: ClientInfo
/** Puppeteer page running WhatsApp Web */
pupPage?: puppeteer.Page
/** Puppeteer browser running WhatsApp Web */
pupBrowser?: puppeteer.Browser
/**Accepts an invitation to join a group */
acceptInvite(inviteCode: string): Promise<void>
acceptInvite(inviteCode: string): Promise<string>
/** Accepts a private invitation to join a group (v4 invite) */
acceptGroupV4Invite: (inviteV4: InviteV4Data) => Promise<{status: number}>
/**Returns an object with information about the invite code's group */
getInviteInfo(inviteCode: string): Promise<object>
@@ -38,6 +48,9 @@ declare namespace WAWebJS {
/** Logs out the client, closing the current session */
logout(): Promise<void>
/** Get all blocked contacts by host account */
getBlockedContacts(): Promise<Contact[]>
/** Get chat instance by ID */
getChatById(chatId: string): Promise<Chat>
@@ -49,6 +62,24 @@ declare namespace WAWebJS {
/** Get all current contact instances */
getContacts(): Promise<Contact[]>
/** Get the country code of a WhatsApp ID. (154185968@c.us) => (1) */
getCountryCode(number: string): Promise<string>
/** Get the formatted number of a WhatsApp ID. (12345678901@c.us) => (+1 (234) 5678-901) */
getFormattedNumber(number: string): Promise<string>
/** Get all current Labels */
getLabels(): Promise<Label[]>
/** Get Label instance by ID */
getLabelById(labelId: string): Promise<Label>
/** Get all Labels assigned to a Chat */
getChatLabels(chatId: string): Promise<Label[]>
/** Get all Chats for a specific Label */
getChatsByLabelId(labelId: string): Promise<Chat[]>
/** Returns the contact ID's profile picture URL, if privacy settings allow it */
getProfilePicUrl(contactId: string): Promise<string>
@@ -65,12 +96,15 @@ declare namespace WAWebJS {
/** Check if a given ID is registered in whatsapp */
isRegisteredUser(contactId: string): Promise<boolean>
/** Get the registered WhatsApp ID for a number. Returns null if the number is not registered on WhatsApp. */
getNumberId(number: string): Promise<ContactId | null>
/**
* Mutes the Chat until a specified date
* Mutes this chat forever, unless a date is specified
* @param chatId ID of the chat that will be muted
* @param unmuteDate Date when the chat will be unmuted
* @param unmuteDate Date when the chat will be unmuted, leave as is to mute forever
*/
muteChat(chatId: string, unmuteDate: Date): Promise<void>
muteChat(chatId: string, unmuteDate?: Date): Promise<void>
/** Force reset of connection state for the client */
resetState(): Promise<void>
@@ -78,12 +112,18 @@ declare namespace WAWebJS {
/** Send a message to a specific chatId */
sendMessage(chatId: string, content: MessageContent, options?: MessageSendOptions): Promise<Message>
/** Searches for messages */
searchMessages(query: string, options?: { chatId?: string, page?: number, limit?: number }): Promise<Message[]>
/** Marks the client as online */
sendPresenceAvailable(): Promise<void>
/** Mark as seen for the Chat */
sendSeen(chatId: string): Promise<boolean>
/** Mark the Chat as unread */
markChatUnread(chatId: string): Promise<void>
/**
* Sets the current user's status message
* @param status New status message
@@ -125,8 +165,8 @@ declare namespace WAWebJS {
/** Emitted when the client has been disconnected */
on(event: 'disconnected', listener: (
/** state that caused the disconnect */
reason: WAState
/** reason that caused the disconnect */
reason: WAState | "NAVIGATION"
) => void): this
/** Emitted when a user joins the chat via invite link or is added by an admin */
@@ -197,6 +237,12 @@ declare namespace WAWebJS {
qr: string
) => void): this
/** Emitted when a call is received */
on(event: 'call', listener: (
/** The call that started */
call: Call
) => void): this
/** Emitted when the client has initialized and is ready to receive messages */
on(event: 'ready', listener: () => void): this
}
@@ -241,13 +287,16 @@ declare namespace WAWebJS {
* @default 45000 */
authTimeoutMs?: number,
/** Puppeteer launch options. View docs here: https://github.com/puppeteer/puppeteer/ */
puppeteer?: puppeteer.LaunchOptions
puppeteer?: puppeteer.LaunchOptions & puppeteer.BrowserLaunchArgumentOptions & puppeteer.BrowserConnectOptions
/** Refresh interval for qr code (how much time to wait before checking if the qr code has changed)
* @default 20000 */
qrRefreshIntervalMs?: number
/** Timeout for qr code selector in puppeteer
* @default 45000 */
qrTimeoutMs?: number,
/** How many times should the qrcode be refreshed before giving up
* @default 0 (disabled) */
qrMaxRetries?: number,
/** Restart client with a new session (i.e. use null 'session' var) if authentication fails
* @default false */
restartOnAuthFail?: boolean
@@ -262,6 +311,9 @@ declare namespace WAWebJS {
/** User agent to use in puppeteer.
* @default 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36' */
userAgent?: string
/** Ffmpeg path to use when formating videos to webp while sending stickers
* @default 'ffmpeg' */
ffmpegPath?: string
}
/** Represents a Whatsapp client session */
@@ -316,7 +368,7 @@ declare namespace WAWebJS {
reply: (content: MessageContent, options?: MessageSendOptions) => Promise<Message>,
}
/** whatsapp web url */
export const WhatsWebURL: string
@@ -386,7 +438,30 @@ declare namespace WAWebJS {
CONTACT_CARD = 'vcard',
CONTACT_CARD_MULTI = 'multi_vcard',
REVOKED = 'revoked',
ORDER = 'order',
PRODUCT = 'product',
PAYMENT = 'payment',
UNKNOWN = 'unknown',
GROUP_INVITE = 'groups_v4_invite',
LIST = 'list',
LIST_RESPONSE = 'list_response',
BUTTONS_RESPONSE = 'buttons_response',
BROADCAST_NOTIFICATION = 'broadcast_notification',
CALL_LOG = 'call_log',
CIPHERTEXT = 'ciphertext',
DEBUG = 'debug',
E2E_NOTIFICATION = 'e2e_notification',
GP2 = 'gp2',
GROUP_NOTIFICATION = 'group_notification',
HSM = 'hsm',
INTERACTIVE = 'interactive',
NATIVE_FLOW = 'native_flow',
NOTIFICATION = 'notification',
NOTIFICATION_TEMPLATE = 'notification_template',
OVERSIZED = 'oversized',
PROTOCOL = 'protocol',
REACTION = 'reaction',
TEMPLATE_BUTTON_REPLY = 'template_button_reply',
}
/** Client status */
@@ -412,6 +487,24 @@ declare namespace WAWebJS {
UNPAIRED_IDLE = 'UNPAIRED_IDLE',
}
export type MessageInfo = {
delivery: Array<{id: ContactId, t: number}>,
deliveryRemaining: number,
played: Array<{id: ContactId, t: number}>,
playedRemaining: number,
read: Array<{id: ContactId, t: number}>,
readRemaining: number
}
export type InviteV4Data = {
inviteCode: string,
inviteCodeExp: number,
groupId: string,
groupName?: string,
fromId: string,
toId: string
}
/**
* Represents a Message on WhatsApp
*
@@ -451,6 +544,10 @@ declare namespace WAWebJS {
broadcast: boolean,
/** Indicates if the message was a status update */
isStatus: boolean,
/** Indicates if the message is a Gif */
isGif: boolean,
/** Indicates if the message will disappear after it expires */
isEphemeral: boolean,
/** ID for the Chat that this message was sent to, except if the message was sent by the current user */
from: string,
/** Indicates if the message was sent by the current user */
@@ -463,10 +560,19 @@ declare namespace WAWebJS {
id: MessageId,
/** Indicates if the message was forwarded */
isForwarded: boolean,
/**
* Indicates how many times the message was forwarded.
* The maximum value is 127.
*/
forwardingScore: number,
/** Indicates if the message was starred */
isStarred: boolean,
/** Location information contained in the message, if the message is type "location" */
location: Location,
/** List of vCards contained in the message */
vCards: string[],
/** Invite v4 info */
inviteV4?: InviteV4Data,
/** MediaKey that represents the sticker 'ID' */
mediaKey?: string,
/** Indicates the mentions in the message body. */
@@ -481,7 +587,29 @@ declare namespace WAWebJS {
to: string,
/** Message type */
type: MessageTypes,
/** Links included in the message. */
links: Array<{
link: string,
isSuspicious: boolean
}>,
/** Order ID */
orderId: string,
/** title */
title?: string,
/** description*/
description?: string,
/** Business Owner JID */
businessOwnerJid?: string,
/** Product JID */
productId?: string,
/** Message buttons */
dynamicReplyButtons?: object,
/** Selected button ID */
selectedButtonId?: string,
/** Selected list row ID */
selectedRowId?: string,
/** Accept the Group V4 Invite in message */
acceptGroupV4Invite: () => Promise<{status: number}>,
/** Deletes the message from the chat */
delete: (everyone?: boolean) => Promise<void>,
/** Downloads and returns the attatched message media */
@@ -504,6 +632,20 @@ declare namespace WAWebJS {
* Forwards this message to another chat
*/
forward: (chat: Chat | string) => Promise<void>,
/** Star this message */
star: () => Promise<void>,
/** Unstar this message */
unstar: () => Promise<void>,
/** Get information about message delivery statuso */
getInfo: () => Promise<MessageInfo | null>,
/**
* Gets the order associated with a given message
*/
getOrder: () => Order,
/**
* Gets the payment details associated with a given message
*/
getPayment: () => Payment,
}
/** ID that represents a message */
@@ -514,10 +656,25 @@ declare namespace WAWebJS {
_serialized: string,
}
export interface Location {
description?: string | null,
latitude: string,
longitude: string,
/** Location information */
export class Location {
description?: string | null
latitude: string
longitude: string
constructor(latitude: number, longitude: number, description?: string)
}
export interface Label {
/** Label name */
name: string,
/** Label ID */
id: string,
/** Color assigned to the label */
hexColor: string,
/** Get all chats that have been assigned this Label */
getChats: () => Promise<Chat[]>
}
/** Options for sending a message */
@@ -526,6 +683,12 @@ declare namespace WAWebJS {
linkPreview?: boolean
/** Send audio as voice message */
sendAudioAsVoice?: boolean
/** Send video as gif */
sendVideoAsGif?: boolean
/** Send media as sticker */
sendMediaAsSticker?: boolean
/** Send media as document */
sendMediaAsDocument?: boolean
/** Automatically parse vCards and send them as contacts */
parseVCards?: boolean
/** Image or videos caption */
@@ -538,6 +701,21 @@ declare namespace WAWebJS {
sendSeen?: boolean
/** Media to be sent */
media?: MessageMedia
/** Extra options */
extra?: any
/** Sticker name, if sendMediaAsSticker is true */
stickerName?: string
/** Sticker author, if sendMediaAsSticker is true */
stickerAuthor?: string
/** Sticker categories, if sendMediaAsSticker is true */
stickerCategories?: string[]
}
export interface MediaFromURLOptions {
client?: Client
filename?: string
unsafeMime?: boolean
reqOptions?: RequestInit
}
/** Media attached to a message */
@@ -558,9 +736,12 @@ declare namespace WAWebJS {
/** Creates a MessageMedia instance from a local file path */
static fromFilePath: (filePath: string) => MessageMedia
/** Creates a MessageMedia instance from a URL */
static fromUrl: (url: string, options?: MediaFromURLOptions) => Promise<MessageMedia>
}
export type MessageContent = string | MessageMedia | Location | Contact | Contact[]
export type MessageContent = string | MessageMedia | Location | Contact | Contact[] | List | Buttons
/**
* Represents a Contact on WhatsApp
@@ -638,11 +819,22 @@ declare namespace WAWebJS {
* Will return null when getting chat for currently logged in user.
*/
getChat: () => Promise<Chat>,
/** Returns the contact's countrycode, (1541859685@c.us) => (1) */
getCountryCode(): Promise<string>,
/** Returns the contact's formatted phone number, (12345678901@c.us) => (+1 (234) 5678-901) */
getFormattedNumber(): Promise<string>,
/** Blocks this contact from WhatsApp */
block: () => Promise<boolean>,
/** Unlocks this contact from WhatsApp */
unblock: () => Promise<boolean>,
/** Gets the Contact's current "about" info. Returns null if you don't have permission to read their status. */
getAbout: () => Promise<string | null>,
}
export interface ContactId {
@@ -715,8 +907,8 @@ declare namespace WAWebJS {
delete: () => Promise<boolean>,
/** Loads chat messages, sorted from earliest to latest. */
fetchMessages: (searchOptions: MessageSearchOptions) => Promise<Message[]>,
/** Mutes this chat until a specified date */
mute: (unmuteDate: Date) => Promise<void>,
/** Mutes this chat forever, unless a date is specified */
mute: (unmuteDate?: Date) => Promise<void>,
/** Send a message to this chat */
sendMessage: (content: MessageContent, options?: MessageSendOptions) => Promise<Message>,
/** Set the message as seen */
@@ -731,14 +923,17 @@ declare namespace WAWebJS {
unmute: () => Promise<void>,
/** Returns the Contact that corresponds to this Chat. */
getContact: () => Promise<Contact>,
/** Marks this Chat as unread */
markUnread: () => Promise<void>
/** Returns array of all Labels assigned to this Chat */
getLabels: () => Promise<Label[]>
}
export interface MessageSearchOptions {
/**
* The amount of messages to return.
* The amount of messages to return. If no limit is specified, the available messages will be returned.
* Note that the actual number of returned messages may be smaller if there aren't enough messages in the conversation.
* Set this to Infinity to load all messages.
* @default 50
*/
limit?: number
}
@@ -774,6 +969,255 @@ declare namespace WAWebJS {
export interface PrivateChat extends Chat {
}
export type GroupParticipant = {
id: ContactId,
isAdmin: boolean
isSuperAdmin: boolean
}
/** Promotes or demotes participants by IDs to regular users or admins */
export type ChangeParticipantsPermisions =
(participantIds: Array<string>) => Promise<{ status: number }>
/** Adds or removes a list of participants by ID to the group */
export type ChangeGroupParticipants =
(participantIds: Array<string>) => Promise<{
status: number;
participants: Array<{
[key: string]: {
code: number
}
}>
} & {
[key: string]: number;
}>
export interface GroupChat extends Chat {
/** Group owner */
owner: ContactId;
/** Date at which the group was created */
createdAt: Date;
/** Group description */
description: string;
/** Group participants */
participants: Array<GroupParticipant>;
/** Adds a list of participants by ID to the group */
addParticipants: ChangeGroupParticipants;
/** Removes a list of participants by ID to the group */
removeParticipants: ChangeGroupParticipants;
/** Promotes participants by IDs to admins */
promoteParticipants: ChangeParticipantsPermisions;
/** Demotes participants by IDs to regular users */
demoteParticipants: ChangeParticipantsPermisions;
/** Updates the group subject */
setSubject: (subject: string) => Promise<void>;
/** Updates the group description */
setDescription: (description: string) => Promise<void>;
/** Updates the group settings to only allow admins to send messages
* @param {boolean} [adminsOnly=true] Enable or disable this option
* @returns {Promise<boolean>} Returns true if the setting was properly updated. This can return false if the user does not have the necessary permissions.
*/
setMessagesAdminsOnly: (adminsOnly?: boolean) => Promise<boolean>;
/**
* Updates the group settings to only allow admins to edit group info (title, description, photo).
* @param {boolean} [adminsOnly=true] Enable or disable this option
* @returns {Promise<boolean>} Returns true if the setting was properly updated. This can return false if the user does not have the necessary permissions.
*/
setInfoAdminsOnly: (adminsOnly?: boolean) => Promise<boolean>;
/** Gets the invite code for a specific group */
getInviteCode: () => Promise<string>;
/** Invalidates the current group invite code and generates a new one */
revokeInvite: () => Promise<void>;
/** Makes the bot leave the group */
leave: () => Promise<void>;
}
/**
* Represents the metadata associated with a given product
*
*/
export interface ProductMetadata {
/** Product Id */
id: string,
/** Product Name */
name: string,
/** Product Description */
description: string,
/** Retailer ID */
retailer_id?: string
}
/**
* Represents a Product on Whatsapp
* @example
* {
* "id": "123456789",
* "price": "150000",
* "thumbnailId": "123456789",
* "thumbnailUrl": "https://mmg.whatsapp.net",
* "currency": "GTQ",
* "name": "Store Name",
* "quantity": 1
* }
*/
export interface Product {
/** Product Id */
id: string,
/** Price */
price?: string,
/** Product Thumbnail*/
thumbnailUrl: string,
/** Currency */
currency: string,
/** Product Name */
name: string,
/** Product Quantity*/
quantity: number,
/** Gets the Product metadata */
getData: () => Promise<ProductMetadata>
}
/**
* Represents a Order on WhatsApp
*
* @example
* {
* "products": [
* {
* "id": "123456789",
* "price": "150000",
* "thumbnailId": "123456789",
* "thumbnailUrl": "https://mmg.whatsapp.net",
* "currency": "GTQ",
* "name": "Store Name",
* "quantity": 1
* }
* ],
* "subtotal": "150000",
* "total": "150000",
* "currency": "GTQ",
* "createdAt": 1610136796,
* "sellerJid": "55555555@s.whatsapp.net"
* }
*/
export interface Order {
/** List of products*/
products: Array<Product>,
/** Order Subtotal */
subtotal: string,
/** Order Total */
total: string,
/** Order Currency */
currency: string,
/** Order Created At*/
createdAt: number;
}
/**
* Represents a Payment on WhatsApp
*
* @example
* {
* id: {
* fromMe: true,
* remote: {
* server: 'c.us',
* user: '5511999999999',
* _serialized: '5511999999999@c.us'
* },
* id: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
* _serialized: 'true_5511999999999@c.us_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
* },
* paymentCurrency: 'BRL',
* paymentAmount1000: 1000,
* paymentMessageReceiverJid: {
* server: 'c.us',
* user: '5511999999999',
* _serialized: '5511999999999@c.us'
* },
* paymentTransactionTimestamp: 1623463058,
* paymentStatus: 4,
* paymentTxnStatus: 4,
* paymentNote: 'note'
* }
*/
export interface Payment {
/** Payment Id*/
id: object,
/** Payment currency */
paymentCurrency: string,
/** Payment ammount */
paymentAmount1000 : number,
/** Payment receiver */
paymentMessageReceiverJid : object,
/** Payment transaction timestamp */
paymentTransactionTimestamp : number,
/** Payment paymentStatus */
paymentStatus : number,
/** Integer that represents the payment Text */
paymentTxnStatus : number,
/** The note sent with the payment */
paymentNote : string;
}
/**
* Represents a Call on WhatsApp
*
* @example
* Call {
* id: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
* from: '5511999999@c.us',
* timestamp: 1625003709,
* isVideo: false,
* isGroup: false,
* fromMe: false,
* canHandleLocally: false,
* webClientShouldHandle: false,
* participants: []
* }
*/
export interface Call {
/** Call Id */
id: string,
/** from */
from?: string,
/** Unix timestamp for when the call was created*/
timestamp: number,
/** Is video */
isVideo: boolean,
/** Is Group */
isGroup: boolean,
/** Indicates if the call was sent by the current user */
fromMe: boolean,
/** indicates if the call can be handled in waweb */
canHandleLocally: boolean,
/** indicates if the call should be handled in waweb */
webClientShouldHandle: boolean,
/** Object with participants */
participants: object
}
/** Message type List */
export class List {
body: string
buttonText: string
sections: Array<any>
title?: string | null
footer?: string | null
constructor(body: string, buttonText: string, sections: Array<any>, title?: string | null, footer?: string | null)
}
/** Message type buttons */
export class Buttons {
body: string | MessageMedia
buttons: Array<{ buttonId: string; buttonText: {displayText: string}; type: number }>
title?: string | null
footer?: string | null
constructor(body: string, buttons: Array<{ id?: string; body: string }>, title?: string | null, footer?: string | null)
}
}
export = WAWebJS

View File

@@ -18,6 +18,8 @@ module.exports = {
BusinessContact: require('./src/structures/BusinessContact'),
ClientInfo: require('./src/structures/ClientInfo'),
Location: require('./src/structures/Location'),
ProductMetadata: require('./src/structures/ProductMetadata'),
List: require('./src/structures/List'),
Buttons: require('./src/structures/Buttons'),
...Constants
};

View File

@@ -1,11 +1,12 @@
{
"name": "whatsapp-web.js",
"version": "1.11.2",
"version": "1.15.7",
"description": "Library for interacting with the WhatsApp Web API ",
"main": "./index.js",
"typings": "./index.d.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"test": "mocha tests --recursive",
"test-single": "mocha",
"shell": "node --experimental-repl-await ./shell.js",
"generate-docs": "node_modules/.bin/jsdoc --configure .jsdoc.json --verbose"
},
@@ -26,16 +27,29 @@
"bugs": {
"url": "https://github.com/pedroslopez/whatsapp-web.js/issues"
},
"homepage": "https://github.com/pedroslopez/whatsapp-web.js#readme",
"homepage": "https://wwebjs.dev/",
"dependencies": {
"@pedroslopez/moduleraid": "^4.1.0",
"@pedroslopez/moduleraid": "^5.0.2",
"fluent-ffmpeg": "^2.1.2",
"jsqr": "^1.3.1",
"mime": "^2.4.5",
"puppeteer": "^5.2.1"
"mime": "^3.0.0",
"node-fetch": "^2.6.5",
"node-webpmux": "^3.1.0",
"puppeteer": "^13.0.0",
"sharp": "^0.28.3"
},
"devDependencies": {
"eslint": "^6.8.0",
"@types/node-fetch": "^2.5.12",
"chai": "^4.3.4",
"dotenv": "^16.0.0",
"eslint": "^8.4.1",
"eslint-plugin-mocha": "^10.0.3",
"jsdoc": "^3.6.4",
"jsdoc-baseline": "^0.1.5"
"jsdoc-baseline": "^0.1.5",
"mocha": "^9.0.2",
"sinon": "^13.0.1"
},
"engines": {
"node": ">=12.0.0"
}
}

View File

@@ -11,7 +11,7 @@ const { WhatsWebURL, DefaultOptions, Events, WAState } = require('./util/Constan
const { ExposeStore, LoadUtils } = require('./util/Injected');
const ChatFactory = require('./factories/ChatFactory');
const ContactFactory = require('./factories/ContactFactory');
const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification } = require('./structures');
const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification , Label, Call, Buttons, List} = require('./structures');
/**
* Starting point for interacting with the WhatsApp Web API
* @extends {EventEmitter}
@@ -20,6 +20,7 @@ const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification
* @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
@@ -29,6 +30,8 @@ const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification
* @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
* @param {string} options.ffmpegPath - Ffmpeg path to use when formating videos to webp while sending stickers
* @param {boolean} options.bypassCSP - Sets bypassing of page's Content-Security-Policy.
*
* @fires Client#qr
* @fires Client#authenticated
@@ -55,39 +58,61 @@ class Client extends EventEmitter {
this.pupBrowser = null;
this.pupPage = null;
Util.setFfmpegPath(this.options.ffmpegPath);
}
/**
* Sets up events and requirements, kicks off authentication request
*/
async initialize() {
const browser = await puppeteer.launch(this.options.puppeteer);
const page = (await browser.pages())[0];
page.setUserAgent(this.options.userAgent);
let [browser, page] = [null, null];
if(this.options.puppeteer && this.options.puppeteer.browserWSEndpoint) {
browser = await puppeteer.connect(this.options.puppeteer);
page = await browser.newPage();
} else {
browser = await puppeteer.launch(this.options.puppeteer);
page = (await browser.pages())[0];
}
await page.setUserAgent(this.options.userAgent);
this.pupBrowser = browser;
this.pupPage = page;
// remember me
await page.evaluateOnNewDocument(() => {
localStorage.setItem('remember-me', 'true');
});
if (this.options.session) {
await page.evaluateOnNewDocument(
session => {
localStorage.clear();
localStorage.setItem('WABrowserId', session.WABrowserId);
localStorage.setItem('WASecretBundle', session.WASecretBundle);
localStorage.setItem('WAToken1', session.WAToken1);
localStorage.setItem('WAToken2', session.WAToken2);
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 page.goto(WhatsWebURL, {
waitUntil: 'load',
timeout: 0,
referer: 'https://whatsapp.com/'
});
const KEEP_PHONE_CONNECTED_IMG_SELECTOR = '[data-asset-intro-image-light="true"], [data-asset-intro-image-dark="true"]';
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"]';
if (this.options.session) {
// Check if session restore was successfull
// Check if session restore was successful
try {
await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: this.options.authTimeoutMs });
} catch (err) {
@@ -111,39 +136,61 @@ class Client extends EventEmitter {
}
} else {
let qrRetries = 0;
const getQrCode = async () => {
// Check if retry button is present
var QR_RETRY_SELECTOR = 'div[data-ref] > span > div';
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;
/**
* Emitted when the 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();
}
}
};
getQrCode();
this._qrRefreshInterval = setInterval(getQrCode, this.options.qrRefreshIntervalMs);
// Wait for code scan
await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: 0 });
clearInterval(this._qrRefreshInterval);
this._qrRefreshInterval = undefined;
try {
await page.waitForSelector(KEEP_PHONE_CONNECTED_IMG_SELECTOR, { timeout: 0 });
clearInterval(this._qrRefreshInterval);
this._qrRefreshInterval = undefined;
} catch(error) {
if (
error.name === 'ProtocolError' &&
error.message &&
error.message.match(/Target closed/)
) {
// something has called .destroy() while waiting
return;
}
throw error;
}
}
await page.evaluate(ExposeStore, moduleRaid.toString());
// Get session tokens
const localStorage = JSON.parse(await page.evaluate(() => {
return JSON.stringify(window.localStorage);
@@ -170,6 +217,14 @@ class Client extends EventEmitter {
// Check window.Store Injection
await page.waitForFunction('window.Store != undefined');
const isMD = await page.evaluate(() => {
return window.Store.Features.features.MD_BACKEND;
});
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);
@@ -187,8 +242,6 @@ class Client extends EventEmitter {
// Register events
await page.exposeFunction('onAddMessageEvent', msg => {
if (!msg.isNewMsg) return;
if (msg.type === 'gp2') {
const notification = new GroupNotification(this, msg);
if (msg.subtype === 'add' || msg.subtype === 'invite') {
@@ -332,7 +385,7 @@ class Client extends EventEmitter {
/**
* Emitted when the client has been disconnected
* @event Client#disconnected
* @param {WAState} reason state that caused the disconnect
* @param {WAState|"NAVIGATION"} reason reason that caused the disconnect
*/
this.emit(Events.DISCONNECTED, state);
this.destroy();
@@ -354,8 +407,25 @@ class Client extends EventEmitter {
this.emit(Events.BATTERY_CHANGED, { battery, plugged });
});
await page.exposeFunction('onIncomingCall', (call) => {
/**
* Emitted when a call is received
* @event Client#incoming_call
* @param {object} call
* @param {number} call.id - Call id
* @param {string} call.peerJid - Who called
* @param {boolean} call.isVideo - if is video
* @param {boolean} call.isGroup - if is group
* @param {boolean} call.canHandleLocally - if we can handle in waweb
* @param {boolean} call.outgoing - if is outgoing
* @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);
});
await page.evaluate(() => {
window.Store.Msg.on('add', (msg) => { if (msg.isNewMsg) window.onAddMessageEvent(window.WWebJS.getMessageModel(msg)); });
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); });
@@ -363,6 +433,17 @@ class Client extends EventEmitter {
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); });
window.Store.Conn.on('change:battery', (state) => { window.onBatteryStateChangedEvent(state); });
window.Store.Call.on('add', (call) => { window.onIncomingCall(call); });
window.Store.Msg.on('add', (msg) => {
if (msg.isNewMsg) {
if(msg.type === 'ciphertext') {
// defer message event until ciphertext is resolved (type changed)
msg.once('change:type', (_msg) => window.onAddMessageEvent(window.WWebJS.getMessageModel(_msg)));
} else {
window.onAddMessageEvent(window.WWebJS.getMessageModel(msg));
}
}
});
});
/**
@@ -370,6 +451,15 @@ class Client extends EventEmitter {
* @event Client#ready
*/
this.emit(Events.READY);
// Disconnect when navigating away when in PAIRING state (detect logout)
this.pupPage.on('framenavigated', async () => {
const appState = await this.getState();
if(!appState || appState === WAState.PAIRING) {
this.emit(Events.DISCONNECTED, 'NAVIGATION');
await this.destroy();
}
});
}
/**
@@ -420,18 +510,24 @@ class Client extends EventEmitter {
* @typedef {Object} MessageSendOptions
* @property {boolean} [linkPreview=true] - Show links preview
* @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
* @property {boolean} [sendMediaAsDocument=false] - Send media as a document
* @property {boolean} [parseVCards=true] - Automatically parse vCards and send them as contacts
* @property {string} [caption] - Image or video caption
* @property {string} [quotedMessageId] - Id of the message that is being quoted (or replied to)
* @property {Contact[]} [mentions] - Contacts that are being mentioned in the message
* @property {boolean} [sendSeen=true] - Mark the conversation as seen after sending the message
* @property {boolean} [media] - Media to be sent
* @property {string} [stickerAuthor=undefined] - Sets the author of the sticker, (if sendMediaAsSticker is true).
* @property {string} [stickerName=undefined] - Sets the name of the sticker, (if sendMediaAsSticker is true).
* @property {string[]} [stickerCategories=undefined] - Sets the categories of the sticker, (if sendMediaAsSticker is true). Provide emoji char array, can be null.
* @property {MessageMedia} [media] - Media to be sent
*/
/**
* Send a message to a specific chatId
* @param {string} chatId
* @param {string|MessageMedia|Location|Contact|Array<Contact>} content
* @param {string|MessageMedia|Location|Contact|Array<Contact>|Buttons|List} content
* @param {MessageSendOptions} [options] - Options used when sending the message
*
* @returns {Promise<Message>} Message that was just sent
@@ -440,10 +536,14 @@ class Client extends EventEmitter {
let internalOptions = {
linkPreview: options.linkPreview === false ? undefined : true,
sendAudioAsVoice: options.sendAudioAsVoice,
sendVideoAsGif: options.sendVideoAsGif,
sendMediaAsSticker: options.sendMediaAsSticker,
sendMediaAsDocument: options.sendMediaAsDocument,
caption: options.caption,
quotedMessageId: options.quotedMessageId,
parseVCards: options.parseVCards === false ? false : true,
mentionedJidList: Array.isArray(options.mentions) ? options.mentions.map(contact => contact.id._serialized) : []
mentionedJidList: Array.isArray(options.mentions) ? options.mentions.map(contact => contact.id._serialized) : [],
extraOptions: options.extra
};
const sendSeen = typeof options.sendSeen === 'undefined' ? true : options.sendSeen;
@@ -464,6 +564,22 @@ class Client extends EventEmitter {
} 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;}
internalOptions.buttons = content;
content = '';
} else if(content instanceof List){
internalOptions.list = content;
content = '';
}
if (internalOptions.sendMediaAsSticker && internalOptions.attachment) {
internalOptions.attachment =
await Util.formatToWebpSticker(internalOptions.attachment, {
name: options.stickerName,
author: options.stickerAuthor,
categories: options.stickerCategories
});
}
const newMessage = await this.pupPage.evaluate(async (chatId, message, options, sendSeen) => {
@@ -481,6 +597,24 @@ class Client extends EventEmitter {
return new Message(this, newMessage);
}
/**
* Searches for messages
* @param {string} query
* @param {Object} [options]
* @param {number} [options.page]
* @param {number} [options.limit]
* @param {string} [options.chatId]
* @returns {Promise<Message[]>}
*/
async searchMessages(query, options = {}) {
const messages = await this.pupPage.evaluate(async (query, page, count, remote) => {
const { messages } = await window.Store.Msg.search(query, page, count, remote);
return messages.map(msg => window.WWebJS.getMessageModel(msg));
}, query, options.page, options.limit, options.chatId);
return messages.map(msg => new Message(this, msg));
}
/**
* Get all current chat instances
* @returns {Promise<Array<Chat>>}
@@ -545,6 +679,7 @@ class Client extends EventEmitter {
/**
* Accepts an invitation to join a group
* @param {string} inviteCode Invitation code
* @returns {Promise<string>} Id of the joined Chat
*/
async acceptInvite(inviteCode) {
const chatId = await this.pupPage.evaluate(async inviteCode => {
@@ -554,6 +689,20 @@ class Client extends EventEmitter {
return chatId._serialized;
}
/**
* Accepts a private invitation to join a group
* @param {object} inviteV4 Invite V4 Info
* @returns {Promise<Object>}
*/
async acceptGroupV4Invite(inviteInfo) {
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);
}, inviteInfo);
}
/**
* Sets the current user's status message
* @param {string} status New status message
@@ -581,6 +730,7 @@ class Client extends EventEmitter {
*/
async getState() {
return await this.pupPage.evaluate(() => {
if(!window.Store) return null;
return window.Store.AppState.state;
});
}
@@ -602,7 +752,7 @@ class Client extends EventEmitter {
return await this.pupPage.evaluate(async chatId => {
let chat = await window.Store.Chat.get(chatId);
await window.Store.Cmd.archiveChat(chat, true);
return chat.archive;
return true;
}, chatId);
}
@@ -614,7 +764,7 @@ class Client extends EventEmitter {
return await this.pupPage.evaluate(async chatId => {
let chat = await window.Store.Chat.get(chatId);
await window.Store.Cmd.archiveChat(chat, false);
return chat.archive;
return false;
}, chatId);
}
@@ -656,15 +806,16 @@ class Client extends EventEmitter {
}
/**
* Mutes the Chat until a specified date
* Mutes this chat forever, unless a date is specified
* @param {string} chatId ID of the chat that will be muted
* @param {Date} unmuteDate Date when the chat will be unmuted
* @param {?Date} unmuteDate Date when the chat will be unmuted, leave as is to mute forever
*/
async muteChat(chatId, unmuteDate) {
unmuteDate = unmuteDate ? unmuteDate.getTime() / 1000 : -1;
await this.pupPage.evaluate(async (chatId, timestamp) => {
let chat = await window.Store.Chat.get(chatId);
await chat.mute.mute(timestamp, !0);
}, chatId, unmuteDate.getTime() / 1000);
}, chatId, unmuteDate || -1);
}
/**
@@ -678,6 +829,17 @@ class Client extends EventEmitter {
}, chatId);
}
/**
* Mark the Chat as unread
* @param {string} chatId ID of the chat that will be marked as unread
*/
async markChatUnread(chatId) {
await this.pupPage.evaluate(async chatId => {
let chat = await window.Store.Chat.get(chatId);
await window.Store.Cmd.markChatUnread(chat, true);
}, chatId);
}
/**
* Returns the contact ID's profile picture URL, if privacy settings allow it
* @param {string} contactId the whatsapp user's ID
@@ -712,6 +874,50 @@ class Client extends EventEmitter {
}, id);
}
/**
* Get the registered WhatsApp ID for a number.
* Will return null if the number is not registered on WhatsApp.
* @param {string} number Number or ID ("@c.us" will be automatically appended if not specified)
* @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;
}
}
/**
* Get the formatted number of a WhatsApp ID.
* @param {string} number Number or ID
* @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`;
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
* @returns {Promise<string>}
*/
async getCountryCode(number) {
number = number.replace(' ', '').replace('+', '').replace('@c.us', '');
return await this.pupPage.evaluate(async numberId => {
return window.Store.NumberInfo.findCC(numberId);
}, number);
}
/**
* Create a new group
* @param {string} name group title
@@ -749,6 +955,76 @@ class Client extends EventEmitter {
return { gid: createRes.gid, missingParticipants };
}
/**
* Get all current Labels
* @returns {Promise<Array<Label>>}
*/
async getLabels() {
const labels = await this.pupPage.evaluate(async () => {
return window.WWebJS.getLabels();
});
return labels.map(data => new Label(this , data));
}
/**
* Get Label instance by ID
* @param {string} labelId
* @returns {Promise<Label>}
*/
async getLabelById(labelId) {
const label = await this.pupPage.evaluate(async (labelId) => {
return window.WWebJS.getLabel(labelId);
}, labelId);
return new Label(this, label);
}
/**
* Get all Labels assigned to a chat
* @param {string} chatId
* @returns {Promise<Array<Label>>}
*/
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));
}
/**
* Get all Chats for a specific Label
* @param {string} labelId
* @returns {Promise<Array<Chat>>}
*/
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'){
result.push(item.parentId);
}
return result;
},[]);
}, labelId);
return Promise.all(chatIds.map(id => this.getChatById(id)));
}
/**
* Gets all blocked contacts by host account
* @returns {Promise<Array<Contact>>}
*/
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 blockedContacts.map(contact => ContactFactory.create(this.client, contact));
}
}
module.exports = Client;

82
src/structures/Buttons.js Normal file
View File

@@ -0,0 +1,82 @@
'use strict';
const MessageMedia = require('./MessageMedia');
const Util = require('../util/Util');
/**
* Button spec used in Buttons constructor
* @typedef {Object} ButtonSpec
* @property {string=} id - Custom ID to set on the button. A random one will be generated if one is not passed.
* @property {string} body - The text to show on the button.
*/
/**
* @typedef {Object} FormattedButtonSpec
* @property {string} buttonId
* @property {number} type
* @property {Object} buttonText
*/
/**
* Message type buttons
*/
class Buttons {
/**
* @param {string|MessageMedia} body
* @param {ButtonSpec[]} buttons - See {@link ButtonSpec}
* @param {string?} title
* @param {string?} footer
*/
constructor(body, buttons, title, footer) {
/**
* Message body
* @type {string|MessageMedia}
*/
this.body = body;
/**
* title of message
* @type {string}
*/
this.title = title;
/**
* footer of message
* @type {string}
*/
this.footer = footer;
if (body instanceof MessageMedia) {
this.type = 'media';
this.title = '';
}else{
this.type = 'chat';
}
/**
* buttons of message
* @type {FormattedButtonSpec[]}
*/
this.buttons = this._format(buttons);
if(!this.buttons.length){ throw '[BT01] No buttons';}
}
/**
* Creates button array from simple array
* @param {ButtonSpec[]} buttons
* @returns {FormattedButtonSpec[]}
* @example
* Input: [{id:'customId',body:'button1'},{body:'button2'},{body:'button3'},{body:'button4'}]
* Returns: [{ buttonId:'customId',buttonText:{'displayText':'button1'},type: 1 },{buttonId:'n3XKsL',buttonText:{'displayText':'button2'},type:1},{buttonId:'NDJk0a',buttonText:{'displayText':'button3'},type:1}]
*/
_format(buttons){
buttons = buttons.slice(0,3); // phone users can only see 3 buttons, so lets limit this
return buttons.map((btn) => {
return {'buttonId':btn.id ? String(btn.id) : Util.generateHash(6),'buttonText':{'displayText':btn.body},'type':1};
});
}
}
module.exports = Buttons;

68
src/structures/Call.js Normal file
View File

@@ -0,0 +1,68 @@
'use strict';
const Base = require('./Base');
/**
* Represents a Call on WhatsApp
* @extends {Base}
*/
class Call extends Base {
constructor(client, data) {
super(client);
if (data) this._patch(data);
}
_patch(data) {
/**
* Call ID
* @type {string}
*/
this.id = data.id;
/**
* From
* @type {string}
*/
this.from = data.peerJid;
/**
* Unix timestamp for when the call was created
* @type {number}
*/
this.timestamp = data.offerTime;
/**
* Is video
* @type {boolean}
*/
this.isVideo = data.isVideo;
/**
* Is Group
* @type {boolean}
*/
this.isGroup = data.isGroup;
/**
* Indicates if the call was sent by the current user
* @type {boolean}
*/
this.fromMe = data.outgoing;
/**
* Indicates if the call can be handled in waweb
* @type {boolean}
*/
this.canHandleLocally = data.canHandleLocally;
/**
* Indicates if the call Should be handled in waweb
* @type {boolean}
*/
this.webClientShouldHandle = data.webClientShouldHandle;
/**
* Object with participants
* @type {object}
*/
this.participants = data.participants;
return super._patch(data);
}
}
module.exports = Call;

View File

@@ -65,7 +65,7 @@ class Chat extends Base {
/**
* Indicates if the chat is muted or not
* @type {number}
* @type {boolean}
*/
this.isMuted = data.isMuted;
@@ -147,8 +147,8 @@ class Chat extends Base {
}
/**
* Mutes this chat until a specified date
* @param {Date} unmuteDate Date at which the Chat will be unmuted
* Mutes this chat forever, unless a date is specified
* @param {?Date} unmuteDate Date at which the Chat will be unmuted, leave as is to mute forever
*/
async mute(unmuteDate) {
return this.client.muteChat(this.id._serialized, unmuteDate);
@@ -161,33 +161,42 @@ class Chat extends Base {
return this.client.unmuteChat(this.id._serialized);
}
/**
* Mark this chat as unread
*/
async markUnread(){
return this.client.markChatUnread(this.id._serialized);
}
/**
* Loads chat messages, sorted from earliest to latest.
* @param {Object} searchOptions Options for searching messages. Right now only limit is supported.
* @param {Number} [searchOptions.limit=50] The amount of messages to return. Note that the actual number of returned messages may be smaller if there aren't enough messages in the conversation. Set this to Infinity to load all messages.
* @param {Number} [searchOptions.limit] The amount of messages to return. If no limit is specified, the available messages will be returned. Note that the actual number of returned messages may be smaller if there aren't enough messages in the conversation. Set this to Infinity to load all messages.
* @returns {Promise<Array<Message>>}
*/
async fetchMessages(searchOptions) {
if (!searchOptions || !searchOptions.limit) {
searchOptions = { limit: 50 };
}
let messages = await this.client.pupPage.evaluate(async (chatId, limit) => {
let messages = await this.client.pupPage.evaluate(async (chatId, searchOptions) => {
const msgFilter = m => !m.isNotification; // dont include notification messages
const chat = window.Store.Chat.get(chatId);
let msgs = chat.msgs.models.filter(msgFilter);
while (msgs.length < limit) {
const loadedMessages = await chat.loadEarlierMsgs();
if (!loadedMessages) break;
msgs = [...loadedMessages.filter(msgFilter), ...msgs];
if (searchOptions && searchOptions.limit > 0) {
while (msgs.length < searchOptions.limit) {
const loadedMessages = await chat.loadEarlierMsgs();
if (!loadedMessages) break;
msgs = [...loadedMessages.filter(msgFilter), ...msgs];
}
if (msgs.length > searchOptions.limit) {
msgs.sort((a, b) => (a.t > b.t) ? 1 : -1);
msgs = msgs.splice(msgs.length - searchOptions.limit);
}
}
msgs.sort((a, b) => (a.t > b.t) ? 1 : -1);
if (msgs.length > limit) msgs = msgs.splice(msgs.length - limit);
return msgs.map(m => window.WWebJS.getMessageModel(m));
}, this.id._serialized, searchOptions.limit);
}, this.id._serialized, searchOptions);
return messages.map(m => new Message(this.client, m));
}
@@ -229,6 +238,14 @@ class Chat extends Base {
async getContact() {
return await this.client.getContactById(this.id._serialized);
}
/**
* Returns array of all Labels assigned to this Chat
* @returns {Promise<Array<Label>>}
*/
async getLabels() {
return this.client.getChatLabels(this.id._serialized);
}
}
module.exports = Chat;

View File

@@ -2,6 +2,14 @@
const Base = require('./Base');
/**
* ID that represents a contact
* @typedef {Object} ContactId
* @property {string} server
* @property {string} user
* @property {string} _serialized
*/
/**
* Represents a Contact on WhatsApp
* @extends {Base}
@@ -16,7 +24,7 @@ class Contact extends Base {
_patch(data) {
/**
* ID that represents the contact
* @type {object}
* @type {ContactId}
*/
this.id = data.id;
@@ -100,7 +108,7 @@ class Contact extends Base {
* @type {boolean}
*/
this.isBlocked = data.isBlocked;
return super._patch(data);
}
@@ -112,6 +120,22 @@ class Contact extends Base {
return await this.client.getProfilePicUrl(this.id._serialized);
}
/**
* Returns the contact's formatted phone number, (12345678901@c.us) => (+1 (234) 5678-901)
* @returns {Promise<string>}
*/
async getFormattedNumber() {
return await this.client.getFormattedNumber(this.id._serialized);
}
/**
* Returns the contact's countrycode, (1541859685@c.us) => (1)
* @returns {Promise<string>}
*/
async getCountryCode() {
return await this.client.getCountryCode(this.id._serialized);
}
/**
* Returns the Chat that corresponds to this Contact.
* Will return null when getting chat for currently logged in user.
@@ -152,7 +176,22 @@ class Contact extends Base {
return true;
}
/**
* Gets the Contact's current "about" info. Returns null if you don't have permission to read their status.
* @returns {Promise<?string>}
*/
async getAbout() {
const about = await this.client.pupPage.evaluate(async (contactId) => {
return window.Store.Wap.statusFind(contactId);
}, this.id._serialized);
if (typeof about.status !== 'string')
return null;
return about.status;
}
}
module.exports = Contact;
module.exports = Contact;

View File

@@ -2,6 +2,14 @@
const Chat = require('./Chat');
/**
* Group participant information
* @typedef {Object} GroupParticipant
* @property {ContactId} id
* @property {boolean} isAdmin
* @property {boolean} isSuperAdmin
*/
/**
* Represents a Group Chat on WhatsApp
* @extends {Chat}
@@ -15,6 +23,7 @@ class GroupChat extends Chat {
/**
* Gets the group owner
* @type {ContactId}
*/
get owner() {
return this.groupMetadata.owner;
@@ -38,7 +47,7 @@ class GroupChat extends Chat {
/**
* Gets the group participants
* @type {array}
* @type {Array<GroupParticipant>}
*/
get participants() {
return this.groupMetadata.participants;
@@ -47,6 +56,7 @@ class GroupChat extends Chat {
/**
* Adds a list of participants by ID to the group
* @param {Array<string>} participantIds
* @returns {Promise<Object>}
*/
async addParticipants(participantIds) {
return await this.client.pupPage.evaluate((chatId, participantIds) => {
@@ -57,6 +67,7 @@ class GroupChat extends Chat {
/**
* Removes a list of participants by ID to the group
* @param {Array<string>} participantIds
* @returns {Promise<Object>}
*/
async removeParticipants(participantIds) {
return await this.client.pupPage.evaluate((chatId, participantIds) => {
@@ -67,6 +78,7 @@ class GroupChat extends Chat {
/**
* Promotes participants by IDs to admins
* @param {Array<string>} participantIds
* @returns {Promise<{ status: number }>} Object with status code indicating if the operation was successful
*/
async promoteParticipants(participantIds) {
return await this.client.pupPage.evaluate((chatId, participantIds) => {
@@ -77,6 +89,7 @@ class GroupChat extends Chat {
/**
* Demotes participants by IDs to regular users
* @param {Array<string>} participantIds
* @returns {Promise<{ status: number }>} Object with status code indicating if the operation was successful
*/
async demoteParticipants(participantIds) {
return await this.client.pupPage.evaluate((chatId, participantIds) => {
@@ -87,6 +100,7 @@ class GroupChat extends Chat {
/**
* Updates the group subject
* @param {string} subject
* @returns {Promise}
*/
async setSubject(subject) {
let res = await this.client.pupPage.evaluate((chatId, subject) => {
@@ -101,6 +115,7 @@ class GroupChat extends Chat {
/**
* Updates the group description
* @param {string} description
* @returns {Promise}
*/
async setDescription(description) {
let res = await this.client.pupPage.evaluate((chatId, description) => {
@@ -147,6 +162,7 @@ class GroupChat extends Chat {
/**
* Gets the invite code for a specific group
* @returns {Promise<string>} Group's invite code
*/
async getInviteCode() {
let res = await this.client.pupPage.evaluate(chatId => {
@@ -162,6 +178,7 @@ class GroupChat extends Chat {
/**
* Invalidates the current group invite code and generates a new one
* @returns {Promise}
*/
async revokeInvite() {
return await this.client.pupPage.evaluate(chatId => {
@@ -171,6 +188,7 @@ class GroupChat extends Chat {
/**
* Makes the bot leave the group
* @returns {Promise}
*/
async leave() {
return await this.client.pupPage.evaluate(chatId => {

View File

@@ -43,7 +43,7 @@ class GroupNotification extends Base {
*
* @type {string}
*/
this.chatId = typeof (data.from) === 'object' ? data.from._serialized : data.from;
this.chatId = typeof (data.to) === 'object' ? data.to._serialized : data.to;
/**
* ContactId for the user that produced the GroupNotification.

50
src/structures/Label.js Normal file
View File

@@ -0,0 +1,50 @@
'use strict';
const Base = require('./Base');
// eslint-disable-next-line no-unused-vars
const Chat = require('./Chat');
/**
* WhatsApp Business Label information
*/
class Label extends Base {
/**
* @param {Base} client
* @param {object} labelData
*/
constructor(client, labelData){
super(client);
if(labelData) this._patch(labelData);
}
_patch(labelData){
/**
* Label ID
* @type {string}
*/
this.id = labelData.id;
/**
* Label name
* @type {string}
*/
this.name = labelData.name;
/**
* Label hex color
* @type {string}
*/
this.hexColor = labelData.hexColor;
}
/**
* Get all chats that have been assigned this Label
* @returns {Promise<Array<Chat>>}
*/
async getChats(){
return this.client.getChatsByLabelId(this.id);
}
}
module.exports = Label;

79
src/structures/List.js Normal file
View File

@@ -0,0 +1,79 @@
'use strict';
const Util = require('../util/Util');
/**
* Message type List
*/
class List {
/**
* @param {string} body
* @param {string} buttonText
* @param {Array<any>} sections
* @param {string?} title
* @param {string?} footer
*/
constructor(body, buttonText, sections, title, footer) {
/**
* Message body
* @type {string}
*/
this.description = body;
/**
* List button text
* @type {string}
*/
this.buttonText = buttonText;
/**
* title of message
* @type {string}
*/
this.title = title;
/**
* footer of message
* @type {string}
*/
this.footer = footer;
/**
* sections of message
* @type {Array<any>}
*/
this.sections = this._format(sections);
}
/**
* Creates section array from simple array
* @param {Array<any>} sections
* @returns {Array<any>}
* @example
* Input: [{title:'sectionTitle',rows:[{id:'customId', title:'ListItem2', description: 'desc'},{title:'ListItem2'}]}}]
* Returns: [{'title':'sectionTitle','rows':[{'rowId':'customId','title':'ListItem1','description':'desc'},{'rowId':'oGSRoD','title':'ListItem2','description':''}]}]
*/
_format(sections){
if(!sections.length){throw '[LT02] List without sections';}
if(sections.length > 1 && sections.filter(s => typeof s.title == 'undefined').length > 1){throw '[LT05] You can\'t have more than one empty title.';}
return sections.map( (section) =>{
if(!section.rows.length){throw '[LT03] Section without rows';}
return {
title: section.title ? section.title : undefined,
rows: section.rows.map( (row) => {
if(!row.title){throw '[LT04] Row without title';}
return {
rowId: row.id ? row.id : Util.generateHash(6),
title: row.title,
description: row.description ? row.description : ''
};
})
};
});
}
}
module.exports = List;

View File

@@ -3,6 +3,8 @@
const Base = require('./Base');
const MessageMedia = require('./MessageMedia');
const Location = require('./Location');
const Order = require('./Order');
const Payment = require('./Payment');
const { MessageTypes } = require('../util/Constants');
/**
@@ -40,7 +42,7 @@ class Message extends Base {
* Indicates if the message has media available for download
* @type {boolean}
*/
this.hasMedia = data.clientUrl ? true : false;
this.hasMedia = Boolean(data.mediaKey && data.directPath);
/**
* Message content
@@ -81,18 +83,38 @@ class Message extends Base {
*/
this.author = (typeof (data.author) === 'object' && data.author !== null) ? data.author._serialized : data.author;
/**
* String that represents from which device type the message was sent
* @type {string}
*/
this.deviceType = data.id.id.length > 21 ? 'android' : data.id.id.substring(0,2) =='3A' ? 'ios' : 'web';
/**
* Indicates if the message was forwarded
* @type {boolean}
*/
this.isForwarded = data.isForwarded;
/**
* Indicates how many times the message was forwarded.
*
* The maximum value is 127.
* @type {number}
*/
this.forwardingScore = data.forwardingScore || 0;
/**
* Indicates if the message is a status update
* @type {boolean}
*/
this.isStatus = data.isStatusV3;
/**
* Indicates if the message was starred
* @type {boolean}
*/
this.isStarred = data.star;
/**
* Indicates if the message was a broadcast
* @type {boolean}
@@ -123,6 +145,19 @@ class Message extends Base {
*/
this.vCards = data.type === MessageTypes.CONTACT_CARD_MULTI ? data.vcardList.map((c) => c.vcard) : data.type === MessageTypes.CONTACT_CARD ? [data.body] : [];
/**
* Group Invite Data
* @type {object}
*/
this.inviteV4 = data.type === MessageTypes.GROUP_INVITE ? {
inviteCode: data.inviteCode,
inviteCodeExp: data.inviteCodeExp,
groupId: data.inviteGrp,
groupName: data.inviteGrpName,
fromId: data.from._serialized,
toId: data.to._serialized
} : undefined;
/**
* Indicates the mentions in the message body.
* @type {Array<string>}
@@ -133,6 +168,71 @@ class Message extends Base {
this.mentionedIds = data.mentionedJidList;
}
/**
* Order ID for message type ORDER
* @type {string}
*/
this.orderId = data.orderId ? data.orderId : undefined;
/**
* Order Token for message type ORDER
* @type {string}
*/
this.token = data.token ? data.token : undefined;
/**
* Indicates whether the message is a Gif
* @type {boolean}
*/
this.isGif = Boolean(data.isGif);
/**
* Indicates if the message will disappear after it expires
* @type {boolean}
*/
this.isEphemeral = data.isEphemeral;
/** Title */
if (data.title) {
this.title = data.title;
}
/** Description */
if (data.description) {
this.description = data.description;
}
/** Business Owner JID */
if (data.businessOwnerJid) {
this.businessOwnerJid = data.businessOwnerJid;
}
/** Product ID */
if (data.productId) {
this.productId = data.productId;
}
/**
* Links included in the message.
* @type {Array<{link: string, isSuspicious: boolean}>}
*
*/
this.links = data.links;
/** Buttons */
if (data.dynamicReplyButtons) {
this.dynamicReplyButtons = data.dynamicReplyButtons;
}
/** Selected Button Id **/
if (data.selectedButtonId) {
this.selectedButtonId = data.selectedButtonId;
}
/** Selected List row Id **/
if (data.listResponse && data.listResponse.singleSelectReply.selectedRowId) {
this.selectedRowId = data.listResponse.singleSelectReply.selectedRowId;
}
return super._patch(data);
}
@@ -202,6 +302,14 @@ class Message extends Base {
return this.client.sendMessage(chatId, content, options);
}
/**
* Accept Group V4 Invite
* @returns {Promise<Object>}
*/
async acceptGroupV4Invite() {
return await this.client.acceptGroupV4Invite(this.inviteV4);
}
/**
* Forwards this message to another chat
*
@@ -233,24 +341,39 @@ class Message extends Base {
if (msg.mediaData.mediaStage != 'RESOLVED') {
// try to resolve media
await msg.downloadMedia(true, 1);
await msg.downloadMedia({
downloadEvenIfExpensive: true,
rmrReason: 1
});
}
if (msg.mediaData.mediaStage.includes('ERROR')) {
if (msg.mediaData.mediaStage.includes('ERROR') || msg.mediaData.mediaStage === 'FETCHING') {
// media could not be downloaded
return undefined;
}
const buffer = await window.WWebJS.downloadBuffer(msg.clientUrl);
const decrypted = await window.Store.CryptoLib.decryptE2EMedia(msg.type, buffer, msg.mediaKey, msg.mimetype);
const data = await window.WWebJS.readBlobAsync(decrypted._blob);
return {
data: data.split(',')[1],
mimetype: msg.mimetype,
filename: msg.filename
};
try {
const decryptedMedia = await window.Store.DownloadManager.downloadAndDecrypt({
directPath: msg.directPath,
encFilehash: msg.encFilehash,
filehash: msg.filehash,
mediaKey: msg.mediaKey,
mediaKeyTimestamp: msg.mediaKeyTimestamp,
type: msg.type,
signal: (new AbortController).signal
});
const data = window.WWebJS.arrayBufferToBase64(decryptedMedia);
return {
data,
mimetype: msg.mimetype,
filename: msg.filename
};
} catch (e) {
if(e.status && e.status === 404) return undefined;
throw e;
}
}, this.id._serialized);
if (!result) return undefined;
@@ -265,13 +388,99 @@ class Message extends Base {
await this.client.pupPage.evaluate((msgId, everyone) => {
let msg = window.Store.Msg.get(msgId);
if (everyone && msg.id.fromMe && msg.canRevoke()) {
return window.Store.Cmd.sendRevokeMsgs(msg.chat, [msg], true);
if (everyone && msg.id.fromMe && msg._canRevoke()) {
return window.Store.Cmd.sendRevokeMsgs(msg.chat, [msg], {type: 'Sender'});
}
return window.Store.Cmd.sendDeleteMsgs(msg.chat, [msg], true);
}, this.id._serialized, everyone);
}
/**
* Stars this message
*/
async star() {
await this.client.pupPage.evaluate((msgId) => {
let msg = window.Store.Msg.get(msgId);
if (msg.canStar()) {
return msg.chat.sendStarMsgs([msg], true);
}
}, this.id._serialized);
}
/**
* Unstars this message
*/
async unstar() {
await this.client.pupPage.evaluate((msgId) => {
let msg = window.Store.Msg.get(msgId);
if (msg.canStar()) {
return msg.chat.sendStarMsgs([msg], false);
}
}, this.id._serialized);
}
/**
* Message Info
* @typedef {Object} MessageInfo
* @property {Array<{id: ContactId, t: number}>} delivery Contacts to which the message has been delivered to
* @property {number} deliveryRemaining Amount of people to whom the message has not been delivered to
* @property {Array<{id: ContactId, t: number}>} played Contacts who have listened to the voice message
* @property {number} playedRemaining Amount of people who have not listened to the message
* @property {Array<{id: ContactId, t: number}>} read Contacts who have read the message
* @property {number} readRemaining Amount of people who have not read the message
*/
/**
* Get information about message delivery status. May return null if the message does not exist or is not sent by you.
* @returns {Promise<?MessageInfo>}
*/
async getInfo() {
const info = await this.client.pupPage.evaluate(async (msgId) => {
const msg = window.Store.Msg.get(msgId);
if(!msg) return null;
return await window.Store.Wap.queryMsgInfo(msg.id);
}, this.id._serialized);
if(info.status) {
return null;
}
return info;
}
/**
* Gets the order associated with a given message
* @return {Promise<Order>}
*/
async getOrder() {
if (this.type === MessageTypes.ORDER) {
const result = await this.client.pupPage.evaluate((orderId, token) => {
return window.WWebJS.getOrderDetail(orderId, token);
}, this.orderId, this.token);
if (!result) return undefined;
return new Order(this.client, result);
}
return undefined;
}
/**
* Gets the payment details associated with a given message
* @return {Promise<Payment>}
*/
async getPayment() {
if (this.type === MessageTypes.PAYMENT) {
const msg = await this.client.pupPage.evaluate(async (msgId) => {
const msg = window.Store.Msg.get(msgId);
if(!msg) return null;
return msg.serialize();
}, this.id._serialized);
return new Payment(this.client, msg);
}
return undefined;
}
}
module.exports = Message;

View File

@@ -3,6 +3,8 @@
const fs = require('fs');
const path = require('path');
const mime = require('mime');
const fetch = require('node-fetch');
const { URL } = require('url');
/**
* Media attached to a message
@@ -43,6 +45,59 @@ class MessageMedia {
return new MessageMedia(mimetype, b64data, filename);
}
/**
* Creates a MessageMedia instance from a URL
* @param {string} url
* @param {Object} [options]
* @param {boolean} [options.unsafeMime=false]
* @param {string} [options.filename]
* @param {object} [options.client]
* @param {object} [options.reqOptions]
* @param {number} [options.reqOptions.size=0]
* @returns {Promise<MessageMedia>}
*/
static async fromUrl(url, options = {}) {
const pUrl = new URL(url);
let mimetype = mime.getType(pUrl.pathname);
if (!mimetype && !options.unsafeMime)
throw new Error('Unable to determine MIME type using URL. Set unsafeMime to true to download it anyway.');
async function fetchData (url, options) {
const reqOptions = Object.assign({ headers: { accept: 'image/* video/* text/* audio/*' } }, options);
const response = await fetch(url, reqOptions);
const mime = response.headers.get('Content-Type');
const contentDisposition = response.headers.get('Content-Disposition');
const name = contentDisposition ? contentDisposition.match(/((?<=filename=")(.*)(?="))/) : null;
let data = '';
if (response.buffer) {
data = (await response.buffer()).toString('base64');
} else {
const bArray = new Uint8Array(await response.arrayBuffer());
bArray.forEach((b) => {
data += String.fromCharCode(b);
});
data = btoa(data);
}
return { data, mime, name };
}
const res = options.client
? (await options.client.pupPage.evaluate(fetchData, url, options.reqOptions))
: (await fetchData(url, options.reqOptions));
const filename = options.filename ||
(res.name ? res.name[0] : (pUrl.pathname.split('/').pop() || 'file'));
if (!mimetype)
mimetype = res.mime;
return new MessageMedia(mimetype, res.data, filename);
}
}
module.exports = MessageMedia;
module.exports = MessageMedia;

52
src/structures/Order.js Normal file
View File

@@ -0,0 +1,52 @@
'use strict';
const Base = require('./Base');
const Product = require('./Product');
/**
* Represents a Order on WhatsApp
* @extends {Base}
*/
class Order extends Base {
constructor(client, data) {
super(client);
if (data) this._patch(data);
}
_patch(data) {
/**
* List of products
* @type {Array<Product>}
*/
if (data.products) {
this.products = data.products.map(product => new Product(this.client, product));
}
/**
* Order Subtotal
* @type {string}
*/
this.subtotal = data.subtotal;
/**
* Order Total
* @type {string}
*/
this.total = data.total;
/**
* Order Currency
* @type {string}
*/
this.currency = data.currency;
/**
* Order Created At
* @type {number}
*/
this.createdAt = data.createdAt;
return super._patch(data);
}
}
module.exports = Order;

79
src/structures/Payment.js Normal file
View File

@@ -0,0 +1,79 @@
const Base = require('./Base');
class Payment extends Base {
constructor(client, data) {
super(client);
if (data) this._patch(data);
}
_patch(data) {
/**
* The payment Id
* @type {object}
*/
this.id = data.id;
/**
* The payment currency
* @type {string}
*/
this.paymentCurrency = data.paymentCurrency;
/**
* The payment ammount ( R$ 1.00 = 1000 )
* @type {number}
*/
this.paymentAmount1000 = data.paymentAmount1000;
/**
* The payment receiver
* @type {object}
*/
this.paymentMessageReceiverJid = data.paymentMessageReceiverJid;
/**
* The payment transaction timestamp
* @type {number}
*/
this.paymentTransactionTimestamp = data.paymentTransactionTimestamp;
/**
* The paymentStatus
*
* Possible Status
* 0:UNKNOWN_STATUS
* 1:PROCESSING
* 2:SENT
* 3:NEED_TO_ACCEPT
* 4:COMPLETE
* 5:COULD_NOT_COMPLETE
* 6:REFUNDED
* 7:EXPIRED
* 8:REJECTED
* 9:CANCELLED
* 10:WAITING_FOR_PAYER
* 11:WAITING
*
* @type {number}
*/
this.paymentStatus = data.paymentStatus;
/**
* Integer that represents the payment Text
* @type {number}
*/
this.paymentTxnStatus = data.paymentTxnStatus;
/**
* The note sent with the payment
* @type {string}
*/
this.paymentNote = !data.paymentNoteMsg ? undefined : data.paymentNoteMsg.body ? data.paymentNoteMsg.body : undefined ;
return super._patch(data);
}
}
module.exports = Payment;

68
src/structures/Product.js Normal file
View File

@@ -0,0 +1,68 @@
'use strict';
const Base = require('./Base');
const ProductMetadata = require('./ProductMetadata');
/**
* Represents a Product on WhatsAppBusiness
* @extends {Base}
*/
class Product extends Base {
constructor(client, data) {
super(client);
if (data) this._patch(data);
}
_patch(data) {
/**
* Product ID
* @type {string}
*/
this.id = data.id;
/**
* Price
* @type {string}
*/
this.price = data.price ? data.price : '';
/**
* Product Thumbnail
* @type {string}
*/
this.thumbnailUrl = data.thumbnailUrl;
/**
* Currency
* @type {string}
*/
this.currency = data.currency;
/**
* Product Name
* @type {string}
*/
this.name = data.name;
/**
* Product Quantity
* @type {number}
*/
this.quantity = data.quantity;
/** Product metadata */
this.data = null;
return super._patch(data);
}
async getData() {
if (this.data === null) {
let result = await this.client.pupPage.evaluate((productId) => {
return window.WWebJS.getProductMetadata(productId);
}, this.id);
if (!result) {
this.data = undefined;
} else {
this.data = new ProductMetadata(this.client, result);
}
}
return this.data;
}
}
module.exports = Product;

View File

@@ -0,0 +1,25 @@
const Base = require('./Base');
class ProductMetadata extends Base {
constructor(client, data) {
super(client);
if (data) this._patch(data);
}
_patch(data) {
/** Product ID */
this.id = data.id;
/** Retailer ID */
this.retailer_id = data.retailer_id;
/** Product Name */
this.name = data.name;
/** Product Description */
this.description = data.description;
return super._patch(data);
}
}
module.exports = ProductMetadata;

View File

@@ -10,5 +10,12 @@ module.exports = {
MessageMedia: require('./MessageMedia'),
PrivateChat: require('./PrivateChat'),
PrivateContact: require('./PrivateContact'),
GroupNotification: require('./GroupNotification')
};
GroupNotification: require('./GroupNotification'),
Label: require('./Label.js'),
Order: require('./Order'),
Product: require('./Product'),
Call: require('./Call'),
Buttons: require('./Buttons'),
List: require('./List'),
Payment: require('./Payment')
};

View File

@@ -11,9 +11,12 @@ exports.DefaultOptions = {
qrTimeoutMs: 45000,
qrRefreshIntervalMs: 20000,
authTimeoutMs: 45000,
qrMaxRetries: 0,
takeoverOnConflict: false,
takeoverTimeoutMs: 0,
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
ffmpegPath: 'ffmpeg',
bypassCSP: false
};
/**
@@ -48,7 +51,8 @@ exports.Events = {
QR_RECEIVED: 'qr',
DISCONNECTED: 'disconnected',
STATE_CHANGED: 'change_state',
BATTERY_CHANGED: 'change_battery'
BATTERY_CHANGED: 'change_battery',
INCOMING_CALL: 'incoming_call'
};
/**
@@ -67,8 +71,31 @@ exports.MessageTypes = {
LOCATION: 'location',
CONTACT_CARD: 'vcard',
CONTACT_CARD_MULTI: 'multi_vcard',
ORDER: 'order',
REVOKED: 'revoked',
UNKNOWN: 'unknown'
PRODUCT: 'product',
UNKNOWN: 'unknown',
GROUP_INVITE: 'groups_v4_invite',
LIST: 'list',
LIST_RESPONSE: 'list_response',
BUTTONS_RESPONSE: 'buttons_response',
PAYMENT: 'payment',
BROADCAST_NOTIFICATION: 'broadcast_notification',
CALL_LOG: 'call_log',
CIPHERTEXT: 'ciphertext',
DEBUG: 'debug',
E2E_NOTIFICATION: 'e2e_notification',
GP2: 'gp2',
GROUP_NOTIFICATION: 'group_notification',
HSM: 'hsm',
INTERACTIVE: 'interactive',
NATIVE_FLOW: 'native_flow',
NOTIFICATION: 'notification',
NOTIFICATION_TEMPLATE: 'notification_template',
OVERSIZED: 'oversized',
PROTOCOL: 'protocol',
REACTION: 'reaction',
TEMPLATE_BUTTON_REPLY: 'template_button_reply',
};
/**

View File

@@ -5,15 +5,14 @@ exports.ExposeStore = (moduleRaidStr) => {
eval('var moduleRaid = ' + moduleRaidStr);
// eslint-disable-next-line no-undef
window.mR = moduleRaid();
window.Store = window.mR.findModule('Chat')[0].default;
window.Store.AppState = window.mR.findModule('STREAM')[0].default;
window.Store.Conn = window.mR.findModule('Conn')[0].default;
window.Store.CryptoLib = window.mR.findModule('decryptE2EMedia')[0];
window.Store.Wap = window.mR.findModule('Wap')[0].default;
window.Store = Object.assign({}, window.mR.findModule(m => m.default && m.default.Chat)[0].default);
window.Store.AppState = window.mR.findModule('STREAM')[0].Socket;
window.Store.Conn = window.mR.findModule('Conn')[0].Conn;
window.Store.Wap = window.mR.findModule('queryLinkPreview')[0].default;
window.Store.SendSeen = window.mR.findModule('sendSeen')[0];
window.Store.SendClear = window.mR.findModule('sendClear')[0];
window.Store.SendDelete = window.mR.findModule('sendDelete')[0];
window.Store.genId = window.mR.findModule((module) => module.default && typeof module.default === 'function' && module.default.toString().match(/crypto/))[0].default;
window.Store.genId = window.mR.findModule('randomId')[0].randomId;
window.Store.SendMessage = window.mR.findModule('addAndSendMsgToChat')[0];
window.Store.MsgKey = window.mR.findModule((module) => module.default && module.default.fromString)[0].default;
window.Store.Invite = window.mR.findModule('sendJoinGroupViaInvite')[0];
@@ -21,7 +20,8 @@ exports.ExposeStore = (moduleRaidStr) => {
window.Store.MediaPrep = window.mR.findModule('MediaPrep')[0];
window.Store.MediaObject = window.mR.findModule('getOrCreateMediaObject')[0];
window.Store.MediaUpload = window.mR.findModule('uploadMedia')[0];
window.Store.Cmd = window.mR.findModule('Cmd')[0].default;
window.Store.NumberInfo = window.mR.findModule('formattedPhoneNumber')[0];
window.Store.Cmd = window.mR.findModule('Cmd')[0].Cmd;
window.Store.MediaTypes = window.mR.findModule('msgToMediaType')[0];
window.Store.VCard = window.mR.findModule('vcardFromContactModel')[0];
window.Store.UserConstructor = window.mR.findModule((module) => (module.default && module.default.prototype && module.default.prototype.isServer && module.default.prototype.isUser) ? module.default : null)[0].default;
@@ -29,10 +29,27 @@ exports.ExposeStore = (moduleRaidStr) => {
window.Store.WidFactory = window.mR.findModule('createWid')[0];
window.Store.BlockContact = window.mR.findModule('blockContact')[0];
window.Store.GroupMetadata = window.mR.findModule((module) => module.default && module.default.handlePendingInvite)[0].default;
window.Store.UploadUtils = window.mR.findModule((module) => (module.default && module.default.encryptAndUpload) ? module.default : null)[0].default;
window.Store.Label = window.mR.findModule('LabelCollection')[0].LabelCollection;
window.Store.Features = window.mR.findModule('FEATURE_CHANGE_EVENT')[0].GK;
window.Store.QueryOrder = window.mR.findModule('queryOrder')[0];
window.Store.QueryProduct = window.mR.findModule('queryProduct')[0];
window.Store.DownloadManager = window.mR.findModule('downloadManager')[0].downloadManager;
window.Store.Call = window.mR.findModule('CallCollection')[0].CallCollection;
if(!window.Store.Chat._find) {
window.Store.Chat._find = e => {
const target = window.Store.Chat.get(e);
return target ? Promise.resolve(target) : Promise.resolve({
id: e
});
};
}
};
exports.LoadUtils = () => {
window.WWebJS = {};
window.WWebJS.getNumberId = async (id) => {
let result = await window.Store.Wap.queryExist(id);
@@ -40,6 +57,7 @@ exports.LoadUtils = () => {
throw 'The number provided is not a registered whatsapp user';
return result.jid;
};
window.WWebJS.sendSeen = async (chatId) => {
let chat = window.Store.Chat.get(chatId);
if (chat !== undefined) {
@@ -49,12 +67,22 @@ exports.LoadUtils = () => {
return false;
};
window.WWebJS.sendMessage = async (chat, content, options = {}) => {
let attOptions = {};
if (options.attachment) {
attOptions = await window.WWebJS.processMediaData(options.attachment, options.sendAudioAsVoice);
content = attOptions.preview;
attOptions = options.sendMediaAsSticker
? await window.WWebJS.processStickerData(options.attachment)
: await window.WWebJS.processMediaData(options.attachment, {
forceVoice: options.sendAudioAsVoice,
forceDocument: options.sendMediaAsDocument,
forceGif: options.sendVideoAsGif
});
content = options.sendMediaAsSticker ? undefined : attOptions.preview;
delete options.attachment;
delete options.sendMediaAsSticker;
}
let quotedMsgOptions = {};
@@ -124,13 +152,62 @@ exports.LoadUtils = () => {
options = { ...options, ...preview };
}
}
let buttonOptions = {};
if(options.buttons){
let caption;
if(options.buttons.type === 'chat') {
content = options.buttons.body;
caption = content;
}else{
caption = options.caption ? options.caption : ' '; //Caption can't be empty
}
buttonOptions = {
productHeaderImageRejected: false,
isFromTemplate: false,
isDynamicReplyButtonsMsg: true,
title: options.buttons.title ? options.buttons.title : undefined,
footer: options.buttons.footer ? options.buttons.footer : undefined,
dynamicReplyButtons: options.buttons.buttons,
replyButtons: options.buttons.buttons,
caption: caption
};
delete options.buttons;
}
let listOptions = {};
if(options.list){
if(window.Store.Conn.platform === 'smba' || window.Store.Conn.platform === 'smbi'){
throw '[LT01] Whatsapp business can\'t send this yet';
}
listOptions = {
type: 'list',
footer: options.list.footer,
list: {
...options.list,
listType: 1
},
body: options.list.description
};
delete options.list;
delete listOptions.list.footer;
}
const newMsgId = new window.Store.MsgKey({
fromMe: true,
remote: chat.id,
id: window.Store.genId(),
});
const extraOptions = options.extraOptions || {};
delete options.extraOptions;
const ephemeralSettings = {
ephemeralDuration: chat.isEphemeralSettingOn() ? chat.getEphemeralSetting() : undefined,
ephemeralSettingTimestamp: chat.getEphemeralSettingTimestamp() || undefined,
disappearingModeInitiator: chat.getDisappearingModeInitiator() || undefined,
};
const message = {
...options,
id: newMsgId,
@@ -143,20 +220,52 @@ exports.LoadUtils = () => {
t: parseInt(new Date().getTime() / 1000),
isNewMsg: true,
type: 'chat',
...ephemeralSettings,
...locationOptions,
...attOptions,
...quotedMsgOptions,
...vcardOptions
...vcardOptions,
...buttonOptions,
...listOptions,
...extraOptions
};
await window.Store.SendMessage.addAndSendMsgToChat(chat, message);
return window.Store.Msg.get(newMsgId._serialized);
};
window.WWebJS.processMediaData = async (mediaInfo, forceVoice) => {
window.WWebJS.processStickerData = async (mediaInfo) => {
if (mediaInfo.mimetype !== 'image/webp') throw new Error('Invalid media type');
const file = window.WWebJS.mediaInfoToFile(mediaInfo);
let filehash = await window.WWebJS.getFileHash(file);
let mediaKey = await window.WWebJS.generateHash(32);
const controller = new AbortController();
const uploadedInfo = await window.Store.UploadUtils.encryptAndUpload({
blob: file,
type: 'sticker',
signal: controller.signal,
mediaKey
});
const stickerInfo = {
...uploadedInfo,
clientUrl: uploadedInfo.url,
deprecatedMms3Url: uploadedInfo.url,
uploadhash: uploadedInfo.encFilehash,
size: file.size,
type: 'sticker',
filehash
};
return stickerInfo;
};
window.WWebJS.processMediaData = async (mediaInfo, { forceVoice, forceDocument, forceGif }) => {
const file = window.WWebJS.mediaInfoToFile(mediaInfo);
const mData = await window.Store.OpaqueData.createFromData(file, file.type);
const mediaPrep = window.Store.MediaPrep.prepRawMedia(mData, {});
const mediaPrep = window.Store.MediaPrep.prepRawMedia(mData, { asDocument: forceDocument });
const mediaData = await mediaPrep.waitForPrep();
const mediaObject = window.Store.MediaObject.getOrCreateMediaObject(mediaData.filehash);
@@ -169,6 +278,14 @@ exports.LoadUtils = () => {
mediaData.type = 'ptt';
}
if (forceGif && mediaData.type === 'video') {
mediaData.isGif = true;
}
if (forceDocument) {
mediaData.type = 'document';
}
if (!(mediaData.mediaBlob instanceof window.Store.OpaqueData)) {
mediaData.mediaBlob = await window.Store.OpaqueData.createFromData(mediaData.mediaBlob, mediaData.mediaBlob.type);
}
@@ -190,10 +307,12 @@ exports.LoadUtils = () => {
mediaData.set({
clientUrl: mediaEntry.mmsUrl,
deprecatedMms3Url: mediaEntry.deprecatedMms3Url,
directPath: mediaEntry.directPath,
mediaKey: mediaEntry.mediaKey,
mediaKeyTimestamp: mediaEntry.mediaKeyTimestamp,
filehash: mediaObject.filehash,
encFilehash: mediaEntry.encFilehash,
uploadhash: mediaEntry.uploadHash,
size: mediaObject.size,
streamingSidecar: mediaEntry.sidecar,
@@ -205,14 +324,34 @@ exports.LoadUtils = () => {
window.WWebJS.getMessageModel = message => {
const msg = message.serialize();
msg.isEphemeral = message.isEphemeral;
msg.isStatusV3 = message.isStatusV3;
msg.links = (message.getLinks()).map(link => ({
link: link.href,
isSuspicious: Boolean(link.suspiciousCharacters && link.suspiciousCharacters.size)
}));
if (msg.buttons) {
msg.buttons = msg.buttons.serialize();
}
if (msg.dynamicReplyButtons) {
msg.dynamicReplyButtons = JSON.parse(JSON.stringify(msg.dynamicReplyButtons));
}
if(msg.replyButtons) {
msg.replyButtons = JSON.parse(JSON.stringify(msg.replyButtons));
}
if(typeof msg.id.remote === 'object') {
msg.id = Object.assign({}, msg.id, {remote: msg.id.remote._serialized});
}
delete msg.pendingAckUpdate;
return msg;
};
window.WWebJS.getChatModel = async chat => {
let res = chat.serialize();
res.isGroup = chat.isGroup;
@@ -232,7 +371,8 @@ exports.LoadUtils = () => {
};
window.WWebJS.getChat = async chatId => {
const chat = window.Store.Chat.get(chatId);
const chatWid = window.Store.WidFactory.createWid(chatId);
const chat = await window.Store.Chat.find(chatWid);
return await window.WWebJS.getChatModel(chat);
};
@@ -262,8 +402,9 @@ exports.LoadUtils = () => {
return res;
};
window.WWebJS.getContact = contactId => {
const contact = window.Store.Contact.get(contactId);
window.WWebJS.getContact = async contactId => {
const wid = window.Store.WidFactory.createWid(contactId);
const contact = await window.Store.Contact.find(wid);
return window.WWebJS.getContactModel(contact);
};
@@ -288,43 +429,30 @@ exports.LoadUtils = () => {
});
};
window.WWebJS.downloadBuffer = (url) => {
return new Promise(function (resolve, reject) {
let xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
if (xhr.status == 200) {
resolve(xhr.response);
} else {
reject({
status: this.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function () {
reject({
status: this.status,
statusText: xhr.statusText
});
};
xhr.send(null);
});
window.WWebJS.arrayBufferToBase64 = (arrayBuffer) => {
let binary = '';
const bytes = new Uint8Array( arrayBuffer );
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa( binary );
};
window.WWebJS.readBlobAsync = (blob) => {
return new Promise((resolve, reject) => {
let reader = new FileReader();
window.WWebJS.getFileHash = async (data) => {
let buffer = await data.arrayBuffer();
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
return btoa(String.fromCharCode(...new Uint8Array(hashBuffer)));
};
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
reader.readAsDataURL(blob);
});
window.WWebJS.generateHash = async (length) => {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
};
window.WWebJS.sendClearChat = async (chatId) => {
@@ -363,6 +491,41 @@ exports.LoadUtils = () => {
return true;
};
window.WWebJS.getLabelModel = label => {
let res = label.serialize();
res.hexColor = label.hexColor;
return res;
};
window.WWebJS.getLabels = () => {
const labels = window.Store.Label.models;
return labels.map(label => window.WWebJS.getLabelModel(label));
};
window.WWebJS.getLabel = (labelId) => {
const label = window.Store.Label.get(labelId);
return window.WWebJS.getLabelModel(label);
};
window.WWebJS.getChatLabels = async (chatId) => {
const chat = await window.WWebJS.getChat(chatId);
return (chat.labels || []).map(id => window.WWebJS.getLabel(id));
};
window.WWebJS.getOrderDetail = async (orderId, token) => {
return window.Store.QueryOrder.queryOrder(orderId, 80, 80, token);
};
window.WWebJS.getProductMetadata = async (productId) => {
let sellerId = window.Store.Conn.wid;
let product = await window.Store.QueryProduct.queryProduct(sellerId, productId);
if (product && product.data) {
return product.data;
}
return undefined;
};
};
exports.MarkAllRead = () => {

View File

@@ -15,7 +15,8 @@ class InterfaceController {
*/
async openChatWindow(chatId) {
await this.pupPage.evaluate(async chatId => {
let chat = await window.Store.Chat.get(chatId);
let chatWid = window.Store.WidFactory.createWid(chatId);
let chat = await window.Store.Chat.find(chatWid);
await window.Store.Cmd.openChatAt(chat);
}, chatId);
}
@@ -27,10 +28,32 @@ class InterfaceController {
async openChatDrawer(chatId) {
await this.pupPage.evaluate(async chatId => {
let chat = await window.Store.Chat.get(chatId);
await window.Store.Cmd.chatInfoDrawer(chat);
await window.Store.Cmd.openDrawerMid(chat);
}, chatId);
}
/**
* Opens the Chat Search
* @param {string} chatId ID of the chat search that will be opened
*/
async openChatSearch(chatId) {
await this.pupPage.evaluate(async chatId => {
let chat = await window.Store.Chat.get(chatId);
await window.Store.Cmd.chatSearch(chat);
}, chatId);
}
/**
* Opens or Scrolls the Chat Window to the position of the message
* @param {string} msgId ID of the message that will be scrolled to
*/
async openChatWindowAt(msgId) {
await this.pupPage.evaluate(async msgId => {
let msg = await window.Store.Msg.get(msgId);
await window.Store.Cmd.openChatAt(msg.chat, msg.chat.getSearchContext(msg));
}, msgId);
}
/**
* Opens the Message Drawer
* @param {string} msgId ID of the message drawer that will be opened
@@ -50,7 +73,49 @@ class InterfaceController {
await window.Store.Cmd.closeDrawerRight();
});
}
/**
* Get all Features
*/
async getFeatures() {
return await this.pupPage.evaluate(() => {
return window.Store.Features.F;
});
}
/**
* Check if Feature is enabled
* @param {string} feature status to check
*/
async checkFeatureStatus(feature) {
return await this.pupPage.evaluate((feature) => {
return window.Store.Features.supportsFeature(feature);
}, feature);
}
/**
* Enable Features
* @param {string[]} features to be enabled
*/
async enableFeatures(features) {
await this.pupPage.evaluate((features) => {
for (const feature in features) {
window.Store.Features.setFeature(features[feature], true);
}
}, features);
}
/**
* Disable Features
* @param {string[]} features to be disabled
*/
async disableFeatures(features) {
await this.pupPage.evaluate((features) => {
for (const feature in features) {
window.Store.Features.setFeature(features[feature], false);
}
}, features);
}
}
module.exports = InterfaceController;
module.exports = InterfaceController;

View File

@@ -1,5 +1,13 @@
'use strict';
const sharp = require('sharp');
const path = require('path');
const Crypto = require('crypto');
const { tmpdir } = require('os');
const ffmpeg = require('fluent-ffmpeg');
const webp = require('node-webpmux');
const fs = require('fs').promises;
const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
/**
@@ -11,6 +19,16 @@ class Util {
throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
}
static generateHash(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
/**
* Sets default properties on an object that aren't already specified.
* @param {Object} def Default properties
@@ -30,6 +48,156 @@ class Util {
return given;
}
/**
* Formats a image to webp
* @param {MessageMedia} media
*
* @returns {Promise<MessageMedia>} media in webp format
*/
static async formatImageToWebpSticker(media) {
if (!media.mimetype.includes('image'))
throw new Error('media is not a image');
if (media.mimetype.includes('webp')) {
return media;
}
const buff = Buffer.from(media.data, 'base64');
let sharpImg = sharp(buff);
sharpImg = sharpImg.webp();
sharpImg = sharpImg.resize(512, 512, {
fit: 'contain',
background: { r: 0, g: 0, b: 0, alpha: 0 },
});
let webpBase64 = (await sharpImg.toBuffer()).toString('base64');
return {
mimetype: 'image/webp',
data: webpBase64,
filename: media.filename,
};
}
/**
* Formats a video to webp
* @param {MessageMedia} media
*
* @returns {Promise<MessageMedia>} media in webp format
*/
static async formatVideoToWebpSticker(media) {
if (!media.mimetype.includes('video'))
throw new Error('media is not a video');
const videoType = media.mimetype.split('/')[1];
const tempFile = path.join(
tmpdir(),
`${Crypto.randomBytes(6).readUIntLE(0, 6).toString(36)}.webp`
);
const stream = new (require('stream').Readable)();
const buffer = Buffer.from(
media.data.replace(`data:${media.mimetype};base64,`, ''),
'base64'
);
stream.push(buffer);
stream.push(null);
await new Promise((resolve, reject) => {
ffmpeg(stream)
.inputFormat(videoType)
.on('error', reject)
.on('end', () => resolve(true))
.addOutputOptions([
'-vcodec',
'libwebp',
'-vf',
// eslint-disable-next-line no-useless-escape
'scale=\'iw*min(300/iw\,300/ih)\':\'ih*min(300/iw\,300/ih)\',format=rgba,pad=300:300:\'(300-iw)/2\':\'(300-ih)/2\':\'#00000000\',setsar=1,fps=10',
'-loop',
'0',
'-ss',
'00:00:00.0',
'-t',
'00:00:05.0',
'-preset',
'default',
'-an',
'-vsync',
'0',
'-s',
'512:512',
])
.toFormat('webp')
.save(tempFile);
});
const data = await fs.readFile(tempFile, 'base64');
await fs.unlink(tempFile);
return {
mimetype: 'image/webp',
data: data,
filename: media.filename,
};
}
/**
* Sticker metadata.
* @typedef {Object} StickerMetadata
* @property {string} [name]
* @property {string} [author]
* @property {string[]} [categories]
*/
/**
* Formats a media to webp
* @param {MessageMedia} media
* @param {StickerMetadata} metadata
*
* @returns {Promise<MessageMedia>} media in webp format
*/
static async formatToWebpSticker(media, metadata) {
let webpMedia;
if (media.mimetype.includes('image'))
webpMedia = await this.formatImageToWebpSticker(media);
else if (media.mimetype.includes('video'))
webpMedia = await this.formatVideoToWebpSticker(media);
else
throw new Error('Invalid media format');
if (metadata.name || metadata.author) {
const img = new webp.Image();
const hash = this.generateHash(32);
const stickerPackId = hash;
const packname = metadata.name;
const author = metadata.author;
const categories = metadata.categories || [''];
const json = { 'sticker-pack-id': stickerPackId, 'sticker-pack-name': packname, 'sticker-pack-publisher': author, 'emojis': categories };
let exifAttr = Buffer.from([0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00]);
let jsonBuffer = Buffer.from(JSON.stringify(json), 'utf8');
let exif = Buffer.concat([exifAttr, jsonBuffer]);
exif.writeUIntLE(jsonBuffer.length, 14, 4);
await img.load(Buffer.from(webpMedia.data, 'base64'));
img.exif = exif;
webpMedia.data = (await img.save(null)).toString('base64');
}
return webpMedia;
}
/**
* Configure ffmpeg path
* @param {string} path
*/
static setFfmpegPath(path) {
ffmpeg.setFfmpegPath(path);
}
}
module.exports = Util;
module.exports = Util;

10
tests/README.md Normal file
View File

@@ -0,0 +1,10 @@
## Running tests
These tests require an authenticated WhatsApp Web session, as well as an additional phone that you can send messages to.
This can be configured using the following environment variables:
- `WWEBJS_TEST_SESSION`: A JSON-formatted string with the session details. Must include `WABrowserId`, `WASecretBundle`, `WAToken1` and `WAToken2`.
- `WWEBJS_TEST_SESSION_PATH`: Path to a JSON file that contains the session details. Must include `WABrowserId`, `WASecretBundle`, `WAToken1` and `WAToken2`.
- `WWEBJS_TEST_REMOTE_ID`: A valid WhatsApp ID that you can send messages to, e.g. `123456789@c.us`. It should be different from the ID used by the provided session.
You *must* set `WWEBJS_TEST_REMOTE_ID` **and** either `WWEBJS_TEST_SESSION` or `WWEBJS_TEST_SESSION_PATH` for the tests to run properly.

584
tests/client.js Normal file
View File

@@ -0,0 +1,584 @@
const {expect} = require('chai');
const sinon = require('sinon');
const helper = require('./helper');
const Chat = require('../src/structures/Chat');
const Contact = require('../src/structures/Contact');
const Message = require('../src/structures/Message');
const MessageMedia = require('../src/structures/MessageMedia');
const Location = require('../src/structures/Location');
const { MessageTypes, WAState } = require('../src/util/Constants');
const remoteId = helper.remoteId;
describe('Client', function() {
describe('Authentication', function() {
it('should emit QR code if not authenticated', async function() {
this.timeout(25000);
const callback = sinon.spy();
const client = helper.createClient();
client.on('qr', callback);
client.initialize();
await helper.sleep(20000);
expect(callback.called).to.equal(true);
expect(callback.args[0][0]).to.have.lengthOf(152);
await client.destroy();
});
it('should disconnect after reaching max qr retries', async function () {
this.timeout(50000);
const qrCallback = sinon.spy();
const disconnectedCallback = sinon.spy();
const client = helper.createClient({options: {qrMaxRetries: 2}});
client.on('qr', qrCallback);
client.on('disconnected', disconnectedCallback);
client.initialize();
await helper.sleep(45000);
expect(qrCallback.calledThrice).to.eql(true);
expect(disconnectedCallback.calledOnceWith('Max qrcode retries reached')).to.eql(true);
});
it('should fail auth if session is invalid', async function() {
this.timeout(40000);
const authFailCallback = sinon.spy();
const qrCallback = sinon.spy();
const readyCallback = sinon.spy();
const client = helper.createClient({
options: {
session: {
WABrowserId: 'invalid',
WASecretBundle: 'invalid',
WAToken1: 'invalid',
WAToken2: 'invalid'
},
authTimeoutMs: 10000,
restartOnAuthFail: false
}
});
client.on('qr', qrCallback);
client.on('auth_failure', authFailCallback);
client.on('ready', readyCallback);
client.initialize();
await helper.sleep(25000);
expect(authFailCallback.called).to.equal(true);
expect(authFailCallback.args[0][0]).to.equal('Unable to log in. Are the session details valid?');
expect(readyCallback.called).to.equal(false);
expect(qrCallback.called).to.equal(false);
await client.destroy();
});
it('can restart without a session if session was invalid and restartOnAuthFail=true', async function() {
this.timeout(40000);
const authFailCallback = sinon.spy();
const qrCallback = sinon.spy();
const client = helper.createClient({
options:{
session: {
WABrowserId: 'invalid',
WASecretBundle: 'invalid',
WAToken1: 'invalid',
WAToken2: 'invalid'
},
authTimeoutMs: 10000,
restartOnAuthFail: true
}
});
client.on('auth_failure', authFailCallback);
client.on('qr', qrCallback);
client.initialize();
await helper.sleep(35000);
expect(authFailCallback.called).to.equal(true);
expect(qrCallback.called).to.equal(true);
expect(qrCallback.args[0][0]).to.have.lengthOf(152);
await client.destroy();
});
it('should authenticate with existing session', async function() {
this.timeout(40000);
const authenticatedCallback = sinon.spy();
const qrCallback = sinon.spy();
const readyCallback = sinon.spy();
const client = helper.createClient({withSession: true});
client.on('qr', qrCallback);
client.on('authenticated', authenticatedCallback);
client.on('ready', readyCallback);
await client.initialize();
expect(authenticatedCallback.called).to.equal(true);
const newSession = authenticatedCallback.args[0][0];
expect(newSession).to.have.key([
'WABrowserId',
'WASecretBundle',
'WAToken1',
'WAToken2'
]);
expect(authenticatedCallback.called).to.equal(true);
expect(readyCallback.called).to.equal(true);
expect(qrCallback.called).to.equal(false);
await client.destroy();
});
it('can take over if client was logged in somewhere else with takeoverOnConflict=true', async function() {
this.timeout(40000);
const readyCallback1 = sinon.spy();
const readyCallback2 = sinon.spy();
const disconnectedCallback1 = sinon.spy();
const disconnectedCallback2 = sinon.spy();
const client1 = helper.createClient({
withSession: true,
options: { takeoverOnConflict: true, takeoverTimeoutMs: 5000 }
});
const client2 = helper.createClient({withSession: true});
client1.on('ready', readyCallback1);
client2.on('ready', readyCallback2);
client1.on('disconnected', disconnectedCallback1);
client2.on('disconnected', disconnectedCallback2);
await client1.initialize();
expect(readyCallback1.called).to.equal(true);
expect(readyCallback2.called).to.equal(false);
expect(disconnectedCallback1.called).to.equal(false);
expect(disconnectedCallback2.called).to.equal(false);
await client2.initialize();
expect(readyCallback2.called).to.equal(true);
expect(disconnectedCallback1.called).to.equal(false);
expect(disconnectedCallback2.called).to.equal(false);
// wait for takeoverTimeoutMs to kick in
await helper.sleep(5200);
expect(disconnectedCallback1.called).to.equal(false);
expect(disconnectedCallback2.called).to.equal(true);
expect(disconnectedCallback2.calledWith(WAState.CONFLICT)).to.equal(true);
await client1.destroy();
});
});
describe('Authenticated', function() {
let client;
before(async function() {
this.timeout(35000);
client = helper.createClient({withSession: true});
await client.initialize();
});
after(async function () {
await client.destroy();
});
it('can get current WhatsApp Web version', async function () {
const version = await client.getWWebVersion();
expect(typeof version).to.equal('string');
console.log(`WA Version: ${version}`);
});
describe('Expose Store', function() {
it('exposes the store', async function() {
const exposed = await client.pupPage.evaluate(() => {
return Boolean(window.Store);
});
expect(exposed).to.equal(true);
});
it('exposes all required WhatsApp Web internal models', async function() {
const expectedModules = [
'AppState',
'BlockContact',
'Call',
'Chat',
'Cmd',
'Conn',
'Contact',
'DownloadManager',
'Features',
'GroupMetadata',
'Invite',
'Label',
'MediaObject',
'MediaPrep',
'MediaTypes',
'MediaUpload',
'Msg',
'MsgKey',
'OpaqueData',
'QueryOrder',
'QueryProduct',
'SendClear',
'SendDelete',
'SendMessage',
'SendSeen',
'Sticker',
'UploadUtils',
'UserConstructor',
'VCard',
'Validators',
'Wap',
'WidFactory',
'genId'
];
const loadedModules = await client.pupPage.evaluate((expectedModules) => {
return expectedModules.filter(m => Boolean(window.Store[m]));
}, expectedModules);
expect(loadedModules).to.have.members(expectedModules);
});
});
describe('Send Messages', function () {
it('can send a message', async function() {
const msg = await client.sendMessage(remoteId, 'hello world');
expect(msg).to.be.instanceOf(Message);
expect(msg.type).to.equal(MessageTypes.TEXT);
expect(msg.fromMe).to.equal(true);
expect(msg.body).to.equal('hello world');
expect(msg.to).to.equal(remoteId);
});
it('can send a media message', async function() {
const media = new MessageMedia(
'image/png',
'iVBORw0KGgoAAAANSUhEUgAAAV4AAACWBAMAAABkyf1EAAAAG1BMVEXMzMyWlpacnJyqqqrFxcWxsbGjo6O3t7e+vr6He3KoAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEcElEQVR4nO2aTW/bRhCGh18ij1zKknMkbbf2UXITIEeyMhIfRaF1exQLA/JRclslRykO+rs7s7s0VwytNmhJtsA8gHZEcox9PTs7uysQgGEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmGYr2OWRK/ReIKI8Zt7Hb19wTcQ0uTkGh13bQupcw7gPOvdo12/5CzNtNR7xLUtNtT3CGBQ6g3InjY720pvofUec22LJPr8PhEp2OMPyI40PdwWUdronCu9yQpdPx53bQlfLKnfOVhlnDYRBXve4Ov+IZTeMgdedm0NR+xoXJeQvdJ3CvziykSukwil16W/Oe7aGjIjqc/9ib4jQlJy0uArtN4A0+cvXFvDkmUJ47sJ1Y1ATLDNVXZkNPIepQzxy1ki9fqiwbUj/I+64zxWNzyZnPuhvohJ9K70VvXBixpcu2SAHU+Xd9EKdEJDNpYP3AQr3bQSpPQ6Y6/4dl1z7ZDbArsszjA7L0g7ibB0CDcidUWVoErvIMKZh2Xs0LUzcLW6V5NfiUgNEbaYmAVL6bXl0nJRc+1S72ua/D/cTjGPlQj7eUqd7A096rYlRjdPYlhz7VIvxpVG3cemDKF+WAwLY/6XelOZKTXXzsC4xvDjjtSN6kHLhLke6PrwM8h1raf40qjrGO7H9aTEbduucjS04ZrYU/4iuS5Z2Hdt0rvCLFdmLEXcU30AGddST62o+sLcf5l6k7CP+ru4pLYqX/VFyxbm/utQbx/r22ZEbTb2f5I2kns1Y1OQR8ZyofX+TjJxj1Rz7QQVnf1QzR26Oth0ueJVYcRP6ZUPac/Rx/5M6ixO1dhSrT3Y1DpiYmx3tF4ZUdpz9LD/dSg9PXES0LB71BwcGjKROuV28lnvnv7HHJsezheBGH5+X2CfSfRbMKW+5aGs3JFjMrjGibJc0S7TJzqjHrh2hDybj9XRXNZa89Aro55XBdbW5wti2c/5WJ7jJ1RolVUn/HWpb0I58Tziup6Rx7Dm2hnbRP1GM9PW/NFmQ4PtVRVN63Wvxfmu5sowDMMwDMMwDMMwDMMwDMMwDMMwzL+CpT//F/6beoV8zb2Jmt4Qryx6lTUCsENQ75HOkhXAO3EPVgyQtKtUy3C/e+FJg17Zjnew1Xrdb9InbG4WqfUAftG+WhLwPVyfg536+MU7m4C1CMk4ZznpXZzDYI1PDL2nS1hpvc5cNd7E2sJg05Fe7/7d3Fln8Cvc3bwB616auxsKl4WPghjemHrDqyDWeu1UNW5s2btPnSQ75oOdunEwWazfwgVG0kqluYCM9OIjWOGnfA2b9G4Ha63XKpvQ8perTvTifJNhi6+WMWmi7smEZf6G8MmhlyGq+NqP8GV84TLuJr7UIQVx+bDEoEpRZIz42gs40OuN4Mv8hXzelV7KX1isH+ewTWckikyVv+CfHuqVF7I16gN0VKypX6wPsE+zFPzkinolU9UH8OMGvSpnZqKsv13p/RsMun6X5x/y2LeAr8O66lsBwzBMP/wJfyGq8pgBk6IAAAAASUVORK5CYII='
);
const msg = await client.sendMessage(remoteId, media, {caption: 'here\'s my media'});
expect(msg).to.be.instanceOf(Message);
expect(msg.type).to.equal(MessageTypes.IMAGE);
expect(msg.fromMe).to.equal(true);
expect(msg.hasMedia).to.equal(true);
expect(msg.body).to.equal('here\'s my media');
expect(msg.to).to.equal(remoteId);
});
it('can send a media message from URL', async function() {
const media = await MessageMedia.fromUrl('https://via.placeholder.com/350x150.png');
const msg = await client.sendMessage(remoteId, media);
expect(msg).to.be.instanceOf(Message);
expect(msg.type).to.equal(MessageTypes.IMAGE);
expect(msg.fromMe).to.equal(true);
expect(msg.hasMedia).to.equal(true);
expect(msg.to).to.equal(remoteId);
});
it('can send a media message as a document', async function() {
const media = new MessageMedia(
'image/png',
'iVBORw0KGgoAAAANSUhEUgAAAV4AAACWBAMAAABkyf1EAAAAG1BMVEXMzMyWlpacnJyqqqrFxcWxsbGjo6O3t7e+vr6He3KoAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEcElEQVR4nO2aTW/bRhCGh18ij1zKknMkbbf2UXITIEeyMhIfRaF1exQLA/JRclslRykO+rs7s7s0VwytNmhJtsA8gHZEcox9PTs7uysQgGEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmGYr2OWRK/ReIKI8Zt7Hb19wTcQ0uTkGh13bQupcw7gPOvdo12/5CzNtNR7xLUtNtT3CGBQ6g3InjY720pvofUec22LJPr8PhEp2OMPyI40PdwWUdronCu9yQpdPx53bQlfLKnfOVhlnDYRBXve4Ov+IZTeMgdedm0NR+xoXJeQvdJ3CvziykSukwil16W/Oe7aGjIjqc/9ib4jQlJy0uArtN4A0+cvXFvDkmUJ47sJ1Y1ATLDNVXZkNPIepQzxy1ki9fqiwbUj/I+64zxWNzyZnPuhvohJ9K70VvXBixpcu2SAHU+Xd9EKdEJDNpYP3AQr3bQSpPQ6Y6/4dl1z7ZDbArsszjA7L0g7ibB0CDcidUWVoErvIMKZh2Xs0LUzcLW6V5NfiUgNEbaYmAVL6bXl0nJRc+1S72ua/D/cTjGPlQj7eUqd7A096rYlRjdPYlhz7VIvxpVG3cemDKF+WAwLY/6XelOZKTXXzsC4xvDjjtSN6kHLhLke6PrwM8h1raf40qjrGO7H9aTEbduucjS04ZrYU/4iuS5Z2Hdt0rvCLFdmLEXcU30AGddST62o+sLcf5l6k7CP+ru4pLYqX/VFyxbm/utQbx/r22ZEbTb2f5I2kns1Y1OQR8ZyofX+TjJxj1Rz7QQVnf1QzR26Oth0ueJVYcRP6ZUPac/Rx/5M6ixO1dhSrT3Y1DpiYmx3tF4ZUdpz9LD/dSg9PXES0LB71BwcGjKROuV28lnvnv7HHJsezheBGH5+X2CfSfRbMKW+5aGs3JFjMrjGibJc0S7TJzqjHrh2hDybj9XRXNZa89Aro55XBdbW5wti2c/5WJ7jJ1RolVUn/HWpb0I58Tziup6Rx7Dm2hnbRP1GM9PW/NFmQ4PtVRVN63Wvxfmu5sowDMMwDMMwDMMwDMMwDMMwDMMwzL+CpT//F/6beoV8zb2Jmt4Qryx6lTUCsENQ75HOkhXAO3EPVgyQtKtUy3C/e+FJg17Zjnew1Xrdb9InbG4WqfUAftG+WhLwPVyfg536+MU7m4C1CMk4ZznpXZzDYI1PDL2nS1hpvc5cNd7E2sJg05Fe7/7d3Fln8Cvc3bwB616auxsKl4WPghjemHrDqyDWeu1UNW5s2btPnSQ75oOdunEwWazfwgVG0kqluYCM9OIjWOGnfA2b9G4Ha63XKpvQ8perTvTifJNhi6+WMWmi7smEZf6G8MmhlyGq+NqP8GV84TLuJr7UIQVx+bDEoEpRZIz42gs40OuN4Mv8hXzelV7KX1isH+ewTWckikyVv+CfHuqVF7I16gN0VKypX6wPsE+zFPzkinolU9UH8OMGvSpnZqKsv13p/RsMun6X5x/y2LeAr8O66lsBwzBMP/wJfyGq8pgBk6IAAAAASUVORK5CYII=',
'this is my filename.png'
);
const msg = await client.sendMessage(remoteId, media, { sendMediaAsDocument: true});
expect(msg).to.be.instanceOf(Message);
expect(msg.type).to.equal(MessageTypes.DOCUMENT);
expect(msg.fromMe).to.equal(true);
expect(msg.hasMedia).to.equal(true);
expect(msg.body).to.equal('this is my filename.png');
expect(msg.to).to.equal(remoteId);
});
it('can send a sticker message', async function() {
const media = new MessageMedia(
'image/png',
'iVBORw0KGgoAAAANSUhEUgAAAV4AAACWBAMAAABkyf1EAAAAG1BMVEXMzMyWlpacnJyqqqrFxcWxsbGjo6O3t7e+vr6He3KoAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEcElEQVR4nO2aTW/bRhCGh18ij1zKknMkbbf2UXITIEeyMhIfRaF1exQLA/JRclslRykO+rs7s7s0VwytNmhJtsA8gHZEcox9PTs7uysQgGEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmGYr2OWRK/ReIKI8Zt7Hb19wTcQ0uTkGh13bQupcw7gPOvdo12/5CzNtNR7xLUtNtT3CGBQ6g3InjY720pvofUec22LJPr8PhEp2OMPyI40PdwWUdronCu9yQpdPx53bQlfLKnfOVhlnDYRBXve4Ov+IZTeMgdedm0NR+xoXJeQvdJ3CvziykSukwil16W/Oe7aGjIjqc/9ib4jQlJy0uArtN4A0+cvXFvDkmUJ47sJ1Y1ATLDNVXZkNPIepQzxy1ki9fqiwbUj/I+64zxWNzyZnPuhvohJ9K70VvXBixpcu2SAHU+Xd9EKdEJDNpYP3AQr3bQSpPQ6Y6/4dl1z7ZDbArsszjA7L0g7ibB0CDcidUWVoErvIMKZh2Xs0LUzcLW6V5NfiUgNEbaYmAVL6bXl0nJRc+1S72ua/D/cTjGPlQj7eUqd7A096rYlRjdPYlhz7VIvxpVG3cemDKF+WAwLY/6XelOZKTXXzsC4xvDjjtSN6kHLhLke6PrwM8h1raf40qjrGO7H9aTEbduucjS04ZrYU/4iuS5Z2Hdt0rvCLFdmLEXcU30AGddST62o+sLcf5l6k7CP+ru4pLYqX/VFyxbm/utQbx/r22ZEbTb2f5I2kns1Y1OQR8ZyofX+TjJxj1Rz7QQVnf1QzR26Oth0ueJVYcRP6ZUPac/Rx/5M6ixO1dhSrT3Y1DpiYmx3tF4ZUdpz9LD/dSg9PXES0LB71BwcGjKROuV28lnvnv7HHJsezheBGH5+X2CfSfRbMKW+5aGs3JFjMrjGibJc0S7TJzqjHrh2hDybj9XRXNZa89Aro55XBdbW5wti2c/5WJ7jJ1RolVUn/HWpb0I58Tziup6Rx7Dm2hnbRP1GM9PW/NFmQ4PtVRVN63Wvxfmu5sowDMMwDMMwDMMwDMMwDMMwDMMwzL+CpT//F/6beoV8zb2Jmt4Qryx6lTUCsENQ75HOkhXAO3EPVgyQtKtUy3C/e+FJg17Zjnew1Xrdb9InbG4WqfUAftG+WhLwPVyfg536+MU7m4C1CMk4ZznpXZzDYI1PDL2nS1hpvc5cNd7E2sJg05Fe7/7d3Fln8Cvc3bwB616auxsKl4WPghjemHrDqyDWeu1UNW5s2btPnSQ75oOdunEwWazfwgVG0kqluYCM9OIjWOGnfA2b9G4Ha63XKpvQ8perTvTifJNhi6+WMWmi7smEZf6G8MmhlyGq+NqP8GV84TLuJr7UIQVx+bDEoEpRZIz42gs40OuN4Mv8hXzelV7KX1isH+ewTWckikyVv+CfHuqVF7I16gN0VKypX6wPsE+zFPzkinolU9UH8OMGvSpnZqKsv13p/RsMun6X5x/y2LeAr8O66lsBwzBMP/wJfyGq8pgBk6IAAAAASUVORK5CYII='
);
const msg = await client.sendMessage(remoteId, media, {sendMediaAsSticker: true});
expect(msg).to.be.instanceOf(Message);
expect(msg.type).to.equal(MessageTypes.STICKER);
expect(msg.fromMe).to.equal(true);
expect(msg.hasMedia).to.equal(true);
expect(msg.to).to.equal(remoteId);
});
it('can send a sticker message with custom author and name', async function() {
const media = new MessageMedia(
'image/png',
'iVBORw0KGgoAAAANSUhEUgAAAV4AAACWBAMAAABkyf1EAAAAG1BMVEXMzMyWlpacnJyqqqrFxcWxsbGjo6O3t7e+vr6He3KoAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEcElEQVR4nO2aTW/bRhCGh18ij1zKknMkbbf2UXITIEeyMhIfRaF1exQLA/JRclslRykO+rs7s7s0VwytNmhJtsA8gHZEcox9PTs7uysQgGEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmGYr2OWRK/ReIKI8Zt7Hb19wTcQ0uTkGh13bQupcw7gPOvdo12/5CzNtNR7xLUtNtT3CGBQ6g3InjY720pvofUec22LJPr8PhEp2OMPyI40PdwWUdronCu9yQpdPx53bQlfLKnfOVhlnDYRBXve4Ov+IZTeMgdedm0NR+xoXJeQvdJ3CvziykSukwil16W/Oe7aGjIjqc/9ib4jQlJy0uArtN4A0+cvXFvDkmUJ47sJ1Y1ATLDNVXZkNPIepQzxy1ki9fqiwbUj/I+64zxWNzyZnPuhvohJ9K70VvXBixpcu2SAHU+Xd9EKdEJDNpYP3AQr3bQSpPQ6Y6/4dl1z7ZDbArsszjA7L0g7ibB0CDcidUWVoErvIMKZh2Xs0LUzcLW6V5NfiUgNEbaYmAVL6bXl0nJRc+1S72ua/D/cTjGPlQj7eUqd7A096rYlRjdPYlhz7VIvxpVG3cemDKF+WAwLY/6XelOZKTXXzsC4xvDjjtSN6kHLhLke6PrwM8h1raf40qjrGO7H9aTEbduucjS04ZrYU/4iuS5Z2Hdt0rvCLFdmLEXcU30AGddST62o+sLcf5l6k7CP+ru4pLYqX/VFyxbm/utQbx/r22ZEbTb2f5I2kns1Y1OQR8ZyofX+TjJxj1Rz7QQVnf1QzR26Oth0ueJVYcRP6ZUPac/Rx/5M6ixO1dhSrT3Y1DpiYmx3tF4ZUdpz9LD/dSg9PXES0LB71BwcGjKROuV28lnvnv7HHJsezheBGH5+X2CfSfRbMKW+5aGs3JFjMrjGibJc0S7TJzqjHrh2hDybj9XRXNZa89Aro55XBdbW5wti2c/5WJ7jJ1RolVUn/HWpb0I58Tziup6Rx7Dm2hnbRP1GM9PW/NFmQ4PtVRVN63Wvxfmu5sowDMMwDMMwDMMwDMMwDMMwDMMwzL+CpT//F/6beoV8zb2Jmt4Qryx6lTUCsENQ75HOkhXAO3EPVgyQtKtUy3C/e+FJg17Zjnew1Xrdb9InbG4WqfUAftG+WhLwPVyfg536+MU7m4C1CMk4ZznpXZzDYI1PDL2nS1hpvc5cNd7E2sJg05Fe7/7d3Fln8Cvc3bwB616auxsKl4WPghjemHrDqyDWeu1UNW5s2btPnSQ75oOdunEwWazfwgVG0kqluYCM9OIjWOGnfA2b9G4Ha63XKpvQ8perTvTifJNhi6+WMWmi7smEZf6G8MmhlyGq+NqP8GV84TLuJr7UIQVx+bDEoEpRZIz42gs40OuN4Mv8hXzelV7KX1isH+ewTWckikyVv+CfHuqVF7I16gN0VKypX6wPsE+zFPzkinolU9UH8OMGvSpnZqKsv13p/RsMun6X5x/y2LeAr8O66lsBwzBMP/wJfyGq8pgBk6IAAAAASUVORK5CYII='
);
const msg = await client.sendMessage(remoteId, media, {
sendMediaAsSticker: true,
stickerAuthor: 'WWEBJS',
stickerName: 'My Sticker'
});
expect(msg).to.be.instanceOf(Message);
expect(msg.type).to.equal(MessageTypes.STICKER);
expect(msg.fromMe).to.equal(true);
expect(msg.hasMedia).to.equal(true);
expect(msg.to).to.equal(remoteId);
});
it('can send a location message', async function() {
const location = new Location(37.422, -122.084, 'Googleplex\nGoogle Headquarters');
const msg = await client.sendMessage(remoteId, location);
expect(msg).to.be.instanceOf(Message);
expect(msg.type).to.equal(MessageTypes.LOCATION);
expect(msg.fromMe).to.equal(true);
expect(msg.to).to.equal(remoteId);
expect(msg.location).to.be.instanceOf(Location);
expect(msg.location.latitude).to.equal(37.422);
expect(msg.location.longitude).to.equal(-122.084);
expect(msg.location.description).to.equal('Googleplex\nGoogle Headquarters');
});
it('can send a vCard as a contact card message', async function() {
const vCard = `BEGIN:VCARD
VERSION:3.0
FN;CHARSET=UTF-8:John Doe
N;CHARSET=UTF-8:Doe;John;;;
EMAIL;CHARSET=UTF-8;type=HOME,INTERNET:john@doe.com
TEL;TYPE=HOME,VOICE:1234567890
REV:2021-06-06T02:35:53.559Z
END:VCARD`;
const msg = await client.sendMessage(remoteId, vCard);
expect(msg).to.be.instanceOf(Message);
expect(msg.type).to.equal(MessageTypes.CONTACT_CARD);
expect(msg.fromMe).to.equal(true);
expect(msg.to).to.equal(remoteId);
expect(msg.body).to.equal(vCard);
expect(msg.vCards).to.have.lengthOf(1);
expect(msg.vCards[0]).to.equal(vCard);
});
it('can optionally turn off vCard parsing', async function() {
const vCard = `BEGIN:VCARD
VERSION:3.0
FN;CHARSET=UTF-8:John Doe
N;CHARSET=UTF-8:Doe;John;;;
EMAIL;CHARSET=UTF-8;type=HOME,INTERNET:john@doe.com
TEL;TYPE=HOME,VOICE:1234567890
REV:2021-06-06T02:35:53.559Z
END:VCARD`;
const msg = await client.sendMessage(remoteId, vCard, {parseVCards: false});
expect(msg).to.be.instanceOf(Message);
expect(msg.type).to.equal(MessageTypes.TEXT); // not a contact card
expect(msg.fromMe).to.equal(true);
expect(msg.to).to.equal(remoteId);
expect(msg.body).to.equal(vCard);
});
it('can send a Contact as a contact card message', async function() {
const contact = await client.getContactById(remoteId);
const msg = await client.sendMessage(remoteId, contact);
expect(msg).to.be.instanceOf(Message);
expect(msg.type).to.equal(MessageTypes.CONTACT_CARD);
expect(msg.fromMe).to.equal(true);
expect(msg.to).to.equal(remoteId);
expect(msg.body).to.match(/BEGIN:VCARD/);
expect(msg.vCards).to.have.lengthOf(1);
expect(msg.vCards[0]).to.match(/BEGIN:VCARD/);
});
it('can send multiple Contacts as a contact card message', async function () {
const contact1 = await client.getContactById(remoteId);
const contact2 = await client.getContactById('5511942167462@c.us'); //iFood
const msg = await client.sendMessage(remoteId, [contact1, contact2]);
expect(msg).to.be.instanceOf(Message);
expect(msg.type).to.equal(MessageTypes.CONTACT_CARD_MULTI);
expect(msg.fromMe).to.equal(true);
expect(msg.to).to.equal(remoteId);
expect(msg.vCards).to.have.lengthOf(2);
expect(msg.vCards[0]).to.match(/BEGIN:VCARD/);
expect(msg.vCards[1]).to.match(/BEGIN:VCARD/);
});
});
describe('Get Chats', function () {
it('can get a chat by its ID', async function () {
const chat = await client.getChatById(remoteId);
expect(chat).to.be.instanceOf(Chat);
expect(chat.id._serialized).to.eql(remoteId);
expect(chat.isGroup).to.eql(false);
});
it('can get all chats', async function () {
const chats = await client.getChats();
expect(chats.length).to.be.greaterThanOrEqual(1);
const chat = chats.find(c => c.id._serialized === remoteId);
expect(chat).to.exist;
expect(chat).to.be.instanceOf(Chat);
});
});
describe('Get Contacts', function () {
it('can get a contact by its ID', async function () {
const contact = await client.getContactById(remoteId);
expect(contact).to.be.instanceOf(Contact);
expect(contact.id._serialized).to.eql(remoteId);
expect(contact.number).to.eql(remoteId.split('@')[0]);
});
it('can get all contacts', async function () {
const contacts = await client.getContacts();
expect(contacts.length).to.be.greaterThanOrEqual(1);
const contact = contacts.find(c => c.id._serialized === remoteId);
expect(contact).to.exist;
expect(contact).to.be.instanceOf(Contact);
});
it('can block a contact', async function () {
const contact = await client.getContactById(remoteId);
await contact.block();
const refreshedContact = await client.getContactById(remoteId);
expect(refreshedContact.isBlocked).to.eql(true);
});
it('can get a list of blocked contacts', async function () {
const blockedContacts = await client.getBlockedContacts();
expect(blockedContacts.length).to.be.greaterThanOrEqual(1);
const contact = blockedContacts.find(c => c.id._serialized === remoteId);
expect(contact).to.exist;
expect(contact).to.be.instanceOf(Contact);
});
it('can unblock a contact', async function () {
const contact = await client.getContactById(remoteId);
await contact.unblock();
const refreshedContact = await client.getContactById(remoteId);
expect(refreshedContact.isBlocked).to.eql(false);
});
});
describe('Numbers and Users', function () {
it('can verify that a user is registered', async function () {
const isRegistered = await client.isRegisteredUser(remoteId);
expect(isRegistered).to.be.true;
});
it('can verify that a user is not registered', async function () {
const isRegistered = await client.isRegisteredUser('9999999999@c.us');
expect(isRegistered).to.be.false;
});
it('can get a number\'s whatsapp id', async function () {
const number = remoteId.split('@')[0];
const numberId = await client.getNumberId(number);
expect(numberId).to.eql({
server: 'c.us',
user: number,
_serialized: `${number}@c.us`
});
});
it('returns null when getting an unregistered number\'s whatsapp id', async function () {
const number = '9999999999';
const numberId = await client.getNumberId(number);
expect(numberId).to.eql(null);
});
it('can get a number\'s country code', async function () {
const number = '18092201111';
const countryCode = await client.getCountryCode(number);
expect(countryCode).to.eql('1');
});
it('can get a formatted number', async function () {
const number = '18092201111';
const formatted = await client.getFormattedNumber(number);
expect(formatted).to.eql('+1 (809) 220-1111');
});
it('can get a formatted number from a serialized ID', async function () {
const number = '18092201111@c.us';
const formatted = await client.getFormattedNumber(number);
expect(formatted).to.eql('+1 (809) 220-1111');
});
});
describe('Search messages', function () {
it('can search for messages', async function () {
this.timeout(5000);
const m1 = await client.sendMessage(remoteId, 'I\'m searching for Super Mario Brothers');
const m2 = await client.sendMessage(remoteId, 'This also contains Mario');
const m3 = await client.sendMessage(remoteId, 'Nothing of interest here, just Luigi');
// wait for search index to catch up
await helper.sleep(1000);
const msgs = await client.searchMessages('Mario', {chatId: remoteId});
expect(msgs.length).to.be.greaterThanOrEqual(2);
const msgIds = msgs.map(m => m.id._serialized);
expect(msgIds).to.include.members([
m1.id._serialized, m2.id._serialized
]);
expect(msgIds).to.not.include.members([m3.id._serialized]);
});
});
describe('Status/About', function () {
let me, previousStatus;
before(async function () {
me = await client.getContactById(client.info.wid._serialized);
previousStatus = await me.getAbout();
});
after(async function () {
await client.setStatus(previousStatus);
});
it('can set the status text', async function () {
await client.setStatus('My shiny new status');
const status = await me.getAbout();
expect(status).to.eql('My shiny new status');
});
it('can set the status text to something else', async function () {
await client.setStatus('Busy');
const status = await me.getAbout();
expect(status).to.eql('Busy');
});
});
});
});

40
tests/helper.js Normal file
View File

@@ -0,0 +1,40 @@
const path = require('path');
const Client = require('../src/Client');
const Util = require('../src/util/Util');
require('dotenv').config();
const remoteId = process.env.WWEBJS_TEST_REMOTE_ID;
if(!remoteId) throw new Error('The WWEBJS_TEST_REMOTE_ID environment variable has not been set.');
function getSessionFromEnv() {
const envSession = process.env.WWEBJS_TEST_SESSION;
if(envSession) return JSON.parse(envSession);
const envSessionPath = process.env.WWEBJS_TEST_SESSION_PATH;
if(envSessionPath) {
const absPath = path.resolve(process.cwd(), envSessionPath);
return require(absPath);
}
throw new Error('No session found in environment.');
}
function createClient({withSession, options: additionalOpts}={}) {
const options = {};
if(withSession) {
options.session = getSessionFromEnv();
}
return new Client(Util.mergeDefault(options, additionalOpts || {}));
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
module.exports = {
sleep,
createClient,
remoteId
};

188
tests/structures/chat.js Normal file
View File

@@ -0,0 +1,188 @@
const { expect } = require('chai');
const helper = require('../helper');
const Message = require('../../src/structures/Message');
const { MessageTypes } = require('../../src/util/Constants');
const { Contact } = require('../../src/structures');
const remoteId = helper.remoteId;
describe('Chat', function () {
let client;
let chat;
before(async function() {
this.timeout(35000);
client = helper.createClient({ withSession: true });
await client.initialize();
chat = await client.getChatById(remoteId);
});
after(async function () {
await client.destroy();
});
it('can send a message to a chat', async function () {
const msg = await chat.sendMessage('hello world');
expect(msg).to.be.instanceOf(Message);
expect(msg.type).to.equal(MessageTypes.TEXT);
expect(msg.fromMe).to.equal(true);
expect(msg.body).to.equal('hello world');
expect(msg.to).to.equal(remoteId);
});
it('can fetch messages sent in a chat', async function () {
this.timeout(5000);
await helper.sleep(1000);
const msg = await chat.sendMessage('another message');
const messages = await chat.fetchMessages();
expect(messages.length).to.be.greaterThanOrEqual(2);
const fetchedMsg = messages[messages.length-1];
expect(fetchedMsg).to.be.instanceOf(Message);
expect(fetchedMsg.type).to.equal(MessageTypes.TEXT);
expect(fetchedMsg.id._serialized).to.equal(msg.id._serialized);
expect(fetchedMsg.body).to.equal(msg.body);
});
it('can use a limit when fetching messages sent in a chat', async function () {
await helper.sleep(1000);
const msg = await chat.sendMessage('yet another message');
const messages = await chat.fetchMessages({limit: 1});
expect(messages).to.have.lengthOf(1);
const fetchedMsg = messages[0];
expect(fetchedMsg).to.be.instanceOf(Message);
expect(fetchedMsg.type).to.equal(MessageTypes.TEXT);
expect(fetchedMsg.id._serialized).to.equal(msg.id._serialized);
expect(fetchedMsg.body).to.equal(msg.body);
});
it('can get the related contact', async function () {
const contact = await chat.getContact();
expect(contact).to.be.instanceOf(Contact);
expect(contact.id._serialized).to.equal(chat.id._serialized);
});
describe('Seen', function () {
it('can mark a chat as unread', async function () {
await chat.markUnread();
await helper.sleep(500);
// refresh chat
chat = await client.getChatById(remoteId);
expect(chat.unreadCount).to.equal(-1);
});
it('can mark a chat as seen', async function () {
const res = await chat.sendSeen();
expect(res).to.equal(true);
// refresh chat
chat = await client.getChatById(remoteId);
expect(chat.unreadCount).to.equal(0);
});
});
describe('Archiving', function (){
it('can archive a chat', async function () {
const res = await chat.archive();
expect(res).to.equal(true);
await helper.sleep(1000);
// refresh chat
chat = await client.getChatById(remoteId);
expect(chat.archived).to.equal(true);
});
it('can unarchive a chat', async function () {
const res = await chat.unarchive();
expect(res).to.equal(false);
await helper.sleep(1000);
// refresh chat
chat = await client.getChatById(remoteId);
expect(chat.archived).to.equal(false);
});
});
describe('Pinning', function () {
it('can pin a chat', async function () {
const res = await chat.pin();
expect(res).to.equal(true);
await helper.sleep(1000);
// refresh chat
chat = await client.getChatById(remoteId);
expect(chat.pinned).to.equal(true);
});
it('can unpin a chat', async function () {
const res = await chat.unpin();
expect(res).to.equal(false);
await helper.sleep(1000);
// refresh chat
chat = await client.getChatById(remoteId);
expect(chat.pinned).to.equal(false);
});
});
describe('Muting', function () {
it('can mute a chat forever', async function() {
await chat.mute();
// refresh chat
chat = await client.getChatById(remoteId);
expect(chat.isMuted).to.equal(true);
expect(chat.muteExpiration).to.equal(-1);
});
it('can mute a chat until a specific date', async function() {
const unmuteDate = new Date(new Date().getTime() + (1000*60*60));
await chat.mute(unmuteDate);
// refresh chat
chat = await client.getChatById(remoteId);
expect(chat.isMuted).to.equal(true);
expect(chat.muteExpiration).to.equal(
Math.round(unmuteDate.getTime() / 1000)
);
});
it('can unmute a chat', async function () {
await chat.unmute();
await helper.sleep(500);
// refresh chat
chat = await client.getChatById(remoteId);
expect(chat.isMuted).to.equal(false);
expect(chat.muteExpiration).to.equal(0);
});
});
// eslint-disable-next-line mocha/no-skipped-tests
describe.skip('Destructive operations', function () {
it('can clear all messages from chat', async function () {
this.timeout(5000);
const res = await chat.clearMessages();
expect(res).to.equal(true);
await helper.sleep(3000);
const msgs = await chat.fetchMessages();
expect(msgs).to.have.lengthOf(0);
});
it('can delete a chat', async function () {
const res = await chat.delete();
expect(res).to.equal(true);
});
});
});

4
tools/changelog.sh Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/sh
LAST_TAG=$(git describe --tags --abbrev=0)
git log --pretty="%h - %s" "$LAST_TAG"..HEAD

View File

@@ -0,0 +1 @@
2.2204.13

View File

@@ -0,0 +1,46 @@
#!/usr/bin/env node
const fs = require('fs');
const fetch = require('node-fetch');
const getLatestVersion = async (currentVersion) => {
const res = await fetch(`https://web.whatsapp.com/check-update?version=${currentVersion}&platform=web`);
const data = await res.json();
return data.currentVersion;
};
const getCurrentVersion = () => {
try {
const versionFile = fs.readFileSync('./.version');
return versionFile ? versionFile.toString().trim() : null;
} catch(_) {
return null;
}
};
const updateVersion = async (oldVersion, newVersion) => {
const readmePath = '../../README.md';
const readme = fs.readFileSync(readmePath);
const newReadme = readme.toString().replaceAll(oldVersion, newVersion);
fs.writeFileSync(readmePath, newReadme);
fs.writeFileSync('./.version', newVersion);
};
(async () => {
const currentVersion = getCurrentVersion();
const version = await getLatestVersion(currentVersion);
console.log(`Current version: ${currentVersion}`);
console.log(`Latest version: ${version}`);
if(currentVersion !== version) {
console.log('Updating files...');
await updateVersion(currentVersion, version);
console.log('Updated!');
} else {
console.log('No changes.');
}
})();