yt-dlp support
This commit is contained in:
3
node_modules/whatsapp-web.js/.env.example
generated
vendored
Normal file
3
node_modules/whatsapp-web.js/.env.example
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
WWEBJS_TEST_REMOTE_ID=XXXXXXXXXX@c.us
|
||||
WWEBJS_TEST_CLIENT_ID=authenticated
|
||||
WWEBJS_TEST_MD=1
|
||||
133
node_modules/whatsapp-web.js/CODE_OF_CONDUCT.md
generated
vendored
Normal file
133
node_modules/whatsapp-web.js/CODE_OF_CONDUCT.md
generated
vendored
Normal 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
|
||||
201
node_modules/whatsapp-web.js/LICENSE
generated
vendored
Normal file
201
node_modules/whatsapp-web.js/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2019 Pedro S Lopez
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
155
node_modules/whatsapp-web.js/README.md
generated
vendored
Normal file
155
node_modules/whatsapp-web.js/README.md
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
<div align="center">
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://wwebjs.dev"><img src="https://github.com/wwebjs/assets/blob/main/Collection/GitHub/wwebjs.png?raw=true" title="whatsapp-web.js" alt="WWebJS Website" width="500" /></a>
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://www.npmjs.com/package/whatsapp-web.js"><img src="https://img.shields.io/npm/v/whatsapp-web.js.svg" alt="npm" /></a>
|
||||
<a href="https://depfu.com/github/pedroslopez/whatsapp-web.js?project_id=9765"><img src="https://badges.depfu.com/badges/4a65a0de96ece65fdf39e294e0c8dcba/overview.svg" alt="Depfu" /></a>
|
||||
<img src="https://img.shields.io/badge/WhatsApp_Web-2.3000.1017054665-brightgreen.svg" alt="WhatsApp_Web 2.2346.52" />
|
||||
<a href="https://discord.gg/H7DqQs4"><img src="https://img.shields.io/discord/698610475432411196.svg?logo=discord" alt="Discord server" /></a>
|
||||
</p>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
## About
|
||||
**A WhatsApp API client that operates via the WhatsApp Web browser.**
|
||||
|
||||
The library launches the WhatsApp Web browser app via Puppeteer, accessing its internal functions and creating a managed instance to reduce the risk of being blocked. This gives the API client nearly all WhatsApp Web features for dynamic use in a Node.js application.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **It is not guaranteed you will not be blocked by using this method. WhatsApp does not allow bots or unofficial clients on their platform, so this shouldn't be considered totally safe.**
|
||||
|
||||
## Links
|
||||
|
||||
* [GitHub][gitHub]
|
||||
* [Guide][guide] ([source][guide-source])
|
||||
* [Documentation][documentation] ([source][documentation-source])
|
||||
* [Discord Server][discord]
|
||||
* [npm][npm]
|
||||
|
||||
## Installation
|
||||
|
||||
The module is available on [npm][npm] via `npm i whatsapp-web.js`!
|
||||
|
||||
> [!NOTE]
|
||||
> **Node ``v18`` or higher, is required.**
|
||||
> See the [Guide][guide] for quick upgrade instructions.
|
||||
|
||||
## Example usage
|
||||
|
||||
```js
|
||||
const { Client } = require('whatsapp-web.js');
|
||||
|
||||
const client = new Client();
|
||||
|
||||
client.on('qr', (qr) => {
|
||||
// Generate and scan this code with your phone
|
||||
console.log('QR RECEIVED', qr);
|
||||
});
|
||||
|
||||
client.on('ready', () => {
|
||||
console.log('Client is ready!');
|
||||
});
|
||||
|
||||
client.on('message', msg => {
|
||||
if (msg.body == '!ping') {
|
||||
msg.reply('pong');
|
||||
}
|
||||
});
|
||||
|
||||
client.initialize();
|
||||
```
|
||||
|
||||
Take a look at [example.js][examples] for another examples with additional use cases.
|
||||
For further details on saving and restoring sessions, explore the provided [Authentication Strategies][auth-strategies].
|
||||
|
||||
|
||||
## Supported features
|
||||
|
||||
| Feature | Status |
|
||||
| ------------- | ------------- |
|
||||
| Multi Device | ✅ |
|
||||
| Send messages | ✅ |
|
||||
| Receive messages | ✅ |
|
||||
| Send media (images/audio/documents) | ✅ |
|
||||
| Send media (video) | ✅ [(requires Google Chrome)][google-chrome] |
|
||||
| Send stickers | ✅ |
|
||||
| Receive media (images/audio/video/documents) | ✅ |
|
||||
| Send contact cards | ✅ |
|
||||
| Send location | ✅ |
|
||||
| Send buttons | ❌ [(DEPRECATED)][deprecated-video] |
|
||||
| Send lists | ❌ [(DEPRECATED)][deprecated-video] |
|
||||
| Receive location | ✅ |
|
||||
| Message replies | ✅ |
|
||||
| Join groups by invite | ✅ |
|
||||
| Get invite for group | ✅ |
|
||||
| Modify group info (subject, description) | ✅ |
|
||||
| Modify group settings (send messages, edit info) | ✅ |
|
||||
| Add group participants | ✅ |
|
||||
| Kick group participants | ✅ |
|
||||
| Promote/demote group participants | ✅ |
|
||||
| Mention users | ✅ |
|
||||
| Mention groups | ✅ |
|
||||
| Mute/unmute chats | ✅ |
|
||||
| Block/unblock contacts | ✅ |
|
||||
| Get contact info | ✅ |
|
||||
| Get profile pictures | ✅ |
|
||||
| Set user status message | ✅ |
|
||||
| React to messages | ✅ |
|
||||
| Create polls | ✅ |
|
||||
| Channels | ✅ |
|
||||
| Vote in polls | 🔜 |
|
||||
| Communities | 🔜 |
|
||||
|
||||
Something missing? Make an issue and let us know!
|
||||
|
||||
## Contributing
|
||||
|
||||
Feel free to open pull requests; we welcome contributions! However, for significant changes, it's best to open an issue beforehand. Make sure to review our [contribution guidelines][contributing] before creating a pull request. Before creating your own issue or pull request, always check to see if one already exists!
|
||||
|
||||
## Supporting the project
|
||||
|
||||
You can support the maintainer of this project through the links below
|
||||
|
||||
- [Support via GitHub Sponsors][gitHub-sponsors]
|
||||
- [Support via PayPal][support-payPal]
|
||||
- [Sign up for DigitalOcean][digitalocean] and get $200 in credit when you sign up (Referral)
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This project is not affiliated, associated, authorized, endorsed by, or in any way officially connected with WhatsApp or any of its subsidiaries or its affiliates. The official WhatsApp website can be found at [whatsapp.com][whatsapp]. "WhatsApp" as well as related names, marks, emblems and images are registered trademarks of their respective owners. Also it is not guaranteed you will not be blocked by using this method. WhatsApp does not allow bots or unofficial clients on their platform, so this shouldn't be considered totally safe.
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2019 Pedro S Lopez
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this project except in compliance with the License.
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
[guide]: https://guide.wwebjs.dev/guide
|
||||
[guide-source]: https://github.com/wwebjs/wwebjs.dev/tree/main
|
||||
[documentation]: https://docs.wwebjs.dev/
|
||||
[documentation-source]: https://github.com/pedroslopez/whatsapp-web.js/tree/main/docs
|
||||
[discord]: https://discord.gg/H7DqQs4
|
||||
[gitHub]: https://github.com/pedroslopez/whatsapp-web.js
|
||||
[npm]: https://npmjs.org/package/whatsapp-web.js
|
||||
[nodejs]: https://nodejs.org/en/download/
|
||||
[examples]: https://github.com/pedroslopez/whatsapp-web.js/blob/master/example.js
|
||||
[auth-strategies]: https://wwebjs.dev/guide/creating-your-bot/authentication.html
|
||||
[google-chrome]: https://wwebjs.dev/guide/creating-your-bot/handling-attachments.html#caveat-for-sending-videos-and-gifs
|
||||
[deprecated-video]: https://www.youtube.com/watch?v=hv1R1rLeVVE
|
||||
[gitHub-sponsors]: https://github.com/sponsors/pedroslopez
|
||||
[support-payPal]: https://www.paypal.me/psla/
|
||||
[digitalocean]: https://m.do.co/c/73f906a36ed4
|
||||
[contributing]: https://github.com/pedroslopez/whatsapp-web.js/blob/main/CODE_OF_CONDUCT.md
|
||||
[whatsapp]: https://whatsapp.com
|
||||
706
node_modules/whatsapp-web.js/example.js
generated
vendored
Normal file
706
node_modules/whatsapp-web.js/example.js
generated
vendored
Normal file
@@ -0,0 +1,706 @@
|
||||
const { Client, Location, Poll, List, Buttons, LocalAuth } = require('./index');
|
||||
|
||||
const client = new Client({
|
||||
authStrategy: new LocalAuth(),
|
||||
// proxyAuthentication: { username: 'username', password: 'password' },
|
||||
/**
|
||||
* This option changes the browser name from defined in user agent to custom.
|
||||
*/
|
||||
// deviceName: 'Your custom name',
|
||||
/**
|
||||
* This option changes browser type from defined in user agent to yours. It affects the browser icon
|
||||
* that is displayed in 'linked devices' section.
|
||||
* Valid value are: 'Chrome' | 'Firefox' | 'IE' | 'Opera' | 'Safari' | 'Edge'.
|
||||
* If another value is provided, the browser icon in 'linked devices' section will be gray.
|
||||
*/
|
||||
// browserName: 'Firefox',
|
||||
puppeteer: {
|
||||
// args: ['--proxy-server=proxy-server-that-requires-authentication.example.com'],
|
||||
headless: false,
|
||||
},
|
||||
// pairWithPhoneNumber: {
|
||||
// phoneNumber: '96170100100' // Pair with phone number (format: <COUNTRY_CODE><PHONE_NUMBER>)
|
||||
// showNotification: true,
|
||||
// intervalMs: 180000 // Time to renew pairing code in milliseconds, defaults to 3 minutes
|
||||
// }
|
||||
});
|
||||
|
||||
// client initialize does not finish at ready now.
|
||||
client.initialize();
|
||||
|
||||
client.on('loading_screen', (percent, message) => {
|
||||
console.log('LOADING SCREEN', percent, message);
|
||||
});
|
||||
|
||||
client.on('qr', async (qr) => {
|
||||
// NOTE: This event will not be fired if a session is specified.
|
||||
console.log('QR RECEIVED', qr);
|
||||
});
|
||||
|
||||
client.on('code', (code) => {
|
||||
console.log('Pairing code:',code);
|
||||
});
|
||||
|
||||
client.on('authenticated', () => {
|
||||
console.log('AUTHENTICATED');
|
||||
});
|
||||
|
||||
client.on('auth_failure', msg => {
|
||||
// Fired if session restore was unsuccessful
|
||||
console.error('AUTHENTICATION FAILURE', msg);
|
||||
});
|
||||
|
||||
client.on('ready', async () => {
|
||||
console.log('READY');
|
||||
const debugWWebVersion = await client.getWWebVersion();
|
||||
console.log(`WWebVersion = ${debugWWebVersion}`);
|
||||
|
||||
client.pupPage.on('pageerror', function(err) {
|
||||
console.log('Page error: ' + err.toString());
|
||||
});
|
||||
client.pupPage.on('error', function(err) {
|
||||
console.log('Page error: ' + err.toString());
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
client.on('message', async msg => {
|
||||
console.log('MESSAGE RECEIVED', msg);
|
||||
|
||||
if (msg.body === '!ping reply') {
|
||||
// Send a new message as a reply to the current one
|
||||
msg.reply('pong');
|
||||
|
||||
} else if (msg.body === '!ping') {
|
||||
// Send a new message to the same chat
|
||||
client.sendMessage(msg.from, 'pong');
|
||||
|
||||
} else if (msg.body.startsWith('!sendto ')) {
|
||||
// Direct send a new message to specific id
|
||||
let number = msg.body.split(' ')[1];
|
||||
let messageIndex = msg.body.indexOf(number) + number.length;
|
||||
let message = msg.body.slice(messageIndex, msg.body.length);
|
||||
number = number.includes('@c.us') ? number : `${number}@c.us`;
|
||||
let chat = await msg.getChat();
|
||||
chat.sendSeen();
|
||||
client.sendMessage(number, message);
|
||||
|
||||
} else if (msg.body.startsWith('!subject ')) {
|
||||
// Change the group subject
|
||||
let chat = await msg.getChat();
|
||||
if (chat.isGroup) {
|
||||
let newSubject = msg.body.slice(9);
|
||||
chat.setSubject(newSubject);
|
||||
} else {
|
||||
msg.reply('This command can only be used in a group!');
|
||||
}
|
||||
} else if (msg.body.startsWith('!echo ')) {
|
||||
// Replies with the same message
|
||||
msg.reply(msg.body.slice(6));
|
||||
} else if (msg.body.startsWith('!preview ')) {
|
||||
const text = msg.body.slice(9);
|
||||
msg.reply(text, null, { linkPreview: true });
|
||||
} else if (msg.body.startsWith('!desc ')) {
|
||||
// Change the group description
|
||||
let chat = await msg.getChat();
|
||||
if (chat.isGroup) {
|
||||
let newDescription = msg.body.slice(6);
|
||||
chat.setDescription(newDescription);
|
||||
} else {
|
||||
msg.reply('This command can only be used in a group!');
|
||||
}
|
||||
} else if (msg.body === '!leave') {
|
||||
// Leave the group
|
||||
let chat = await msg.getChat();
|
||||
if (chat.isGroup) {
|
||||
chat.leave();
|
||||
} else {
|
||||
msg.reply('This command can only be used in a group!');
|
||||
}
|
||||
} else if (msg.body.startsWith('!join ')) {
|
||||
const inviteCode = msg.body.split(' ')[1];
|
||||
try {
|
||||
await client.acceptInvite(inviteCode);
|
||||
msg.reply('Joined the group!');
|
||||
} catch (e) {
|
||||
msg.reply('That invite code seems to be invalid.');
|
||||
}
|
||||
} else if (msg.body.startsWith('!addmembers')) {
|
||||
const group = await msg.getChat();
|
||||
const result = await group.addParticipants(['number1@c.us', 'number2@c.us', 'number3@c.us']);
|
||||
/**
|
||||
* The example of the {@link result} output:
|
||||
*
|
||||
* {
|
||||
* 'number1@c.us': {
|
||||
* code: 200,
|
||||
* message: 'The participant was added successfully',
|
||||
* isInviteV4Sent: false
|
||||
* },
|
||||
* 'number2@c.us': {
|
||||
* code: 403,
|
||||
* message: 'The participant can be added by sending private invitation only',
|
||||
* isInviteV4Sent: true
|
||||
* },
|
||||
* 'number3@c.us': {
|
||||
* code: 404,
|
||||
* message: 'The phone number is not registered on WhatsApp',
|
||||
* isInviteV4Sent: false
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* For more usage examples:
|
||||
* @see https://github.com/pedroslopez/whatsapp-web.js/pull/2344#usage-example1
|
||||
*/
|
||||
console.log(result);
|
||||
} else if (msg.body === '!creategroup') {
|
||||
const partitipantsToAdd = ['number1@c.us', 'number2@c.us', 'number3@c.us'];
|
||||
const result = await client.createGroup('Group Title', partitipantsToAdd);
|
||||
/**
|
||||
* The example of the {@link result} output:
|
||||
* {
|
||||
* title: 'Group Title',
|
||||
* gid: {
|
||||
* server: 'g.us',
|
||||
* user: '1111111111',
|
||||
* _serialized: '1111111111@g.us'
|
||||
* },
|
||||
* participants: {
|
||||
* 'botNumber@c.us': {
|
||||
* statusCode: 200,
|
||||
* message: 'The participant was added successfully',
|
||||
* isGroupCreator: true,
|
||||
* isInviteV4Sent: false
|
||||
* },
|
||||
* 'number1@c.us': {
|
||||
* statusCode: 200,
|
||||
* message: 'The participant was added successfully',
|
||||
* isGroupCreator: false,
|
||||
* isInviteV4Sent: false
|
||||
* },
|
||||
* 'number2@c.us': {
|
||||
* statusCode: 403,
|
||||
* message: 'The participant can be added by sending private invitation only',
|
||||
* isGroupCreator: false,
|
||||
* isInviteV4Sent: true
|
||||
* },
|
||||
* 'number3@c.us': {
|
||||
* statusCode: 404,
|
||||
* message: 'The phone number is not registered on WhatsApp',
|
||||
* isGroupCreator: false,
|
||||
* isInviteV4Sent: false
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* For more usage examples:
|
||||
* @see https://github.com/pedroslopez/whatsapp-web.js/pull/2344#usage-example2
|
||||
*/
|
||||
console.log(result);
|
||||
} else if (msg.body === '!groupinfo') {
|
||||
let chat = await msg.getChat();
|
||||
if (chat.isGroup) {
|
||||
msg.reply(`
|
||||
*Group Details*
|
||||
Name: ${chat.name}
|
||||
Description: ${chat.description}
|
||||
Created At: ${chat.createdAt.toString()}
|
||||
Created By: ${chat.owner.user}
|
||||
Participant count: ${chat.participants.length}
|
||||
`);
|
||||
} else {
|
||||
msg.reply('This command can only be used in a group!');
|
||||
}
|
||||
} 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') {
|
||||
let info = client.info;
|
||||
client.sendMessage(msg.from, `
|
||||
*Connection info*
|
||||
User name: ${info.pushname}
|
||||
My number: ${info.wid.user}
|
||||
Platform: ${info.platform}
|
||||
`);
|
||||
} else if (msg.body === '!mediainfo' && msg.hasMedia) {
|
||||
const attachmentData = await msg.downloadMedia();
|
||||
msg.reply(`
|
||||
*Media info*
|
||||
MimeType: ${attachmentData.mimetype}
|
||||
Filename: ${attachmentData.filename}
|
||||
Data (length): ${attachmentData.data.length}
|
||||
`);
|
||||
} else if (msg.body === '!quoteinfo' && msg.hasQuotedMsg) {
|
||||
const quotedMsg = await msg.getQuotedMessage();
|
||||
|
||||
quotedMsg.reply(`
|
||||
ID: ${quotedMsg.id._serialized}
|
||||
Type: ${quotedMsg.type}
|
||||
Author: ${quotedMsg.author || quotedMsg.from}
|
||||
Timestamp: ${quotedMsg.timestamp}
|
||||
Has Media? ${quotedMsg.hasMedia}
|
||||
`);
|
||||
} 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.' });
|
||||
}
|
||||
if (quotedMsg.hasMedia && quotedMsg.type === 'audio') {
|
||||
const audio = await quotedMsg.downloadMedia();
|
||||
await client.sendMessage(msg.from, audio, { sendAudioAsVoice: true });
|
||||
}
|
||||
} else if (msg.body === '!isviewonce' && msg.hasQuotedMsg) {
|
||||
const quotedMsg = await msg.getQuotedMessage();
|
||||
if (quotedMsg.hasMedia) {
|
||||
const media = await quotedMsg.downloadMedia();
|
||||
await client.sendMessage(msg.from, media, { isViewOnce: true });
|
||||
}
|
||||
} else if (msg.body === '!location') {
|
||||
// only latitude and longitude
|
||||
await msg.reply(new Location(37.422, -122.084));
|
||||
// location with name only
|
||||
await msg.reply(new Location(37.422, -122.084, { name: 'Googleplex' }));
|
||||
// location with address only
|
||||
await msg.reply(new Location(37.422, -122.084, { address: '1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA' }));
|
||||
// location with name, address and url
|
||||
await msg.reply(new Location(37.422, -122.084, { name: 'Googleplex', address: '1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA', url: 'https://google.com' }));
|
||||
} else if (msg.location) {
|
||||
msg.reply(msg.location);
|
||||
} else if (msg.body.startsWith('!status ')) {
|
||||
const newStatus = msg.body.split(' ')[1];
|
||||
await client.setStatus(newStatus);
|
||||
msg.reply(`Status was updated to *${newStatus}*`);
|
||||
} else if (msg.body === '!mentionUsers') {
|
||||
const chat = await msg.getChat();
|
||||
const userNumber = 'XXXXXXXXXX';
|
||||
/**
|
||||
* To mention one user you can pass user's ID to 'mentions' property as is,
|
||||
* without wrapping it in Array, and a user's phone number to the message body:
|
||||
*/
|
||||
await chat.sendMessage(`Hi @${userNumber}`, {
|
||||
mentions: userNumber + '@c.us'
|
||||
});
|
||||
// To mention a list of users:
|
||||
await chat.sendMessage(`Hi @${userNumber}, @${userNumber}`, {
|
||||
mentions: [userNumber + '@c.us', userNumber + '@c.us']
|
||||
});
|
||||
} else if (msg.body === '!mentionGroups') {
|
||||
const chat = await msg.getChat();
|
||||
const groupId = 'YYYYYYYYYY@g.us';
|
||||
/**
|
||||
* Sends clickable group mentions, the same as user mentions.
|
||||
* When the mentions are clicked, it opens a chat with the mentioned group.
|
||||
* The 'groupMentions.subject' can be custom
|
||||
*
|
||||
* @note The user that does not participate in the mentioned group,
|
||||
* will not be able to click on that mentioned group, the same if the group does not exist
|
||||
*
|
||||
* To mention one group:
|
||||
*/
|
||||
await chat.sendMessage(`Check the last message here: @${groupId}`, {
|
||||
groupMentions: { subject: 'GroupSubject', id: groupId }
|
||||
});
|
||||
// To mention a list of groups:
|
||||
await chat.sendMessage(`Check the last message in these groups: @${groupId}, @${groupId}`, {
|
||||
groupMentions: [
|
||||
{ subject: 'FirstGroup', id: groupId },
|
||||
{ subject: 'SecondGroup', id: groupId }
|
||||
]
|
||||
});
|
||||
} else if (msg.body === '!getGroupMentions') {
|
||||
// To get group mentions from a message:
|
||||
const groupId = 'ZZZZZZZZZZ@g.us';
|
||||
const msg = await client.sendMessage('chatId', `Check the last message here: @${groupId}`, {
|
||||
groupMentions: { subject: 'GroupSubject', id: groupId }
|
||||
});
|
||||
/** {@link groupMentions} is an array of `GroupChat` */
|
||||
const groupMentions = await msg.getGroupMentions();
|
||||
console.log(groupMentions);
|
||||
} 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();
|
||||
await chat.pin();
|
||||
} else if (msg.body === '!archive') {
|
||||
const chat = await msg.getChat();
|
||||
await chat.archive();
|
||||
} else if (msg.body === '!mute') {
|
||||
const chat = await msg.getChat();
|
||||
// mute the chat for 20 seconds
|
||||
const unmuteDate = new Date();
|
||||
unmuteDate.setSeconds(unmuteDate.getSeconds() + 20);
|
||||
await chat.mute(unmuteDate);
|
||||
} else if (msg.body === '!typing') {
|
||||
const chat = await msg.getChat();
|
||||
// simulates typing in the chat
|
||||
chat.sendStateTyping();
|
||||
} else if (msg.body === '!recording') {
|
||||
const chat = await msg.getChat();
|
||||
// simulates recording audio in the chat
|
||||
chat.sendStateRecording();
|
||||
} else if (msg.body === '!clearstate') {
|
||||
const chat = await msg.getChat();
|
||||
// stops typing or recording in the chat
|
||||
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);
|
||||
} else if (msg.body === '!reaction') {
|
||||
await msg.react('👍');
|
||||
} else if (msg.body === '!sendpoll') {
|
||||
/** By default the poll is created as a single choice poll: */
|
||||
await msg.reply(new Poll('Winter or Summer?', ['Winter', 'Summer']));
|
||||
/** If you want to provide a multiple choice poll, add allowMultipleAnswers as true: */
|
||||
await msg.reply(new Poll('Cats or Dogs?', ['Cats', 'Dogs'], { allowMultipleAnswers: true }));
|
||||
/**
|
||||
* You can provide a custom message secret, it can be used as a poll ID:
|
||||
* @note It has to be a unique vector with a length of 32
|
||||
*/
|
||||
await msg.reply(
|
||||
new Poll('Cats or Dogs?', ['Cats', 'Dogs'], {
|
||||
messageSecret: [
|
||||
1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
]
|
||||
})
|
||||
);
|
||||
} else if (msg.body === '!vote') {
|
||||
if (msg.hasQuotedMsg) {
|
||||
const quotedMsg = await msg.getQuotedMessage();
|
||||
if (quotedMsg.type === 'poll_creation') {
|
||||
await quotedMsg.vote(msg.body.replace('!vote', ''));
|
||||
} else {
|
||||
msg.reply('Can only be used on poll messages');
|
||||
}
|
||||
}
|
||||
} else if (msg.body === '!edit') {
|
||||
if (msg.hasQuotedMsg) {
|
||||
const quotedMsg = await msg.getQuotedMessage();
|
||||
if (quotedMsg.fromMe) {
|
||||
await quotedMsg.edit(msg.body.replace('!edit', ''));
|
||||
} else {
|
||||
msg.reply('I can only edit my own messages');
|
||||
}
|
||||
}
|
||||
} else if (msg.body === '!updatelabels') {
|
||||
const chat = await msg.getChat();
|
||||
await chat.changeLabels([0, 1]);
|
||||
} else if (msg.body === '!addlabels') {
|
||||
const chat = await msg.getChat();
|
||||
let labels = (await chat.getLabels()).map((l) => l.id);
|
||||
labels.push('0');
|
||||
labels.push('1');
|
||||
await chat.changeLabels(labels);
|
||||
} else if (msg.body === '!removelabels') {
|
||||
const chat = await msg.getChat();
|
||||
await chat.changeLabels([]);
|
||||
} else if (msg.body === '!approverequest') {
|
||||
/**
|
||||
* Presented an example for membership request approvals, the same examples are for the request rejections.
|
||||
* To approve the membership request from a specific user:
|
||||
*/
|
||||
await client.approveGroupMembershipRequests(msg.from, { requesterIds: 'number@c.us' });
|
||||
/** The same for execution on group object (no need to provide the group ID): */
|
||||
const group = await msg.getChat();
|
||||
await group.approveGroupMembershipRequests({ requesterIds: 'number@c.us' });
|
||||
/** To approve several membership requests: */
|
||||
const approval = await client.approveGroupMembershipRequests(msg.from, {
|
||||
requesterIds: ['number1@c.us', 'number2@c.us']
|
||||
});
|
||||
/**
|
||||
* The example of the {@link approval} output:
|
||||
* [
|
||||
* {
|
||||
* requesterId: 'number1@c.us',
|
||||
* message: 'Rejected successfully'
|
||||
* },
|
||||
* {
|
||||
* requesterId: 'number2@c.us',
|
||||
* error: 404,
|
||||
* message: 'ParticipantRequestNotFoundError'
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
*/
|
||||
console.log(approval);
|
||||
/** To approve all the existing membership requests (simply don't provide any user IDs): */
|
||||
await client.approveGroupMembershipRequests(msg.from);
|
||||
/** To change the sleep value to 300 ms: */
|
||||
await client.approveGroupMembershipRequests(msg.from, {
|
||||
requesterIds: ['number1@c.us', 'number2@c.us'],
|
||||
sleep: 300
|
||||
});
|
||||
/** To change the sleep value to random value between 100 and 300 ms: */
|
||||
await client.approveGroupMembershipRequests(msg.from, {
|
||||
requesterIds: ['number1@c.us', 'number2@c.us'],
|
||||
sleep: [100, 300]
|
||||
});
|
||||
/** To explicitly disable the sleep: */
|
||||
await client.approveGroupMembershipRequests(msg.from, {
|
||||
requesterIds: ['number1@c.us', 'number2@c.us'],
|
||||
sleep: null
|
||||
});
|
||||
} else if (msg.body === '!pinmsg') {
|
||||
/**
|
||||
* Pins a message in a chat, a method takes a number in seconds for the message to be pinned.
|
||||
* WhatsApp default values for duration to pass to the method are:
|
||||
* 1. 86400 for 24 hours
|
||||
* 2. 604800 for 7 days
|
||||
* 3. 2592000 for 30 days
|
||||
* You can pass your own value:
|
||||
*/
|
||||
const result = await msg.pin(60); // Will pin a message for 1 minute
|
||||
console.log(result); // True if the operation completed successfully, false otherwise
|
||||
} else if (msg.body === '!howManyConnections') {
|
||||
/**
|
||||
* Get user device count by ID
|
||||
* Each WaWeb Connection counts as one device, and the phone (if exists) counts as one
|
||||
* So for a non-enterprise user with one WaWeb connection it should return "2"
|
||||
*/
|
||||
let deviceCount = await client.getContactDeviceCount(msg.from);
|
||||
await msg.reply(`You have *${deviceCount}* devices connected`);
|
||||
} else if (msg.body === '!syncHistory') {
|
||||
const isSynced = await client.syncHistory(msg.from);
|
||||
// Or through the Chat object:
|
||||
// const chat = await client.getChatById(msg.from);
|
||||
// const isSynced = await chat.syncHistory();
|
||||
|
||||
await msg.reply(isSynced ? 'Historical chat is syncing..' : 'There is no historical chat to sync.');
|
||||
} else if (msg.body === '!statuses') {
|
||||
const statuses = await client.getBroadcasts();
|
||||
console.log(statuses);
|
||||
const chat = await statuses[0]?.getChat(); // Get user chat of a first status
|
||||
console.log(chat);
|
||||
} else if (msg.body === '!sendMediaHD' && msg.hasQuotedMsg) {
|
||||
const quotedMsg = await msg.getQuotedMessage();
|
||||
if (quotedMsg.hasMedia) {
|
||||
const media = await quotedMsg.downloadMedia();
|
||||
await client.sendMessage(msg.from, media, { sendMediaAsHd: true });
|
||||
}
|
||||
} else if (msg.body === '!parseVCard') {
|
||||
const vCard =
|
||||
'BEGIN:VCARD\n' +
|
||||
'VERSION:3.0\n' +
|
||||
'FN:John Doe\n' +
|
||||
'ORG:Microsoft;\n' +
|
||||
'EMAIL;type=INTERNET:john.doe@gmail.com\n' +
|
||||
'URL:www.johndoe.com\n' +
|
||||
'TEL;type=CELL;type=VOICE;waid=18006427676:+1 (800) 642 7676\n' +
|
||||
'END:VCARD';
|
||||
const vCardExtended =
|
||||
'BEGIN:VCARD\n' +
|
||||
'VERSION:3.0\n' +
|
||||
'FN:John Doe\n' +
|
||||
'ORG:Microsoft;\n' +
|
||||
'item1.TEL:+1 (800) 642 7676\n' +
|
||||
'item1.X-ABLabel:USA Customer Service\n' +
|
||||
'item2.TEL:+55 11 4706 0900\n' +
|
||||
'item2.X-ABLabel:Brazil Customer Service\n' +
|
||||
'PHOTO;BASE64:here you can paste a binary data of a contact photo in Base64 encoding\n' +
|
||||
'END:VCARD';
|
||||
const userId = 'XXXXXXXXXX@c.us';
|
||||
await client.sendMessage(userId, vCard);
|
||||
await client.sendMessage(userId, vCardExtended);
|
||||
} else if (msg.body === '!changeSync') {
|
||||
// NOTE: this action will take effect after you restart the client.
|
||||
const backgroundSync = await client.setBackgroundSync(true);
|
||||
console.log(backgroundSync);
|
||||
} else if (msg.body === '!postStatus') {
|
||||
await client.sendMessage('status@broadcast', 'Hello there!');
|
||||
// send with a different style
|
||||
await client.sendMessage('status@broadcast', 'Hello again! Looks different?', {
|
||||
fontStyle: 1,
|
||||
backgroundColor: '#0b3296'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
client.on('message_create', async (msg) => {
|
||||
// Fired on all message creations, including your own
|
||||
if (msg.fromMe) {
|
||||
// do stuff here
|
||||
}
|
||||
|
||||
// Unpins a message
|
||||
if (msg.fromMe && msg.body.startsWith('!unpin')) {
|
||||
const pinnedMsg = await msg.getQuotedMessage();
|
||||
if (pinnedMsg) {
|
||||
// Will unpin a message
|
||||
const result = await pinnedMsg.unpin();
|
||||
console.log(result); // True if the operation completed successfully, false otherwise
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.on('message_ciphertext', (msg) => {
|
||||
// Receiving new incoming messages that have been encrypted
|
||||
// msg.type === 'ciphertext'
|
||||
msg.body = 'Waiting for this message. Check your phone.';
|
||||
|
||||
// do stuff here
|
||||
});
|
||||
|
||||
client.on('message_revoke_everyone', async (after, before) => {
|
||||
// Fired whenever a message is deleted by anyone (including you)
|
||||
console.log(after); // message after it was deleted.
|
||||
if (before) {
|
||||
console.log(before); // message before it was deleted.
|
||||
}
|
||||
});
|
||||
|
||||
client.on('message_revoke_me', async (msg) => {
|
||||
// Fired whenever a message is only deleted in your own view.
|
||||
console.log(msg.body); // message before it was deleted.
|
||||
});
|
||||
|
||||
client.on('message_ack', (msg, ack) => {
|
||||
/*
|
||||
== ACK VALUES ==
|
||||
ACK_ERROR: -1
|
||||
ACK_PENDING: 0
|
||||
ACK_SERVER: 1
|
||||
ACK_DEVICE: 2
|
||||
ACK_READ: 3
|
||||
ACK_PLAYED: 4
|
||||
*/
|
||||
|
||||
if (ack == 3) {
|
||||
// The message was read
|
||||
}
|
||||
});
|
||||
|
||||
client.on('group_join', (notification) => {
|
||||
// User has joined or been added to the group.
|
||||
console.log('join', notification);
|
||||
notification.reply('User joined.');
|
||||
});
|
||||
|
||||
client.on('group_leave', (notification) => {
|
||||
// User has left or been kicked from the group.
|
||||
console.log('leave', notification);
|
||||
notification.reply('User left.');
|
||||
});
|
||||
|
||||
client.on('group_update', (notification) => {
|
||||
// Group picture, subject or description has been updated.
|
||||
console.log('update', notification);
|
||||
});
|
||||
|
||||
client.on('change_state', state => {
|
||||
console.log('CHANGE STATE', state);
|
||||
});
|
||||
|
||||
// Change to false if you don't want to reject incoming calls
|
||||
let rejectCalls = true;
|
||||
|
||||
client.on('call', async (call) => {
|
||||
console.log('Call received, rejecting. GOTO Line 261 to disable', call);
|
||||
if (rejectCalls) await call.reject();
|
||||
await client.sendMessage(call.from, `[${call.fromMe ? 'Outgoing' : 'Incoming'}] Phone call from ${call.from}, type ${call.isGroup ? 'group' : ''} ${call.isVideo ? 'video' : 'audio'} call. ${rejectCalls ? 'This call was automatically rejected by the script.' : ''}`);
|
||||
});
|
||||
|
||||
client.on('disconnected', (reason) => {
|
||||
console.log('Client was logged out', reason);
|
||||
});
|
||||
|
||||
client.on('contact_changed', async (message, oldId, newId, isContact) => {
|
||||
/** The time the event occurred. */
|
||||
const eventTime = (new Date(message.timestamp * 1000)).toLocaleString();
|
||||
|
||||
console.log(
|
||||
`The contact ${oldId.slice(0, -5)}` +
|
||||
`${!isContact ? ' that participates in group ' +
|
||||
`${(await client.getChatById(message.to ?? message.from)).name} ` : ' '}` +
|
||||
`changed their phone number\nat ${eventTime}.\n` +
|
||||
`Their new phone number is ${newId.slice(0, -5)}.\n`);
|
||||
|
||||
/**
|
||||
* Information about the @param {message}:
|
||||
*
|
||||
* 1. If a notification was emitted due to a group participant changing their phone number:
|
||||
* @param {message.author} is a participant's id before the change.
|
||||
* @param {message.recipients[0]} is a participant's id after the change (a new one).
|
||||
*
|
||||
* 1.1 If the contact who changed their number WAS in the current user's contact list at the time of the change:
|
||||
* @param {message.to} is a group chat id the event was emitted in.
|
||||
* @param {message.from} is a current user's id that got an notification message in the group.
|
||||
* Also the @param {message.fromMe} is TRUE.
|
||||
*
|
||||
* 1.2 Otherwise:
|
||||
* @param {message.from} is a group chat id the event was emitted in.
|
||||
* @param {message.to} is @type {undefined}.
|
||||
* Also @param {message.fromMe} is FALSE.
|
||||
*
|
||||
* 2. If a notification was emitted due to a contact changing their phone number:
|
||||
* @param {message.templateParams} is an array of two user's ids:
|
||||
* the old (before the change) and a new one, stored in alphabetical order.
|
||||
* @param {message.from} is a current user's id that has a chat with a user,
|
||||
* whos phone number was changed.
|
||||
* @param {message.to} is a user's id (after the change), the current user has a chat with.
|
||||
*/
|
||||
});
|
||||
|
||||
client.on('group_admin_changed', (notification) => {
|
||||
if (notification.type === 'promote') {
|
||||
/**
|
||||
* Emitted when a current user is promoted to an admin.
|
||||
* {@link notification.author} is a user who performs the action of promoting/demoting the current user.
|
||||
*/
|
||||
console.log(`You were promoted by ${notification.author}`);
|
||||
} else if (notification.type === 'demote')
|
||||
/** Emitted when a current user is demoted to a regular user. */
|
||||
console.log(`You were demoted by ${notification.author}`);
|
||||
});
|
||||
|
||||
client.on('group_membership_request', async (notification) => {
|
||||
/**
|
||||
* The example of the {@link notification} output:
|
||||
* {
|
||||
* id: {
|
||||
* fromMe: false,
|
||||
* remote: 'groupId@g.us',
|
||||
* id: '123123123132132132',
|
||||
* participant: 'number@c.us',
|
||||
* _serialized: 'false_groupId@g.us_123123123132132132_number@c.us'
|
||||
* },
|
||||
* body: '',
|
||||
* type: 'created_membership_requests',
|
||||
* timestamp: 1694456538,
|
||||
* chatId: 'groupId@g.us',
|
||||
* author: 'number@c.us',
|
||||
* recipientIds: []
|
||||
* }
|
||||
*
|
||||
*/
|
||||
console.log(notification);
|
||||
/** You can approve or reject the newly appeared membership request: */
|
||||
await client.approveGroupMembershipRequestss(notification.chatId, notification.author);
|
||||
await client.rejectGroupMembershipRequests(notification.chatId, notification.author);
|
||||
});
|
||||
|
||||
client.on('message_reaction', async (reaction) => {
|
||||
console.log('REACTION RECEIVED', reaction);
|
||||
});
|
||||
|
||||
client.on('vote_update', (vote) => {
|
||||
/** The vote that was affected: */
|
||||
console.log(vote);
|
||||
});
|
||||
2259
node_modules/whatsapp-web.js/index.d.ts
generated
vendored
Normal file
2259
node_modules/whatsapp-web.js/index.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
35
node_modules/whatsapp-web.js/index.js
generated
vendored
Normal file
35
node_modules/whatsapp-web.js/index.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
'use strict';
|
||||
|
||||
const Constants = require('./src/util/Constants');
|
||||
|
||||
module.exports = {
|
||||
Client: require('./src/Client'),
|
||||
|
||||
version: require('./package.json').version,
|
||||
|
||||
// Structures
|
||||
Chat: require('./src/structures/Chat'),
|
||||
PrivateChat: require('./src/structures/PrivateChat'),
|
||||
GroupChat: require('./src/structures/GroupChat'),
|
||||
Channel: require('./src/structures/Channel'),
|
||||
Message: require('./src/structures/Message'),
|
||||
MessageMedia: require('./src/structures/MessageMedia'),
|
||||
Contact: require('./src/structures/Contact'),
|
||||
PrivateContact: require('./src/structures/PrivateContact'),
|
||||
BusinessContact: require('./src/structures/BusinessContact'),
|
||||
ClientInfo: require('./src/structures/ClientInfo'),
|
||||
Location: require('./src/structures/Location'),
|
||||
Poll: require('./src/structures/Poll'),
|
||||
ScheduledEvent: require('./src/structures/ScheduledEvent'),
|
||||
ProductMetadata: require('./src/structures/ProductMetadata'),
|
||||
List: require('./src/structures/List'),
|
||||
Buttons: require('./src/structures/Buttons'),
|
||||
Broadcast: require('./src/structures/Broadcast'),
|
||||
|
||||
// Auth Strategies
|
||||
NoAuth: require('./src/authStrategies/NoAuth'),
|
||||
LocalAuth: require('./src/authStrategies/LocalAuth'),
|
||||
RemoteAuth: require('./src/authStrategies/RemoteAuth'),
|
||||
|
||||
...Constants
|
||||
};
|
||||
59
node_modules/whatsapp-web.js/package.json
generated
vendored
Normal file
59
node_modules/whatsapp-web.js/package.json
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "whatsapp-web.js",
|
||||
"version": "1.34.6",
|
||||
"description": "Library for interacting with the WhatsApp Web API ",
|
||||
"main": "./index.js",
|
||||
"typings": "./index.d.ts",
|
||||
"scripts": {
|
||||
"test": "mocha tests --recursive --timeout 5000",
|
||||
"test-single": "mocha",
|
||||
"shell": "node --experimental-repl-await ./shell.js",
|
||||
"generate-docs": "npx jsdoc --configure .jsdoc.json --verbose"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/pedroslopez/whatsapp-web.js.git"
|
||||
},
|
||||
"keywords": [
|
||||
"whatsapp",
|
||||
"whatsapp-web",
|
||||
"api",
|
||||
"bot",
|
||||
"client",
|
||||
"node"
|
||||
],
|
||||
"author": "Pedro Lopez",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/pedroslopez/whatsapp-web.js/issues"
|
||||
},
|
||||
"homepage": "https://wwebjs.dev/",
|
||||
"dependencies": {
|
||||
"@pedroslopez/moduleraid": "^5.0.2",
|
||||
"fluent-ffmpeg": "2.1.3",
|
||||
"mime": "^3.0.0",
|
||||
"node-fetch": "^2.6.9",
|
||||
"node-webpmux": "3.1.7",
|
||||
"puppeteer": "^24.31.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node-fetch": "^2.5.12",
|
||||
"chai": "^4.3.4",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"dotenv": "^16.0.0",
|
||||
"eslint": "^8.4.1",
|
||||
"eslint-plugin-mocha": "^10.0.3",
|
||||
"jsdoc": "^3.6.4",
|
||||
"jsdoc-baseline": "^0.1.5",
|
||||
"mocha": "^9.0.2",
|
||||
"sinon": "^13.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"archiver": "^5.3.1",
|
||||
"fs-extra": "^10.1.0",
|
||||
"unzipper": "^0.10.11"
|
||||
}
|
||||
}
|
||||
36
node_modules/whatsapp-web.js/shell.js
generated
vendored
Normal file
36
node_modules/whatsapp-web.js/shell.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* ==== wwebjs-shell ====
|
||||
* Used for quickly testing library features
|
||||
*
|
||||
* Running `npm run shell` will start WhatsApp Web with headless=false
|
||||
* and then drop you into Node REPL with `client` in its context.
|
||||
*/
|
||||
|
||||
const repl = require('repl');
|
||||
|
||||
const { Client, LocalAuth } = require('./index');
|
||||
|
||||
const client = new Client({
|
||||
puppeteer: { headless: false },
|
||||
authStrategy: new LocalAuth()
|
||||
});
|
||||
|
||||
console.log('Initializing...');
|
||||
|
||||
client.initialize();
|
||||
|
||||
client.on('qr', () => {
|
||||
console.log('Please scan the QR code on the browser.');
|
||||
});
|
||||
|
||||
client.on('authenticated', (session) => {
|
||||
console.log(JSON.stringify(session));
|
||||
});
|
||||
|
||||
client.on('ready', () => {
|
||||
const shell = repl.start('wwebjs> ');
|
||||
shell.context.client = client;
|
||||
shell.on('exit', async () => {
|
||||
await client.destroy();
|
||||
});
|
||||
});
|
||||
2540
node_modules/whatsapp-web.js/src/Client.js
generated
vendored
Normal file
2540
node_modules/whatsapp-web.js/src/Client.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
27
node_modules/whatsapp-web.js/src/authStrategies/BaseAuthStrategy.js
generated
vendored
Normal file
27
node_modules/whatsapp-web.js/src/authStrategies/BaseAuthStrategy.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Base class which all authentication strategies extend
|
||||
*/
|
||||
class BaseAuthStrategy {
|
||||
constructor() {}
|
||||
setup(client) {
|
||||
this.client = client;
|
||||
}
|
||||
async beforeBrowserInitialized() {}
|
||||
async afterBrowserInitialized() {}
|
||||
async onAuthenticationNeeded() {
|
||||
return {
|
||||
failed: false,
|
||||
restart: false,
|
||||
failureEventPayload: undefined
|
||||
};
|
||||
}
|
||||
async getAuthEventPayload() {}
|
||||
async afterAuthReady() {}
|
||||
async disconnect() {}
|
||||
async destroy() {}
|
||||
async logout() {}
|
||||
}
|
||||
|
||||
module.exports = BaseAuthStrategy;
|
||||
58
node_modules/whatsapp-web.js/src/authStrategies/LocalAuth.js
generated
vendored
Normal file
58
node_modules/whatsapp-web.js/src/authStrategies/LocalAuth.js
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const BaseAuthStrategy = require('./BaseAuthStrategy');
|
||||
|
||||
/**
|
||||
* Local directory-based authentication
|
||||
* @param {object} options - options
|
||||
* @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
|
||||
* @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
|
||||
* @param {number} options.rmMaxRetries - Sets the maximum number of retries for removing the session directory
|
||||
*/
|
||||
class LocalAuth extends BaseAuthStrategy {
|
||||
constructor({ clientId, dataPath, rmMaxRetries }={}) {
|
||||
super();
|
||||
|
||||
const idRegex = /^[-_\w]+$/i;
|
||||
if(clientId && !idRegex.test(clientId)) {
|
||||
throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
|
||||
}
|
||||
|
||||
this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
|
||||
this.clientId = clientId;
|
||||
this.rmMaxRetries = rmMaxRetries ?? 4;
|
||||
}
|
||||
|
||||
async beforeBrowserInitialized() {
|
||||
const puppeteerOpts = this.client.options.puppeteer;
|
||||
const sessionDirName = this.clientId ? `session-${this.clientId}` : 'session';
|
||||
const dirPath = path.join(this.dataPath, sessionDirName);
|
||||
|
||||
if(puppeteerOpts.userDataDir && puppeteerOpts.userDataDir !== dirPath) {
|
||||
throw new Error('LocalAuth is not compatible with a user-supplied userDataDir.');
|
||||
}
|
||||
|
||||
fs.mkdirSync(dirPath, { recursive: true });
|
||||
|
||||
this.client.options.puppeteer = {
|
||||
...puppeteerOpts,
|
||||
userDataDir: dirPath
|
||||
};
|
||||
|
||||
this.userDataDir = dirPath;
|
||||
}
|
||||
|
||||
async logout() {
|
||||
if (this.userDataDir) {
|
||||
await fs.promises.rm(this.userDataDir, { recursive: true, force: true, maxRetries: this.rmMaxRetries })
|
||||
.catch((e) => {
|
||||
throw new Error(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = LocalAuth;
|
||||
12
node_modules/whatsapp-web.js/src/authStrategies/NoAuth.js
generated
vendored
Normal file
12
node_modules/whatsapp-web.js/src/authStrategies/NoAuth.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
const BaseAuthStrategy = require('./BaseAuthStrategy');
|
||||
|
||||
/**
|
||||
* No session restoring functionality
|
||||
* Will need to authenticate via QR code every time
|
||||
*/
|
||||
class NoAuth extends BaseAuthStrategy { }
|
||||
|
||||
|
||||
module.exports = NoAuth;
|
||||
211
node_modules/whatsapp-web.js/src/authStrategies/RemoteAuth.js
generated
vendored
Normal file
211
node_modules/whatsapp-web.js/src/authStrategies/RemoteAuth.js
generated
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
'use strict';
|
||||
|
||||
/* Require Optional Dependencies */
|
||||
try {
|
||||
var fs = require('fs-extra');
|
||||
var unzipper = require('unzipper');
|
||||
var archiver = require('archiver');
|
||||
} catch {
|
||||
fs = undefined;
|
||||
unzipper = undefined;
|
||||
archiver = undefined;
|
||||
}
|
||||
|
||||
const path = require('path');
|
||||
const { Events } = require('./../util/Constants');
|
||||
const BaseAuthStrategy = require('./BaseAuthStrategy');
|
||||
|
||||
/**
|
||||
* Remote-based authentication
|
||||
* @param {object} options - options
|
||||
* @param {object} options.store - Remote database store instance
|
||||
* @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
|
||||
* @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
|
||||
* @param {number} options.backupSyncIntervalMs - Sets the time interval for periodic session backups. Accepts values starting from 60000ms {1 minute}
|
||||
* @param {number} options.rmMaxRetries - Sets the maximum number of retries for removing the session directory
|
||||
*/
|
||||
class RemoteAuth extends BaseAuthStrategy {
|
||||
constructor({ clientId, dataPath, store, backupSyncIntervalMs, rmMaxRetries } = {}) {
|
||||
if (!fs && !unzipper && !archiver) throw new Error('Optional Dependencies [fs-extra, unzipper, archiver] are required to use RemoteAuth. Make sure to run npm install correctly and remove the --no-optional flag');
|
||||
super();
|
||||
|
||||
const idRegex = /^[-_\w]+$/i;
|
||||
if (clientId && !idRegex.test(clientId)) {
|
||||
throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
|
||||
}
|
||||
if (!backupSyncIntervalMs || backupSyncIntervalMs < 60000) {
|
||||
throw new Error('Invalid backupSyncIntervalMs. Accepts values starting from 60000ms {1 minute}.');
|
||||
}
|
||||
if(!store) throw new Error('Remote database store is required.');
|
||||
|
||||
this.store = store;
|
||||
this.clientId = clientId;
|
||||
this.backupSyncIntervalMs = backupSyncIntervalMs;
|
||||
this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
|
||||
this.tempDir = `${this.dataPath}/wwebjs_temp_session_${this.clientId}`;
|
||||
this.requiredDirs = ['Default', 'IndexedDB', 'Local Storage']; /* => Required Files & Dirs in WWebJS to restore session */
|
||||
this.rmMaxRetries = rmMaxRetries ?? 4;
|
||||
}
|
||||
|
||||
async beforeBrowserInitialized() {
|
||||
const puppeteerOpts = this.client.options.puppeteer;
|
||||
const sessionDirName = this.clientId ? `RemoteAuth-${this.clientId}` : 'RemoteAuth';
|
||||
const dirPath = path.join(this.dataPath, sessionDirName);
|
||||
|
||||
if (puppeteerOpts.userDataDir && puppeteerOpts.userDataDir !== dirPath) {
|
||||
throw new Error('RemoteAuth is not compatible with a user-supplied userDataDir.');
|
||||
}
|
||||
|
||||
this.userDataDir = dirPath;
|
||||
this.sessionName = sessionDirName;
|
||||
|
||||
await this.extractRemoteSession();
|
||||
|
||||
this.client.options.puppeteer = {
|
||||
...puppeteerOpts,
|
||||
userDataDir: dirPath
|
||||
};
|
||||
}
|
||||
|
||||
async logout() {
|
||||
await this.disconnect();
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
clearInterval(this.backupSync);
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
await this.deleteRemoteSession();
|
||||
|
||||
let pathExists = await this.isValidPath(this.userDataDir);
|
||||
if (pathExists) {
|
||||
await fs.promises.rm(this.userDataDir, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
maxRetries: this.rmMaxRetries,
|
||||
}).catch(() => {});
|
||||
}
|
||||
clearInterval(this.backupSync);
|
||||
}
|
||||
|
||||
async afterAuthReady() {
|
||||
const sessionExists = await this.store.sessionExists({session: this.sessionName});
|
||||
if(!sessionExists) {
|
||||
await this.delay(60000); /* Initial delay sync required for session to be stable enough to recover */
|
||||
await this.storeRemoteSession({emit: true});
|
||||
}
|
||||
var self = this;
|
||||
this.backupSync = setInterval(async function () {
|
||||
await self.storeRemoteSession();
|
||||
}, this.backupSyncIntervalMs);
|
||||
}
|
||||
|
||||
async storeRemoteSession(options) {
|
||||
/* Compress & Store Session */
|
||||
const pathExists = await this.isValidPath(this.userDataDir);
|
||||
if (pathExists) {
|
||||
await this.compressSession();
|
||||
await this.store.save({session: path.join(this.dataPath, this.sessionName)});
|
||||
await fs.promises.unlink(path.join(this.dataPath, `${this.sessionName}.zip`));
|
||||
await fs.promises.rm(`${this.tempDir}`, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
maxRetries: this.rmMaxRetries,
|
||||
}).catch(() => {});
|
||||
if(options && options.emit) this.client.emit(Events.REMOTE_SESSION_SAVED);
|
||||
}
|
||||
}
|
||||
|
||||
async extractRemoteSession() {
|
||||
const pathExists = await this.isValidPath(this.userDataDir);
|
||||
const compressedSessionPath = path.join(this.dataPath, `${this.sessionName}.zip`);
|
||||
const sessionExists = await this.store.sessionExists({session: this.sessionName});
|
||||
if (pathExists) {
|
||||
await fs.promises.rm(this.userDataDir, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
maxRetries: this.rmMaxRetries,
|
||||
}).catch(() => {});
|
||||
}
|
||||
if (sessionExists) {
|
||||
await this.store.extract({session: this.sessionName, path: compressedSessionPath});
|
||||
await this.unCompressSession(compressedSessionPath);
|
||||
} else {
|
||||
fs.mkdirSync(this.userDataDir, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteRemoteSession() {
|
||||
const sessionExists = await this.store.sessionExists({session: this.sessionName});
|
||||
if (sessionExists) await this.store.delete({session: this.sessionName});
|
||||
}
|
||||
|
||||
async compressSession() {
|
||||
const archive = archiver('zip');
|
||||
const stream = fs.createWriteStream(path.join(this.dataPath, `${this.sessionName}.zip`));
|
||||
|
||||
await fs.copy(this.userDataDir, this.tempDir).catch(() => {});
|
||||
await this.deleteMetadata();
|
||||
return new Promise((resolve, reject) => {
|
||||
archive
|
||||
.directory(this.tempDir, false)
|
||||
.on('error', err => reject(err))
|
||||
.pipe(stream);
|
||||
|
||||
stream.on('close', () => resolve());
|
||||
archive.finalize();
|
||||
});
|
||||
}
|
||||
|
||||
async unCompressSession(compressedSessionPath) {
|
||||
var stream = fs.createReadStream(compressedSessionPath);
|
||||
await new Promise((resolve, reject) => {
|
||||
stream.pipe(unzipper.Extract({
|
||||
path: this.userDataDir,
|
||||
concurrency: 10
|
||||
}))
|
||||
.on('error', err => reject(err))
|
||||
.on('finish', () => resolve());
|
||||
});
|
||||
await fs.promises.unlink(compressedSessionPath);
|
||||
}
|
||||
|
||||
async deleteMetadata() {
|
||||
const sessionDirs = [this.tempDir, path.join(this.tempDir, 'Default')];
|
||||
for (const dir of sessionDirs) {
|
||||
const sessionFiles = await fs.promises.readdir(dir);
|
||||
for (const element of sessionFiles) {
|
||||
if (!this.requiredDirs.includes(element)) {
|
||||
const dirElement = path.join(dir, element);
|
||||
const stats = await fs.promises.lstat(dirElement);
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
await fs.promises.rm(dirElement, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
maxRetries: this.rmMaxRetries,
|
||||
}).catch(() => {});
|
||||
} else {
|
||||
await fs.promises.unlink(dirElement).catch(() => {});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async isValidPath(path) {
|
||||
try {
|
||||
await fs.promises.access(path);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async delay(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RemoteAuth;
|
||||
21
node_modules/whatsapp-web.js/src/factories/ChatFactory.js
generated
vendored
Normal file
21
node_modules/whatsapp-web.js/src/factories/ChatFactory.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
const PrivateChat = require('../structures/PrivateChat');
|
||||
const GroupChat = require('../structures/GroupChat');
|
||||
const Channel = require('../structures/Channel');
|
||||
|
||||
class ChatFactory {
|
||||
static create(client, data) {
|
||||
if (data.isGroup) {
|
||||
return new GroupChat(client, data);
|
||||
}
|
||||
|
||||
if (data.isChannel) {
|
||||
return new Channel(client, data);
|
||||
}
|
||||
|
||||
return new PrivateChat(client, data);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ChatFactory;
|
||||
16
node_modules/whatsapp-web.js/src/factories/ContactFactory.js
generated
vendored
Normal file
16
node_modules/whatsapp-web.js/src/factories/ContactFactory.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
const PrivateContact = require('../structures/PrivateContact');
|
||||
const BusinessContact = require('../structures/BusinessContact');
|
||||
|
||||
class ContactFactory {
|
||||
static create(client, data) {
|
||||
if(data.isBusiness) {
|
||||
return new BusinessContact(client, data);
|
||||
}
|
||||
|
||||
return new PrivateContact(client, data);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ContactFactory;
|
||||
22
node_modules/whatsapp-web.js/src/structures/Base.js
generated
vendored
Normal file
22
node_modules/whatsapp-web.js/src/structures/Base.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Represents a WhatsApp data structure
|
||||
*/
|
||||
class Base {
|
||||
constructor(client) {
|
||||
/**
|
||||
* The client that instantiated this
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(this, 'client', { value: client });
|
||||
}
|
||||
|
||||
_clone() {
|
||||
return Object.assign(Object.create(this), this);
|
||||
}
|
||||
|
||||
_patch(data) { return data; }
|
||||
}
|
||||
|
||||
module.exports = Base;
|
||||
69
node_modules/whatsapp-web.js/src/structures/Broadcast.js
generated
vendored
Normal file
69
node_modules/whatsapp-web.js/src/structures/Broadcast.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
const Message = require('./Message');
|
||||
|
||||
/**
|
||||
* Represents a Status/Story on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Broadcast extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* ID that represents the chat
|
||||
* @type {object}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* Unix timestamp of last status
|
||||
* @type {number}
|
||||
*/
|
||||
this.timestamp = data.t;
|
||||
|
||||
/**
|
||||
* Number of available statuses
|
||||
* @type {number}
|
||||
*/
|
||||
this.totalCount = data.totalCount;
|
||||
|
||||
/**
|
||||
* Number of not viewed
|
||||
* @type {number}
|
||||
*/
|
||||
this.unreadCount = data.unreadCount;
|
||||
|
||||
/**
|
||||
* Messages statuses
|
||||
* @type {Message[]}
|
||||
*/
|
||||
this.msgs = data.msgs?.map(msg => new Message(this.client, msg));
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Chat this message was sent in
|
||||
* @returns {Promise<Chat>}
|
||||
*/
|
||||
getChat() {
|
||||
return this.client.getChatById(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Contact this message was sent from
|
||||
* @returns {Promise<Contact>}
|
||||
*/
|
||||
getContact() {
|
||||
return this.client.getContactById(this.id._serialized);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Broadcast;
|
||||
21
node_modules/whatsapp-web.js/src/structures/BusinessContact.js
generated
vendored
Normal file
21
node_modules/whatsapp-web.js/src/structures/BusinessContact.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
const Contact = require('./Contact');
|
||||
|
||||
/**
|
||||
* Represents a Business Contact on WhatsApp
|
||||
* @extends {Contact}
|
||||
*/
|
||||
class BusinessContact extends Contact {
|
||||
_patch(data) {
|
||||
/**
|
||||
* The contact's business profile
|
||||
*/
|
||||
this.businessProfile = data.businessProfile;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = BusinessContact;
|
||||
82
node_modules/whatsapp-web.js/src/structures/Buttons.js
generated
vendored
Normal file
82
node_modules/whatsapp-web.js/src/structures/Buttons.js
generated
vendored
Normal 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;
|
||||
76
node_modules/whatsapp-web.js/src/structures/Call.js
generated
vendored
Normal file
76
node_modules/whatsapp-web.js/src/structures/Call.js
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
'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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject the call
|
||||
*/
|
||||
async reject() {
|
||||
return this.client.pupPage.evaluate((peerJid, id) => {
|
||||
return window.WWebJS.rejectCall(peerJid, id);
|
||||
}, this.from, this.id);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Call;
|
||||
382
node_modules/whatsapp-web.js/src/structures/Channel.js
generated
vendored
Normal file
382
node_modules/whatsapp-web.js/src/structures/Channel.js
generated
vendored
Normal file
@@ -0,0 +1,382 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
const Message = require('./Message');
|
||||
|
||||
/**
|
||||
* Channel ID structure
|
||||
* @typedef {Object} ChannelId
|
||||
* @property {string} server
|
||||
* @property {string} user
|
||||
* @property {string} _serialized
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a Channel on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Channel extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
this.channelMetadata = data.channelMetadata;
|
||||
|
||||
/**
|
||||
* ID that represents the channel
|
||||
* @type {ChannelId}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* Title of the channel
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = data.name;
|
||||
|
||||
/**
|
||||
* The channel description
|
||||
* @type {string}
|
||||
*/
|
||||
this.description = data.channelMetadata.description;
|
||||
|
||||
/**
|
||||
* Indicates if it is a Channel
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isChannel = data.isChannel;
|
||||
|
||||
/**
|
||||
* Indicates if it is a Group
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isGroup = data.isGroup;
|
||||
|
||||
/**
|
||||
* Indicates if the channel is readonly
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isReadOnly = data.isReadOnly;
|
||||
|
||||
/**
|
||||
* Amount of messages unread
|
||||
* @type {number}
|
||||
*/
|
||||
this.unreadCount = data.unreadCount;
|
||||
|
||||
/**
|
||||
* Unix timestamp for when the last activity occurred
|
||||
* @type {number}
|
||||
*/
|
||||
this.timestamp = data.t;
|
||||
|
||||
/**
|
||||
* Indicates if the channel is muted or not
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isMuted = data.isMuted;
|
||||
|
||||
/**
|
||||
* Unix timestamp for when the mute expires
|
||||
* @type {number}
|
||||
*/
|
||||
this.muteExpiration = data.muteExpiration;
|
||||
|
||||
/**
|
||||
* Last message in the channel
|
||||
* @type {Message}
|
||||
*/
|
||||
this.lastMessage = data.lastMessage ? new Message(super.client, data.lastMessage) : undefined;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subscribers of the channel (only those who are in your contact list)
|
||||
* @param {?number} limit Optional parameter to specify the limit of subscribers to retrieve
|
||||
* @returns {Promise<Array<{contact: Contact, role: string}>>} Returns an array of objects that handle the subscribed contacts and their roles in the channel
|
||||
*/
|
||||
async getSubscribers(limit) {
|
||||
return await this.client.pupPage.evaluate(async (channelId, limit) => {
|
||||
const channel = await window.WWebJS.getChat(channelId, { getAsModel: false });
|
||||
if (!channel) return [];
|
||||
!limit && (limit = window.Store.ChannelUtils.getMaxSubscriberNumber());
|
||||
const response = await window.Store.ChannelSubscribers.mexFetchNewsletterSubscribers(channelId, limit);
|
||||
const contacts = window.Store.ChannelSubscribers.getSubscribersInContacts(response.subscribers);
|
||||
return Promise.all(contacts.map((obj) => ({
|
||||
...obj,
|
||||
contact: window.WWebJS.getContactModel(obj.contact)
|
||||
})));
|
||||
}, this.id._serialized, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channel subject
|
||||
* @param {string} newSubject
|
||||
* @returns {Promise<boolean>} Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.
|
||||
*/
|
||||
async setSubject(newSubject) {
|
||||
const success = await this._setChannelMetadata({ name: newSubject }, { editName: true });
|
||||
success && (this.name = newSubject);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channel description
|
||||
* @param {string} newDescription
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async setDescription(newDescription) {
|
||||
const success = await this._setChannelMetadata({ description: newDescription }, { editDescription: true });
|
||||
success && (this.description = newDescription);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channel profile picture
|
||||
* @param {MessageMedia} newProfilePicture
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async setProfilePicture(newProfilePicture) {
|
||||
return await this._setChannelMetadata({ picture: newProfilePicture }, { editPicture: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates available reactions to use in the channel
|
||||
*
|
||||
* Valid values for passing to the method are:
|
||||
* 0 for NONE reactions to be avaliable
|
||||
* 1 for BASIC reactions to be available: 👍, ❤️, 😂, 😮, 😢, 🙏
|
||||
* 2 for ALL reactions to be available
|
||||
* @param {number} reactionCode
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async setReactionSetting(reactionCode) {
|
||||
if (![0, 1, 2].includes(reactionCode)) return false;
|
||||
const reactionMapper = {
|
||||
0: 3,
|
||||
1: 1,
|
||||
2: 0
|
||||
};
|
||||
const success = await this._setChannelMetadata(
|
||||
{ reactionCodesSetting: reactionMapper[reactionCode] },
|
||||
{ editReactionCodesSetting: true }
|
||||
);
|
||||
success && (this.channelMetadata.reactionCodesSetting = reactionCode);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutes the channel
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async mute() {
|
||||
const success = await this._muteUnmuteChannel('MUTE');
|
||||
if (success) {
|
||||
this.isMuted = true;
|
||||
this.muteExpiration = -1;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmutes the channel
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async unmute() {
|
||||
const success = await this._muteUnmuteChannel('UNMUTE');
|
||||
if (success) {
|
||||
this.isMuted = false;
|
||||
this.muteExpiration = 0;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Message options
|
||||
* @typedef {Object} MessageSendOptions
|
||||
* @property {?string} caption Image or video caption
|
||||
* @property {?string[]} mentions User IDs of user that will be mentioned in the message
|
||||
* @property {?MessageMedia} media Image or video to be sent
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sends a message to this channel
|
||||
* @param {string|MessageMedia} content
|
||||
* @param {?MessageSendOptions} options
|
||||
* @returns {Promise<Message>} Message that was just sent
|
||||
*/
|
||||
async sendMessage(content, options) {
|
||||
return this.client.sendMessage(this.id._serialized, content, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the channel as seen
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async sendSeen() {
|
||||
return this.client.sendSeen(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} SendChannelAdminInviteOptions
|
||||
* @property {?string} comment The comment to be added to an invitation
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sends a channel admin invitation to a user, allowing them to become an admin of the channel
|
||||
* @param {string} chatId The ID of a user to send the channel admin invitation to
|
||||
* @param {SendChannelAdminInviteOptions} options
|
||||
* @returns {Promise<boolean>} Returns true if an invitation was sent successfully, false otherwise
|
||||
*/
|
||||
async sendChannelAdminInvite(chatId, options = {}) {
|
||||
return this.client.sendChannelAdminInvite(chatId, this.id._serialized, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a channel admin invitation and promotes the current user to a channel admin
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async acceptChannelAdminInvite() {
|
||||
return this.client.acceptChannelAdminInvite(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes a channel admin invitation sent to a user by a channel owner
|
||||
* @param {string} userId The user ID the invitation was sent to
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async revokeChannelAdminInvite(userId) {
|
||||
return this.client.revokeChannelAdminInvite(this.id._serialized, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Demotes a channel admin to a regular subscriber (can be used also for self-demotion)
|
||||
* @param {string} userId The user ID to demote
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async demoteChannelAdmin(userId) {
|
||||
return this.client.demoteChannelAdmin(this.id._serialized, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for transferring a channel ownership to another user
|
||||
* @typedef {Object} TransferChannelOwnershipOptions
|
||||
* @property {boolean} [shouldDismissSelfAsAdmin = false] If true, after the channel ownership is being transferred to another user, the current user will be dismissed as a channel admin and will become to a channel subscriber.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Transfers a channel ownership to another user.
|
||||
* Note: the user you are transferring the channel ownership to must be a channel admin.
|
||||
* @param {string} newOwnerId
|
||||
* @param {TransferChannelOwnershipOptions} options
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async transferChannelOwnership(newOwnerId, options = {}) {
|
||||
return this.client.transferChannelOwnership(this.id._serialized, newOwnerId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads channel messages, sorted from earliest to latest
|
||||
* @param {Object} searchOptions Options for searching messages. Right now only limit and fromMe is supported
|
||||
* @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
|
||||
* @param {Boolean} [searchOptions.fromMe] Return only messages from the bot number or vise versa. To get all messages, leave the option undefined
|
||||
* @returns {Promise<Array<Message>>}
|
||||
*/
|
||||
async fetchMessages(searchOptions) {
|
||||
let messages = await this.client.pupPage.evaluate(async (channelId, searchOptions) => {
|
||||
const msgFilter = (m) => {
|
||||
if (m.isNotification || m.type === 'newsletter_notification') {
|
||||
return false; // dont include notification messages
|
||||
}
|
||||
if (searchOptions && searchOptions.fromMe !== undefined && m.id.fromMe !== searchOptions.fromMe) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const channel = await window.WWebJS.getChat(channelId, { getAsModel: false });
|
||||
let msgs = channel.msgs.getModelsArray().filter(msgFilter);
|
||||
|
||||
if (searchOptions && searchOptions.limit > 0) {
|
||||
while (msgs.length < searchOptions.limit) {
|
||||
const loadedMessages = await window.Store.ConversationMsgs.loadEarlierMsgs(channel);
|
||||
if (!loadedMessages || !loadedMessages.length) 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);
|
||||
}
|
||||
}
|
||||
|
||||
return msgs.map(m => window.WWebJS.getMessageModel(m));
|
||||
|
||||
}, this.id._serialized, searchOptions);
|
||||
|
||||
return messages.map((msg) => new Message(this.client, msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the channel you created
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async deleteChannel() {
|
||||
return this.client.deleteChannel(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to change the channel metadata
|
||||
* @param {string|number|MessageMedia} value The new value to set
|
||||
* @param {string} property The property of a channel metadata to change
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async _setChannelMetadata(value, property) {
|
||||
return await this.client.pupPage.evaluate(async (channelId, value, property) => {
|
||||
const channel = await window.WWebJS.getChat(channelId, { getAsModel: false });
|
||||
if (!channel) return false;
|
||||
if (property.editPicture) {
|
||||
value.picture = value.picture
|
||||
? await window.WWebJS.cropAndResizeImage(value.picture, {
|
||||
asDataUrl: true,
|
||||
mimetype: 'image/jpeg',
|
||||
size: 640,
|
||||
quality: 1
|
||||
})
|
||||
: null;
|
||||
}
|
||||
try {
|
||||
await window.Store.ChannelUtils.editNewsletterMetadataAction(channel, property, value);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, value, property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to mute or unmute the channel
|
||||
* @param {string} action The action: 'MUTE' or 'UNMUTE'
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async _muteUnmuteChannel(action) {
|
||||
return await this.client.pupPage.evaluate(async (channelId, action) => {
|
||||
try {
|
||||
action === 'MUTE'
|
||||
? await window.Store.ChannelUtils.muteNewsletter([channelId])
|
||||
: await window.Store.ChannelUtils.unmuteNewsletter([channelId]);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, action);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Channel;
|
||||
329
node_modules/whatsapp-web.js/src/structures/Chat.js
generated
vendored
Normal file
329
node_modules/whatsapp-web.js/src/structures/Chat.js
generated
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
const Message = require('./Message');
|
||||
|
||||
/**
|
||||
* Represents a Chat on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Chat extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* ID that represents the chat
|
||||
* @type {object}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* Title of the chat
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = data.formattedTitle;
|
||||
|
||||
/**
|
||||
* Indicates if the Chat is a Group Chat
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isGroup = data.isGroup;
|
||||
|
||||
/**
|
||||
* Indicates if the Chat is readonly
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isReadOnly = data.isReadOnly;
|
||||
|
||||
/**
|
||||
* Amount of messages unread
|
||||
* @type {number}
|
||||
*/
|
||||
this.unreadCount = data.unreadCount;
|
||||
|
||||
/**
|
||||
* Unix timestamp for when the last activity occurred
|
||||
* @type {number}
|
||||
*/
|
||||
this.timestamp = data.t;
|
||||
|
||||
/**
|
||||
* Indicates if the Chat is archived
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.archived = data.archive;
|
||||
|
||||
/**
|
||||
* Indicates if the Chat is pinned
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.pinned = !!data.pin;
|
||||
|
||||
/**
|
||||
* Indicates if the chat is muted or not
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isMuted = data.isMuted;
|
||||
|
||||
/**
|
||||
* Unix timestamp for when the mute expires
|
||||
* @type {number}
|
||||
*/
|
||||
this.muteExpiration = data.muteExpiration;
|
||||
|
||||
/**
|
||||
* Last message fo chat
|
||||
* @type {Message}
|
||||
*/
|
||||
this.lastMessage = data.lastMessage ? new Message(this.client, data.lastMessage) : undefined;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to this chat
|
||||
* @param {string|MessageMedia|Location} content
|
||||
* @param {MessageSendOptions} [options]
|
||||
* @returns {Promise<Message>} Message that was just sent
|
||||
*/
|
||||
async sendMessage(content, options) {
|
||||
return this.client.sendMessage(this.id._serialized, content, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chat as seen
|
||||
* @returns {Promise<Boolean>} result
|
||||
*/
|
||||
async sendSeen() {
|
||||
return this.client.sendSeen(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all messages from the chat
|
||||
* @returns {Promise<boolean>} result
|
||||
*/
|
||||
async clearMessages() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
return window.WWebJS.sendClearChat(chatId);
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the chat
|
||||
* @returns {Promise<Boolean>} result
|
||||
*/
|
||||
async delete() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
return window.WWebJS.sendDeleteChat(chatId);
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Archives this chat
|
||||
*/
|
||||
async archive() {
|
||||
return this.client.archiveChat(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* un-archives this chat
|
||||
*/
|
||||
async unarchive() {
|
||||
return this.client.unarchiveChat(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins this chat
|
||||
* @returns {Promise<boolean>} New pin state. Could be false if the max number of pinned chats was reached.
|
||||
*/
|
||||
async pin() {
|
||||
return this.client.pinChat(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpins this chat
|
||||
* @returns {Promise<boolean>} New pin state
|
||||
*/
|
||||
async unpin() {
|
||||
return this.client.unpinChat(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutes this chat forever, unless a date is specified
|
||||
* @param {?Date} unmuteDate Date when the chat will be unmuted, don't provide a value to mute forever
|
||||
* @returns {Promise<{isMuted: boolean, muteExpiration: number}>}
|
||||
*/
|
||||
async mute(unmuteDate) {
|
||||
const result = await this.client.muteChat(this.id._serialized, unmuteDate);
|
||||
this.isMuted = result.isMuted;
|
||||
this.muteExpiration = result.muteExpiration;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmutes this chat
|
||||
* @returns {Promise<{isMuted: boolean, muteExpiration: number}>}
|
||||
*/
|
||||
async unmute() {
|
||||
const result = await this.client.unmuteChat(this.id._serialized);
|
||||
this.isMuted = result.isMuted;
|
||||
this.muteExpiration = result.muteExpiration;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 and fromMe is supported.
|
||||
* @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.
|
||||
* @param {Boolean} [searchOptions.fromMe] Return only messages from the bot number or vise versa. To get all messages, leave the option undefined.
|
||||
* @returns {Promise<Array<Message>>}
|
||||
*/
|
||||
async fetchMessages(searchOptions) {
|
||||
let messages = await this.client.pupPage.evaluate(async (chatId, searchOptions) => {
|
||||
const msgFilter = (m) => {
|
||||
if (m.isNotification) {
|
||||
return false; // dont include notification messages
|
||||
}
|
||||
if (searchOptions && searchOptions.fromMe !== undefined && m.id.fromMe !== searchOptions.fromMe) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
let msgs = chat.msgs.getModelsArray().filter(msgFilter);
|
||||
|
||||
if (searchOptions && searchOptions.limit > 0) {
|
||||
while (msgs.length < searchOptions.limit) {
|
||||
const loadedMessages = await window.Store.ConversationMsgs.loadEarlierMsgs(chat,chat.msgs);
|
||||
if (!loadedMessages || !loadedMessages.length) 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);
|
||||
}
|
||||
}
|
||||
|
||||
return msgs.map(m => window.WWebJS.getMessageModel(m));
|
||||
|
||||
}, this.id._serialized, searchOptions);
|
||||
|
||||
return messages.map(m => new Message(this.client, m));
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate typing in chat. This will last for 25 seconds.
|
||||
*/
|
||||
async sendStateTyping() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
window.WWebJS.sendChatstate('typing', chatId);
|
||||
return true;
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate recording audio in chat. This will last for 25 seconds.
|
||||
*/
|
||||
async sendStateRecording() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
window.WWebJS.sendChatstate('recording', chatId);
|
||||
return true;
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops typing or recording in chat immediately.
|
||||
*/
|
||||
async clearState() {
|
||||
return this.client.pupPage.evaluate(chatId => {
|
||||
window.WWebJS.sendChatstate('stop', chatId);
|
||||
return true;
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Contact that corresponds to this Chat.
|
||||
* @returns {Promise<Contact>}
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or remove labels to this Chat
|
||||
* @param {Array<number|string>} labelIds
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async changeLabels(labelIds) {
|
||||
return this.client.addOrRemoveLabels(labelIds, [this.id._serialized]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets instances of all pinned messages in a chat
|
||||
* @returns {Promise<Array<Message>>}
|
||||
*/
|
||||
async getPinnedMessages() {
|
||||
return this.client.getPinnedMessages(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync chat history conversation
|
||||
* @return {Promise<boolean>} True if operation completed successfully, false otherwise.
|
||||
*/
|
||||
async syncHistory() {
|
||||
return this.client.syncHistory(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or edit a customer note
|
||||
* @see https://faq.whatsapp.com/1433099287594476
|
||||
* @param {string} note The note to add
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async addOrEditCustomerNote(note) {
|
||||
if (this.isGroup || this.isChannel) return;
|
||||
|
||||
return this.client.addOrEditCustomerNote(this.id._serialized, note);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a customer note
|
||||
* @see https://faq.whatsapp.com/1433099287594476
|
||||
* @returns {Promise<{
|
||||
* chatId: string,
|
||||
* content: string,
|
||||
* createdAt: number,
|
||||
* id: string,
|
||||
* modifiedAt: number,
|
||||
* type: string
|
||||
* }>}
|
||||
*/
|
||||
async getCustomerNote() {
|
||||
if (this.isGroup || this.isChannel) return null;
|
||||
|
||||
return this.client.getCustomerNote(this.id._serialized);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Chat;
|
||||
71
node_modules/whatsapp-web.js/src/structures/ClientInfo.js
generated
vendored
Normal file
71
node_modules/whatsapp-web.js/src/structures/ClientInfo.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
|
||||
/**
|
||||
* Current connection information
|
||||
* @extends {Base}
|
||||
*/
|
||||
class ClientInfo extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* Name configured to be shown in push notifications
|
||||
* @type {string}
|
||||
*/
|
||||
this.pushname = data.pushname;
|
||||
|
||||
/**
|
||||
* Current user ID
|
||||
* @type {object}
|
||||
*/
|
||||
this.wid = data.wid;
|
||||
|
||||
/**
|
||||
* @type {object}
|
||||
* @deprecated Use .wid instead
|
||||
*/
|
||||
this.me = data.wid;
|
||||
|
||||
/**
|
||||
* Information about the phone this client is connected to. Not available in multi-device.
|
||||
* @type {object}
|
||||
* @property {string} wa_version WhatsApp Version running on the phone
|
||||
* @property {string} os_version OS Version running on the phone (iOS or Android version)
|
||||
* @property {string} device_manufacturer Device manufacturer
|
||||
* @property {string} device_model Device model
|
||||
* @property {string} os_build_number OS build number
|
||||
* @deprecated
|
||||
*/
|
||||
this.phone = data.phone;
|
||||
|
||||
/**
|
||||
* Platform WhatsApp is running on
|
||||
* @type {string}
|
||||
*/
|
||||
this.platform = data.platform;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current battery percentage and charging status for the attached device
|
||||
* @returns {object} batteryStatus
|
||||
* @returns {number} batteryStatus.battery - The current battery percentage
|
||||
* @returns {boolean} batteryStatus.plugged - Indicates if the phone is plugged in (true) or not (false)
|
||||
* @deprecated
|
||||
*/
|
||||
async getBatteryStatus() {
|
||||
return await this.client.pupPage.evaluate(() => {
|
||||
const { battery, plugged } = window.Store.Conn;
|
||||
return { battery, plugged };
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ClientInfo;
|
||||
215
node_modules/whatsapp-web.js/src/structures/Contact.js
generated
vendored
Normal file
215
node_modules/whatsapp-web.js/src/structures/Contact.js
generated
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
'use strict';
|
||||
|
||||
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}
|
||||
*/
|
||||
class Contact extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if(data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* ID that represents the contact
|
||||
* @type {ContactId}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* Contact's phone number
|
||||
* @type {string}
|
||||
*/
|
||||
this.number = data.userid;
|
||||
|
||||
/**
|
||||
* Indicates if the contact is a business contact
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isBusiness = data.isBusiness;
|
||||
|
||||
/**
|
||||
* Indicates if the contact is an enterprise contact
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isEnterprise = data.isEnterprise;
|
||||
|
||||
this.labels = data.labels;
|
||||
|
||||
/**
|
||||
* The contact's name, as saved by the current user
|
||||
* @type {?string}
|
||||
*/
|
||||
this.name = data.name;
|
||||
|
||||
/**
|
||||
* The name that the contact has configured to be shown publically
|
||||
* @type {string}
|
||||
*/
|
||||
this.pushname = data.pushname;
|
||||
|
||||
this.sectionHeader = data.sectionHeader;
|
||||
|
||||
/**
|
||||
* A shortened version of name
|
||||
* @type {?string}
|
||||
*/
|
||||
this.shortName = data.shortName;
|
||||
|
||||
this.statusMute = data.statusMute;
|
||||
this.type = data.type;
|
||||
this.verifiedLevel = data.verifiedLevel;
|
||||
this.verifiedName = data.verifiedName;
|
||||
|
||||
/**
|
||||
* Indicates if the contact is the current user's contact
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isMe = data.isMe;
|
||||
|
||||
/**
|
||||
* Indicates if the contact is a user contact
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isUser = data.isUser;
|
||||
|
||||
/**
|
||||
* Indicates if the contact is a group contact
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isGroup = data.isGroup;
|
||||
|
||||
/**
|
||||
* Indicates if the number is registered on WhatsApp
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isWAContact = data.isWAContact;
|
||||
|
||||
/**
|
||||
* Indicates if the number is saved in the current phone's contacts
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isMyContact = data.isMyContact;
|
||||
|
||||
/**
|
||||
* Indicates if you have blocked this contact
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isBlocked = data.isBlocked;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contact's profile picture URL, if privacy settings allow it
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async getProfilePicUrl() {
|
||||
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.
|
||||
* @returns {Promise<Chat>}
|
||||
*/
|
||||
async getChat() {
|
||||
if(this.isMe) return null;
|
||||
|
||||
return await this.client.getChatById(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks this contact from WhatsApp
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async block() {
|
||||
if(this.isGroup) return false;
|
||||
|
||||
await this.client.pupPage.evaluate(async (contactId) => {
|
||||
const contact = window.Store.Contact.get(contactId);
|
||||
await window.Store.BlockContact.blockContact({contact});
|
||||
}, this.id._serialized);
|
||||
|
||||
this.isBlocked = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblocks this contact from WhatsApp
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async unblock() {
|
||||
if(this.isGroup) return false;
|
||||
|
||||
await this.client.pupPage.evaluate(async (contactId) => {
|
||||
const contact = window.Store.Contact.get(contactId);
|
||||
await window.Store.BlockContact.unblockContact(contact);
|
||||
}, this.id._serialized);
|
||||
|
||||
this.isBlocked = false;
|
||||
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) => {
|
||||
const wid = window.Store.WidFactory.createWid(contactId);
|
||||
return window.Store.StatusUtils.getStatus({'token':'', 'wid': wid});
|
||||
}, this.id._serialized);
|
||||
|
||||
if (typeof about.status !== 'string')
|
||||
return null;
|
||||
|
||||
return about.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Contact's common groups with you. Returns empty array if you don't have any common group.
|
||||
* @returns {Promise<WAWebJS.ChatId[]>}
|
||||
*/
|
||||
async getCommonGroups() {
|
||||
return await this.client.getCommonGroups(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Contact's current status broadcast.
|
||||
* @returns {Promise<Broadcast>}
|
||||
*/
|
||||
async getBroadcast() {
|
||||
return await this.client.getBroadcastById(this.id._serialized);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Contact;
|
||||
485
node_modules/whatsapp-web.js/src/structures/GroupChat.js
generated
vendored
Normal file
485
node_modules/whatsapp-web.js/src/structures/GroupChat.js
generated
vendored
Normal file
@@ -0,0 +1,485 @@
|
||||
'use strict';
|
||||
|
||||
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}
|
||||
*/
|
||||
class GroupChat extends Chat {
|
||||
_patch(data) {
|
||||
this.groupMetadata = data.groupMetadata;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the group owner
|
||||
* @type {ContactId}
|
||||
*/
|
||||
get owner() {
|
||||
return this.groupMetadata.owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the date at which the group was created
|
||||
* @type {date}
|
||||
*/
|
||||
get createdAt() {
|
||||
return new Date(this.groupMetadata.creation * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the group description
|
||||
* @type {string}
|
||||
*/
|
||||
get description() {
|
||||
return this.groupMetadata.desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the group participants
|
||||
* @type {Array<GroupParticipant>}
|
||||
*/
|
||||
get participants() {
|
||||
return this.groupMetadata.participants;
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that handles the result for {@link addParticipants} method
|
||||
* @typedef {Object} AddParticipantsResult
|
||||
* @property {number} code The code of the result
|
||||
* @property {string} message The result message
|
||||
* @property {boolean} isInviteV4Sent Indicates if the inviteV4 was sent to the partitipant
|
||||
*/
|
||||
|
||||
/**
|
||||
* An object that handles options for adding participants
|
||||
* @typedef {Object} AddParticipnatsOptions
|
||||
* @property {Array<number>|number} [sleep = [250, 500]] The number of milliseconds to wait before adding the next participant. If it is an array, a random sleep time between the sleep[0] and sleep[1] values will be added (the difference must be >=100 ms, otherwise, a random sleep time between sleep[1] and sleep[1] + 100 will be added). If sleep is a number, a sleep time equal to its value will be added. By default, sleep is an array with a value of [250, 500]
|
||||
* @property {boolean} [autoSendInviteV4 = true] If true, the inviteV4 will be sent to those participants who have restricted others from being automatically added to groups, otherwise the inviteV4 won't be sent (true by default)
|
||||
* @property {string} [comment = ''] The comment to be added to an inviteV4 (empty string by default)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds a list of participants by ID to the group
|
||||
* @param {string|Array<string>} participantIds
|
||||
* @param {AddParticipnatsOptions} options An object thay handles options for adding participants
|
||||
* @returns {Promise<Object.<string, AddParticipantsResult>|string>} Returns an object with the resulting data or an error message as a string
|
||||
*/
|
||||
async addParticipants(participantIds, options = {}) {
|
||||
return await this.client.pupPage.evaluate(async (groupId, participantIds, options) => {
|
||||
const { sleep = [250, 500], autoSendInviteV4 = true, comment = '' } = options;
|
||||
const participantData = {};
|
||||
|
||||
!Array.isArray(participantIds) && (participantIds = [participantIds]);
|
||||
const groupWid = window.Store.WidFactory.createWid(groupId);
|
||||
const group = window.Store.Chat.get(groupWid) || (await window.Store.Chat.find(groupWid));
|
||||
const participantWids = participantIds.map((p) => window.Store.WidFactory.createWid(p));
|
||||
|
||||
const errorCodes = {
|
||||
default: 'An unknown error occupied while adding a participant',
|
||||
isGroupEmpty: 'AddParticipantsError: The participant can\'t be added to an empty group',
|
||||
iAmNotAdmin: 'AddParticipantsError: You have no admin rights to add a participant to a group',
|
||||
200: 'The participant was added successfully',
|
||||
403: 'The participant can be added by sending private invitation only',
|
||||
404: 'The phone number is not registered on WhatsApp',
|
||||
408: 'You cannot add this participant because they recently left the group',
|
||||
409: 'The participant is already a group member',
|
||||
417: 'The participant can\'t be added to the community. You can invite them privately to join this group through its invite link',
|
||||
419: 'The participant can\'t be added because the group is full'
|
||||
};
|
||||
|
||||
await window.Store.GroupQueryAndUpdate({ id: groupId });
|
||||
|
||||
let groupParticipants = group.groupMetadata?.participants.serialize();
|
||||
|
||||
if (!groupParticipants) {
|
||||
return errorCodes.isGroupEmpty;
|
||||
}
|
||||
|
||||
if (!group.iAmAdmin()) {
|
||||
return errorCodes.iAmNotAdmin;
|
||||
}
|
||||
|
||||
groupParticipants.map(({ id }) => {
|
||||
return id.server === 'lid' ? window.Store.LidUtils.getPhoneNumber(id) : id;
|
||||
});
|
||||
|
||||
const _getSleepTime = (sleep) => {
|
||||
if (!Array.isArray(sleep) || sleep.length === 2 && sleep[0] === sleep[1]) {
|
||||
return sleep;
|
||||
}
|
||||
if (sleep.length === 1) {
|
||||
return sleep[0];
|
||||
}
|
||||
(sleep[1] - sleep[0]) < 100 && (sleep[0] = sleep[1]) && (sleep[1] += 100);
|
||||
return Math.floor(Math.random() * (sleep[1] - sleep[0] + 1)) + sleep[0];
|
||||
};
|
||||
|
||||
for (let pWid of participantWids) {
|
||||
const pId = pWid._serialized;
|
||||
pWid = pWid.server === 'lid' ? window.Store.LidUtils.getPhoneNumber(pWid) : pWid;
|
||||
|
||||
participantData[pId] = {
|
||||
code: undefined,
|
||||
message: undefined,
|
||||
isInviteV4Sent: false
|
||||
};
|
||||
|
||||
if (groupParticipants.some(p => p._serialized === pId)) {
|
||||
participantData[pId].code = 409;
|
||||
participantData[pId].message = errorCodes[409];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(await window.Store.QueryExist(pWid))?.wid) {
|
||||
participantData[pId].code = 404;
|
||||
participantData[pId].message = errorCodes[404];
|
||||
continue;
|
||||
}
|
||||
|
||||
const rpcResult =
|
||||
await window.WWebJS.getAddParticipantsRpcResult(groupWid, pWid);
|
||||
const { code: rpcResultCode } = rpcResult;
|
||||
|
||||
participantData[pId].code = rpcResultCode;
|
||||
participantData[pId].message =
|
||||
errorCodes[rpcResultCode] || errorCodes.default;
|
||||
|
||||
if (autoSendInviteV4 && rpcResultCode === 403) {
|
||||
let userChat, isInviteV4Sent = false;
|
||||
window.Store.Contact.gadd(pWid, { silent: true });
|
||||
|
||||
if (rpcResult.name === 'ParticipantRequestCodeCanBeSent' &&
|
||||
(userChat = window.Store.Chat.get(pWid) || (await window.Store.Chat.find(pWid)))) {
|
||||
const groupName = group.formattedTitle || group.name;
|
||||
const res = await window.Store.GroupInviteV4.sendGroupInviteMessage(
|
||||
userChat,
|
||||
group.id._serialized,
|
||||
groupName,
|
||||
rpcResult.inviteV4Code,
|
||||
rpcResult.inviteV4CodeExp,
|
||||
comment,
|
||||
await window.WWebJS.getProfilePicThumbToBase64(groupWid)
|
||||
);
|
||||
isInviteV4Sent = res.messageSendResult === 'OK';
|
||||
}
|
||||
|
||||
participantData[pId].isInviteV4Sent = isInviteV4Sent;
|
||||
}
|
||||
|
||||
sleep &&
|
||||
participantWids.length > 1 &&
|
||||
participantWids.indexOf(pWid) !== participantWids.length - 1 &&
|
||||
(await new Promise((resolve) => setTimeout(resolve, _getSleepTime(sleep))));
|
||||
}
|
||||
|
||||
return participantData;
|
||||
}, this.id._serialized, participantIds, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a list of participants by ID to the group
|
||||
* @param {Array<string>} participantIds
|
||||
* @returns {Promise<{ status: number }>}
|
||||
*/
|
||||
async removeParticipants(participantIds) {
|
||||
return await this.client.pupPage.evaluate(async (chatId, participantIds) => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
const participants = (await Promise.all(participantIds.map(async p => {
|
||||
const { lid, phone } = await window.WWebJS.enforceLidAndPnRetrieval(p);
|
||||
|
||||
return chat.groupMetadata.participants.get(lid?._serialized) ||
|
||||
chat.groupMetadata.participants.get(phone?._serialized);
|
||||
}))).filter(Boolean);
|
||||
await window.Store.GroupParticipants.removeParticipants(chat, participants);
|
||||
return { status: 200 };
|
||||
}, this.id._serialized, participantIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(async (chatId, participantIds) => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
const participants = (await Promise.all(participantIds.map(async p => {
|
||||
const { lid, phone } = await window.WWebJS.enforceLidAndPnRetrieval(p);
|
||||
|
||||
return chat.groupMetadata.participants.get(lid?._serialized) ||
|
||||
chat.groupMetadata.participants.get(phone?._serialized);
|
||||
}))).filter(Boolean);
|
||||
await window.Store.GroupParticipants.promoteParticipants(chat, participants);
|
||||
return { status: 200 };
|
||||
}, this.id._serialized, participantIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(async (chatId, participantIds) => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
const participants = (await Promise.all(participantIds.map(async p => {
|
||||
const { lid, phone } = await window.WWebJS.enforceLidAndPnRetrieval(p);
|
||||
|
||||
return chat.groupMetadata.participants.get(lid?._serialized) ||
|
||||
chat.groupMetadata.participants.get(phone?._serialized);
|
||||
}))).filter(Boolean);
|
||||
await window.Store.GroupParticipants.demoteParticipants(chat, participants);
|
||||
return { status: 200 };
|
||||
}, this.id._serialized, participantIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the group subject
|
||||
* @param {string} subject
|
||||
* @returns {Promise<boolean>} Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.
|
||||
*/
|
||||
async setSubject(subject) {
|
||||
const success = await this.client.pupPage.evaluate(async (chatId, subject) => {
|
||||
const chatWid = window.Store.WidFactory.createWid(chatId);
|
||||
try {
|
||||
await window.Store.GroupUtils.setGroupSubject(chatWid, subject);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, subject);
|
||||
|
||||
if(!success) return false;
|
||||
this.name = subject;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the group description
|
||||
* @param {string} description
|
||||
* @returns {Promise<boolean>} Returns true if the description was properly updated. This can return false if the user does not have the necessary permissions.
|
||||
*/
|
||||
async setDescription(description) {
|
||||
const success = await this.client.pupPage.evaluate(async (chatId, description) => {
|
||||
const chatWid = window.Store.WidFactory.createWid(chatId);
|
||||
let descId = window.Store.GroupMetadata.get(chatWid).descId;
|
||||
let newId = await window.Store.MsgKey.newId();
|
||||
try {
|
||||
await window.Store.GroupUtils.setGroupDescription(chatWid, description, newId, descId);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, description);
|
||||
|
||||
if(!success) return false;
|
||||
this.groupMetadata.desc = description;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the group setting to allow only admins to add members to the group.
|
||||
* @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.
|
||||
*/
|
||||
async setAddMembersAdminsOnly(adminsOnly=true) {
|
||||
const success = await this.client.pupPage.evaluate(async (groupId, adminsOnly) => {
|
||||
const chat = await window.WWebJS.getChat(groupId, { getAsModel: false });
|
||||
try {
|
||||
await window.Store.GroupUtils.setGroupProperty(chat, 'member_add_mode', adminsOnly ? 0 : 1);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, adminsOnly);
|
||||
|
||||
success && (this.groupMetadata.memberAddMode = adminsOnly ? 'admin_add' : 'all_member_add');
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
async setMessagesAdminsOnly(adminsOnly=true) {
|
||||
const success = await this.client.pupPage.evaluate(async (chatId, adminsOnly) => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
try {
|
||||
await window.Store.GroupUtils.setGroupProperty(chat, 'announcement', adminsOnly ? 1 : 0);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, adminsOnly);
|
||||
|
||||
if(!success) return false;
|
||||
|
||||
this.groupMetadata.announce = adminsOnly;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
async setInfoAdminsOnly(adminsOnly=true) {
|
||||
const success = await this.client.pupPage.evaluate(async (chatId, adminsOnly) => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
try {
|
||||
await window.Store.GroupUtils.setGroupProperty(chat, 'restrict', adminsOnly ? 1 : 0);
|
||||
return true;
|
||||
} catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return false;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized, adminsOnly);
|
||||
|
||||
if(!success) return false;
|
||||
|
||||
this.groupMetadata.restrict = adminsOnly;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the group's picture.
|
||||
* @returns {Promise<boolean>} Returns true if the picture was properly deleted. This can return false if the user does not have the necessary permissions.
|
||||
*/
|
||||
async deletePicture() {
|
||||
const success = await this.client.pupPage.evaluate((chatid) => {
|
||||
return window.WWebJS.deletePicture(chatid);
|
||||
}, this.id._serialized);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the group's picture.
|
||||
* @param {MessageMedia} media
|
||||
* @returns {Promise<boolean>} Returns true if the picture was properly updated. This can return false if the user does not have the necessary permissions.
|
||||
*/
|
||||
async setPicture(media) {
|
||||
const success = await this.client.pupPage.evaluate((chatid, media) => {
|
||||
return window.WWebJS.setPicture(chatid, media);
|
||||
}, this.id._serialized, media);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the invite code for a specific group
|
||||
* @returns {Promise<string>} Group's invite code
|
||||
*/
|
||||
async getInviteCode() {
|
||||
const codeRes = await this.client.pupPage.evaluate(async chatId => {
|
||||
const chatWid = window.Store.WidFactory.createWid(chatId);
|
||||
try {
|
||||
return window.compareWwebVersions(window.Debug.VERSION, '>=', '2.3000.1020730154')
|
||||
? await window.Store.GroupInvite.fetchMexGroupInviteCode(chatId)
|
||||
: await window.Store.GroupInvite.queryGroupInviteCode(chatWid, true);
|
||||
}
|
||||
catch (err) {
|
||||
if(err.name === 'ServerStatusCodeError') return undefined;
|
||||
throw err;
|
||||
}
|
||||
}, this.id._serialized);
|
||||
|
||||
return codeRes?.code
|
||||
? codeRes?.code
|
||||
: codeRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the current group invite code and generates a new one
|
||||
* @returns {Promise<string>} New invite code
|
||||
*/
|
||||
async revokeInvite() {
|
||||
const codeRes = await this.client.pupPage.evaluate(chatId => {
|
||||
const chatWid = window.Store.WidFactory.createWid(chatId);
|
||||
return window.Store.GroupInvite.resetGroupInviteCode(chatWid);
|
||||
}, this.id._serialized);
|
||||
|
||||
return codeRes.code;
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that handles the information about the group membership request
|
||||
* @typedef {Object} GroupMembershipRequest
|
||||
* @property {Object} id The wid of a user who requests to enter the group
|
||||
* @property {Object} addedBy The wid of a user who created that request
|
||||
* @property {Object|null} parentGroupId The wid of a community parent group to which the current group is linked
|
||||
* @property {string} requestMethod The method used to create the request: NonAdminAdd/InviteLink/LinkedGroupJoin
|
||||
* @property {number} t The timestamp the request was created at
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets an array of membership requests
|
||||
* @returns {Promise<Array<GroupMembershipRequest>>} An array of membership requests
|
||||
*/
|
||||
async getGroupMembershipRequests() {
|
||||
return await this.client.getGroupMembershipRequests(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that handles the result for membership request action
|
||||
* @typedef {Object} MembershipRequestActionResult
|
||||
* @property {string} requesterId User ID whos membership request was approved/rejected
|
||||
* @property {number} error An error code that occurred during the operation for the participant
|
||||
* @property {string} message A message with a result of membership request action
|
||||
*/
|
||||
|
||||
/**
|
||||
* An object that handles options for {@link approveGroupMembershipRequests} and {@link rejectGroupMembershipRequests} methods
|
||||
* @typedef {Object} MembershipRequestActionOptions
|
||||
* @property {Array<string>|string|null} requesterIds User ID/s who requested to join the group, if no value is provided, the method will search for all membership requests for that group
|
||||
* @property {Array<number>|number|null} sleep The number of milliseconds to wait before performing an operation for the next requester. If it is an array, a random sleep time between the sleep[0] and sleep[1] values will be added (the difference must be >=100 ms, otherwise, a random sleep time between sleep[1] and sleep[1] + 100 will be added). If sleep is a number, a sleep time equal to its value will be added. By default, sleep is an array with a value of [250, 500]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Approves membership requests if any
|
||||
* @param {MembershipRequestActionOptions} options Options for performing a membership request action
|
||||
* @returns {Promise<Array<MembershipRequestActionResult>>} Returns an array of requester IDs whose membership requests were approved and an error for each requester, if any occurred during the operation. If there are no requests, an empty array will be returned
|
||||
*/
|
||||
async approveGroupMembershipRequests(options = {}) {
|
||||
return await this.client.approveGroupMembershipRequests(this.id._serialized, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rejects membership requests if any
|
||||
* @param {MembershipRequestActionOptions} options Options for performing a membership request action
|
||||
* @returns {Promise<Array<MembershipRequestActionResult>>} Returns an array of requester IDs whose membership requests were rejected and an error for each requester, if any occurred during the operation. If there are no requests, an empty array will be returned
|
||||
*/
|
||||
async rejectGroupMembershipRequests(options = {}) {
|
||||
return await this.client.rejectGroupMembershipRequests(this.id._serialized, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the bot leave the group
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async leave() {
|
||||
await this.client.pupPage.evaluate(async chatId => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
return window.Store.GroupUtils.sendExitGroup(chat);
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GroupChat;
|
||||
104
node_modules/whatsapp-web.js/src/structures/GroupNotification.js
generated
vendored
Normal file
104
node_modules/whatsapp-web.js/src/structures/GroupNotification.js
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
|
||||
/**
|
||||
* Represents a GroupNotification on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class GroupNotification extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if(data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* ID that represents the groupNotification
|
||||
* @type {object}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* Extra content
|
||||
* @type {string}
|
||||
*/
|
||||
this.body = data.body || '';
|
||||
|
||||
/**
|
||||
* GroupNotification type
|
||||
* @type {GroupNotificationTypes}
|
||||
*/
|
||||
this.type = data.subtype;
|
||||
|
||||
/**
|
||||
* Unix timestamp for when the groupNotification was created
|
||||
* @type {number}
|
||||
*/
|
||||
this.timestamp = data.t;
|
||||
|
||||
/**
|
||||
* ID for the Chat that this groupNotification was sent for.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.chatId = typeof (data.id.remote) === 'object' ? data.id.remote._serialized : data.id.remote;
|
||||
|
||||
/**
|
||||
* ContactId for the user that produced the GroupNotification.
|
||||
* @type {string}
|
||||
*/
|
||||
this.author = typeof (data.author) === 'object' ? data.author._serialized : data.author;
|
||||
|
||||
/**
|
||||
* Contact IDs for the users that were affected by this GroupNotification.
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
this.recipientIds = [];
|
||||
|
||||
if (data.recipients) {
|
||||
this.recipientIds = data.recipients;
|
||||
}
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Chat this groupNotification was sent in
|
||||
* @returns {Promise<Chat>}
|
||||
*/
|
||||
getChat() {
|
||||
return this.client.getChatById(this.chatId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Contact this GroupNotification was produced by
|
||||
* @returns {Promise<Contact>}
|
||||
*/
|
||||
getContact() {
|
||||
return this.client.getContactById(this.author);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Contacts affected by this GroupNotification.
|
||||
* @returns {Promise<Array<Contact>>}
|
||||
*/
|
||||
async getRecipients() {
|
||||
return await Promise.all(this.recipientIds.map(async m => await this.client.getContactById(m)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the same chat this GroupNotification was produced in.
|
||||
*
|
||||
* @param {string|MessageMedia|Location} content
|
||||
* @param {object} options
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
async reply(content, options={}) {
|
||||
return this.client.sendMessage(this.chatId, content, options);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GroupNotification;
|
||||
50
node_modules/whatsapp-web.js/src/structures/Label.js
generated
vendored
Normal file
50
node_modules/whatsapp-web.js/src/structures/Label.js
generated
vendored
Normal 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
node_modules/whatsapp-web.js/src/structures/List.js
generated
vendored
Normal file
79
node_modules/whatsapp-web.js/src/structures/List.js
generated
vendored
Normal 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;
|
||||
62
node_modules/whatsapp-web.js/src/structures/Location.js
generated
vendored
Normal file
62
node_modules/whatsapp-web.js/src/structures/Location.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Location send options
|
||||
* @typedef {Object} LocationSendOptions
|
||||
* @property {string} [name] Location name
|
||||
* @property {string} [address] Location address
|
||||
* @property {string} [url] URL address to be shown within a location message
|
||||
* @property {string} [description] Location full description
|
||||
*/
|
||||
|
||||
/**
|
||||
* Location information
|
||||
*/
|
||||
class Location {
|
||||
/**
|
||||
* @param {number} latitude
|
||||
* @param {number} longitude
|
||||
* @param {LocationSendOptions} [options] Location send options
|
||||
*/
|
||||
constructor(latitude, longitude, options = {}) {
|
||||
/**
|
||||
* Location latitude
|
||||
* @type {number}
|
||||
*/
|
||||
this.latitude = latitude;
|
||||
|
||||
/**
|
||||
* Location longitude
|
||||
* @type {number}
|
||||
*/
|
||||
this.longitude = longitude;
|
||||
|
||||
/**
|
||||
* Name for the location
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.name = options.name;
|
||||
|
||||
/**
|
||||
* Location address
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.address = options.address;
|
||||
|
||||
/**
|
||||
* URL address to be shown within a location message
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.url = options.url;
|
||||
|
||||
/**
|
||||
* Location full description
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.description = this.name && this.address
|
||||
? `${this.name}\n${this.address}`
|
||||
: this.name || this.address || '';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Location;
|
||||
787
node_modules/whatsapp-web.js/src/structures/Message.js
generated
vendored
Normal file
787
node_modules/whatsapp-web.js/src/structures/Message.js
generated
vendored
Normal file
@@ -0,0 +1,787 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
const MessageMedia = require('./MessageMedia');
|
||||
const Location = require('./Location');
|
||||
const Order = require('./Order');
|
||||
const Payment = require('./Payment');
|
||||
const Reaction = require('./Reaction');
|
||||
const Contact = require('./Contact');
|
||||
const ScheduledEvent = require('./ScheduledEvent'); // eslint-disable-line no-unused-vars
|
||||
const { MessageTypes } = require('../util/Constants');
|
||||
|
||||
/**
|
||||
* Represents a Message on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Message extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
this._data = data;
|
||||
|
||||
/**
|
||||
* MediaKey that represents the sticker 'ID'
|
||||
* @type {string}
|
||||
*/
|
||||
this.mediaKey = data.mediaKey;
|
||||
|
||||
/**
|
||||
* ID that represents the message
|
||||
* @type {object}
|
||||
*/
|
||||
this.id = data.id;
|
||||
|
||||
/**
|
||||
* ACK status for the message
|
||||
* @type {MessageAck}
|
||||
*/
|
||||
this.ack = data.ack;
|
||||
|
||||
/**
|
||||
* Indicates if the message has media available for download
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hasMedia = Boolean(data.directPath);
|
||||
|
||||
/**
|
||||
* Message content
|
||||
* @type {string}
|
||||
*/
|
||||
this.body = this.hasMedia ? data.caption || '' : data.body || data.pollName || data.eventName || '';
|
||||
|
||||
/**
|
||||
* Message type
|
||||
* @type {MessageTypes}
|
||||
*/
|
||||
this.type = data.type;
|
||||
|
||||
/**
|
||||
* Unix timestamp for when the message was created
|
||||
* @type {number}
|
||||
*/
|
||||
this.timestamp = data.t;
|
||||
|
||||
/**
|
||||
* ID for the Chat that this message was sent to, except if the message was sent by the current user.
|
||||
* @type {string}
|
||||
*/
|
||||
this.from = (typeof (data.from) === 'object' && data.from !== null) ? data.from._serialized : data.from;
|
||||
|
||||
/**
|
||||
* ID for who this message is for.
|
||||
*
|
||||
* If the message is sent by the current user, it will be the Chat to which the message is being sent.
|
||||
* If the message is sent by another user, it will be the ID for the current user.
|
||||
* @type {string}
|
||||
*/
|
||||
this.to = (typeof (data.to) === 'object' && data.to !== null) ? data.to._serialized : data.to;
|
||||
|
||||
/**
|
||||
* If the message was sent to a group, this field will contain the user that sent the message.
|
||||
* @type {string}
|
||||
*/
|
||||
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 = typeof data.id.id === 'string' && data.id.id.length > 21 ? 'android' : typeof data.id.id === 'string' && 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 || data.id.remote === 'status@broadcast';
|
||||
|
||||
/**
|
||||
* Indicates if the message was starred
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isStarred = data.star;
|
||||
|
||||
/**
|
||||
* Indicates if the message was a broadcast
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.broadcast = data.broadcast;
|
||||
|
||||
/**
|
||||
* Indicates if the message was sent by the current user
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.fromMe = data.id.fromMe;
|
||||
|
||||
/**
|
||||
* Indicates if the message was sent as a reply to another message.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hasQuotedMsg = data.quotedMsg ? true : false;
|
||||
|
||||
/**
|
||||
* Indicates whether there are reactions to the message
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hasReaction = data.hasReaction ? true : false;
|
||||
|
||||
/**
|
||||
* Indicates the duration of the message in seconds
|
||||
* @type {string}
|
||||
*/
|
||||
this.duration = data.duration ? data.duration : undefined;
|
||||
|
||||
/**
|
||||
* Location information contained in the message, if the message is type "location"
|
||||
* @type {Location}
|
||||
*/
|
||||
this.location = (() => {
|
||||
if (data.type !== MessageTypes.LOCATION) {
|
||||
return undefined;
|
||||
}
|
||||
let description;
|
||||
if (data.loc && typeof data.loc === 'string') {
|
||||
let splitted = data.loc.split('\n');
|
||||
description = {
|
||||
name: splitted[0],
|
||||
address: splitted[1],
|
||||
url: data.clientUrl
|
||||
};
|
||||
}
|
||||
return new Location(data.lat, data.lng, description);
|
||||
})();
|
||||
|
||||
/**
|
||||
* List of vCards contained in the message.
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
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: typeof data.from === 'object' && '_serialized' in data.from ? data.from._serialized : data.from,
|
||||
toId: typeof data.to === 'object' && '_serialized' in data.to ? data.to._serialized : data.to
|
||||
} : undefined;
|
||||
|
||||
/**
|
||||
* Indicates the mentions in the message body.
|
||||
* @type {string[]}
|
||||
*/
|
||||
this.mentionedIds = data.mentionedJidList || [];
|
||||
|
||||
/**
|
||||
* @typedef {Object} GroupMention
|
||||
* @property {string} groupSubject The name of the group
|
||||
* @property {string} groupJid The group ID
|
||||
*/
|
||||
|
||||
/**
|
||||
* Indicates whether there are group mentions in the message body
|
||||
* @type {GroupMention[]}
|
||||
*/
|
||||
this.groupMentions = data.groupMentions || [];
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/** Last edit time */
|
||||
if (data.latestEditSenderTimestampMs) {
|
||||
this.latestEditSenderTimestampMs = data.latestEditSenderTimestampMs;
|
||||
}
|
||||
|
||||
/** Last edit message author */
|
||||
if (data.latestEditMsgKey) {
|
||||
this.latestEditMsgKey = data.latestEditMsgKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protocol message key.
|
||||
* Can be used to retrieve the ID of an original message that was revoked.
|
||||
*/
|
||||
if (data.protocolMessageKey) {
|
||||
this.protocolMessageKey = data.protocolMessageKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
if (this.type === MessageTypes.POLL_CREATION) {
|
||||
this.pollName = data.pollName;
|
||||
this.pollOptions = data.pollOptions;
|
||||
this.allowMultipleAnswers = Boolean(!data.pollSelectableOptionsCount);
|
||||
this.pollInvalidated = data.pollInvalidated;
|
||||
this.isSentCagPollCreation = data.isSentCagPollCreation;
|
||||
this.messageSecret = data.messageSecret ? Object.keys(data.messageSecret).map((key) => data.messageSecret[key]) : [];
|
||||
}
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
_getChatId() {
|
||||
return this.fromMe ? this.to : this.from;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads this Message object's data in-place with the latest values from WhatsApp Web.
|
||||
* Note that the Message must still be in the web app cache for this to work, otherwise will return null.
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
async reload() {
|
||||
const newData = await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if (!msg) return null;
|
||||
return window.WWebJS.getMessageModel(msg);
|
||||
}, this.id._serialized);
|
||||
|
||||
if(!newData) return null;
|
||||
|
||||
this._patch(newData);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns message in a raw format
|
||||
* @type {Object}
|
||||
*/
|
||||
get rawData() {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Chat this message was sent in
|
||||
* @returns {Promise<Chat>}
|
||||
*/
|
||||
getChat() {
|
||||
return this.client.getChatById(this._getChatId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Contact this message was sent from
|
||||
* @returns {Promise<Contact>}
|
||||
*/
|
||||
getContact() {
|
||||
return this.client.getContactById(this.author || this.from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Contacts mentioned in this message
|
||||
* @returns {Promise<Array<Contact>>}
|
||||
*/
|
||||
async getMentions() {
|
||||
return await Promise.all(this.mentionedIds.map(async m => await this.client.getContactById(m)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns groups mentioned in this message
|
||||
* @returns {Promise<Array<GroupChat>>}
|
||||
*/
|
||||
async getGroupMentions() {
|
||||
return await Promise.all(this.groupMentions.map(async (m) => await this.client.getChatById(m.groupJid._serialized)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the quoted message, if any
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
async getQuotedMessage() {
|
||||
if (!this.hasQuotedMsg) return undefined;
|
||||
|
||||
const quotedMsg = await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
const quotedMsg = window.Store.QuotedMsg.getQuotedMsgObj(msg);
|
||||
return window.WWebJS.getMessageModel(quotedMsg);
|
||||
}, this.id._serialized);
|
||||
|
||||
return new Message(this.client, quotedMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message as a reply to this message. If chatId is specified, it will be sent
|
||||
* through the specified Chat. If not, it will send the message
|
||||
* in the same Chat as the original message was sent.
|
||||
*
|
||||
* @param {string|MessageMedia|Location} content
|
||||
* @param {string} [chatId]
|
||||
* @param {MessageSendOptions} [options]
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
async reply(content, chatId, options = {}) {
|
||||
if (!chatId) {
|
||||
chatId = this._getChatId();
|
||||
}
|
||||
|
||||
options = {
|
||||
...options,
|
||||
quotedMessageId: this.id._serialized
|
||||
};
|
||||
|
||||
return this.client.sendMessage(chatId, content, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* React to this message with an emoji
|
||||
* @param {string} reaction - Emoji to react with. Send an empty string to remove the reaction.
|
||||
* @return {Promise}
|
||||
*/
|
||||
async react(reaction){
|
||||
await this.client.pupPage.evaluate(async (messageId, reaction) => {
|
||||
if (!messageId) return null;
|
||||
const msg =
|
||||
window.Store.Msg.get(messageId) || (await window.Store.Msg.getMessagesById([messageId]))?.messages?.[0];
|
||||
if(!msg) return null;
|
||||
await window.Store.sendReactionToMsg(msg, reaction);
|
||||
}, this.id._serialized, reaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept Group V4 Invite
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
async acceptGroupV4Invite() {
|
||||
return await this.client.acceptGroupV4Invite(this.inviteV4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards this message to another chat (that you chatted before, otherwise it will fail)
|
||||
*
|
||||
* @param {string|Chat} chat Chat model or chat ID to which the message will be forwarded
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async forward(chat) {
|
||||
const chatId = typeof chat === 'string' ? chat : chat.id._serialized;
|
||||
|
||||
await this.client.pupPage.evaluate(async (msgId, chatId) => {
|
||||
return window.WWebJS.forwardMessage(chatId, msgId);
|
||||
}, this.id._serialized, chatId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads and returns the attatched message media
|
||||
* @returns {Promise<MessageMedia>}
|
||||
*/
|
||||
async downloadMedia() {
|
||||
if (!this.hasMedia) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result = await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
|
||||
// REUPLOADING mediaStage means the media is expired and the download button is spinning, cannot be downloaded now
|
||||
if (!msg || !msg.mediaData || msg.mediaData.mediaStage === 'REUPLOADING') {
|
||||
return null;
|
||||
}
|
||||
if (msg.mediaData.mediaStage != 'RESOLVED') {
|
||||
// try to resolve media
|
||||
await msg.downloadMedia({
|
||||
downloadEvenIfExpensive: true,
|
||||
rmrReason: 1
|
||||
});
|
||||
}
|
||||
|
||||
if (msg.mediaData.mediaStage.includes('ERROR') || msg.mediaData.mediaStage === 'FETCHING') {
|
||||
// media could not be downloaded
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
const mockQpl = {
|
||||
addAnnotations: function() { return this; },
|
||||
addPoint: function() { return this; }
|
||||
};
|
||||
const decryptedMedia = await window.Store.DownloadManager.downloadAndMaybeDecrypt({
|
||||
directPath: msg.directPath,
|
||||
encFilehash: msg.encFilehash,
|
||||
filehash: msg.filehash,
|
||||
mediaKey: msg.mediaKey,
|
||||
mediaKeyTimestamp: msg.mediaKeyTimestamp,
|
||||
type: msg.type,
|
||||
signal: (new AbortController).signal,
|
||||
downloadQpl: mockQpl
|
||||
});
|
||||
|
||||
const data = await window.WWebJS.arrayBufferToBase64Async(decryptedMedia);
|
||||
|
||||
return {
|
||||
data,
|
||||
mimetype: msg.mimetype,
|
||||
filename: msg.filename,
|
||||
filesize: msg.size
|
||||
};
|
||||
} catch (e) {
|
||||
if(e.status && e.status === 404) return undefined;
|
||||
throw e;
|
||||
}
|
||||
}, this.id._serialized);
|
||||
|
||||
if (!result) return undefined;
|
||||
return new MessageMedia(result.mimetype, result.data, result.filename, result.filesize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a message from the chat
|
||||
* @param {?boolean} everyone If true and the message is sent by the current user or the user is an admin, will delete it for everyone in the chat.
|
||||
* @param {?boolean} [clearMedia = true] If true, any associated media will also be deleted from a device.
|
||||
*/
|
||||
async delete(everyone, clearMedia = true) {
|
||||
await this.client.pupPage.evaluate(async (msgId, everyone, clearMedia) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
const chat = window.Store.Chat.get(msg.id.remote) || (await window.Store.Chat.find(msg.id.remote));
|
||||
|
||||
const canRevoke =
|
||||
window.Store.MsgActionChecks.canSenderRevokeMsg(msg) || window.Store.MsgActionChecks.canAdminRevokeMsg(msg);
|
||||
|
||||
if (everyone && canRevoke) {
|
||||
return window.compareWwebVersions(window.Debug.VERSION, '>=', '2.3000.0')
|
||||
? window.Store.Cmd.sendRevokeMsgs(chat, { list: [msg], type: 'message' }, { clearMedia: clearMedia })
|
||||
: window.Store.Cmd.sendRevokeMsgs(chat, [msg], { clearMedia: true, type: msg.id.fromMe ? 'Sender' : 'Admin' });
|
||||
}
|
||||
|
||||
return window.compareWwebVersions(window.Debug.VERSION, '>=', '2.3000.0')
|
||||
? window.Store.Cmd.sendDeleteMsgs(chat, { list: [msg], type: 'message' }, clearMedia)
|
||||
: window.Store.Cmd.sendDeleteMsgs(chat, [msg], clearMedia);
|
||||
}, this.id._serialized, everyone, clearMedia);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stars this message
|
||||
*/
|
||||
async star() {
|
||||
await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if (window.Store.MsgActionChecks.canStarMsg(msg)) {
|
||||
let chat = await window.Store.Chat.find(msg.id.remote);
|
||||
return window.Store.Cmd.sendStarMsgs(chat, [msg], false);
|
||||
}
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unstars this message
|
||||
*/
|
||||
async unstar() {
|
||||
await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if (window.Store.MsgActionChecks.canStarMsg(msg)) {
|
||||
let chat = await window.Store.Chat.find(msg.id.remote);
|
||||
return window.Store.Cmd.sendUnstarMsgs(chat, [msg], false);
|
||||
}
|
||||
}, this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pins the message (group admins can pin messages of all group members)
|
||||
* @param {number} duration The duration in seconds the message will be pinned in a chat
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async pin(duration) {
|
||||
return await this.client.pupPage.evaluate(async (msgId, duration) => {
|
||||
return await window.WWebJS.pinUnpinMsgAction(msgId, 1, duration);
|
||||
}, this.id._serialized, duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpins the message (group admins can unpin messages of all group members)
|
||||
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
||||
*/
|
||||
async unpin() {
|
||||
return await this.client.pupPage.evaluate(async (msgId) => {
|
||||
return await window.WWebJS.pinUnpinMsgAction(msgId, 2, 0);
|
||||
}, 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) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if (!msg || !msg.id.fromMe) return null;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(async () => {
|
||||
resolve(await window.Store.getMsgInfo(msg.id));
|
||||
}, (Date.now() - msg.t * 1000 < 1250) && Math.floor(Math.random() * (1200 - 1100 + 1)) + 1100 || 0);
|
||||
});
|
||||
}, this.id._serialized);
|
||||
|
||||
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, chatId) => {
|
||||
return window.WWebJS.getOrderDetail(orderId, token, chatId);
|
||||
}, this.orderId, this.token, this._getChatId());
|
||||
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) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if(!msg) return null;
|
||||
return msg.serialize();
|
||||
}, this.id._serialized);
|
||||
return new Payment(this.client, msg);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reaction List
|
||||
* @typedef {Object} ReactionList
|
||||
* @property {string} id Original emoji
|
||||
* @property {string} aggregateEmoji aggregate emoji
|
||||
* @property {boolean} hasReactionByMe Flag who sent the reaction
|
||||
* @property {Array<Reaction>} senders Reaction senders, to this message
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the reactions associated with the given message
|
||||
* @return {Promise<ReactionList[]>}
|
||||
*/
|
||||
async getReactions() {
|
||||
if (!this.hasReaction) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const reactions = await this.client.pupPage.evaluate(async (msgId) => {
|
||||
const msgReactions = await window.Store.Reactions.find(msgId);
|
||||
if (!msgReactions || !msgReactions.reactions.length) return null;
|
||||
return msgReactions.reactions.serialize();
|
||||
}, this.id._serialized);
|
||||
|
||||
if (!reactions) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return reactions.map(reaction => {
|
||||
reaction.senders = reaction.senders.map(sender => {
|
||||
sender.timestamp = Math.round(sender.timestamp / 1000);
|
||||
return new Reaction(this.client, sender);
|
||||
});
|
||||
return reaction;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the current message.
|
||||
* @param {string} content
|
||||
* @param {MessageEditOptions} [options] - Options used when editing the message
|
||||
* @returns {Promise<?Message>}
|
||||
*/
|
||||
async edit(content, options = {}) {
|
||||
if (options.mentions) {
|
||||
!Array.isArray(options.mentions) && (options.mentions = [options.mentions]);
|
||||
if (options.mentions.some((possiblyContact) => possiblyContact instanceof Contact)) {
|
||||
console.warn('Mentions with an array of Contact are now deprecated. See more at https://github.com/pedroslopez/whatsapp-web.js/pull/2166.');
|
||||
options.mentions = options.mentions.map((a) => a.id._serialized);
|
||||
}
|
||||
}
|
||||
|
||||
options.groupMentions && !Array.isArray(options.groupMentions) && (options.groupMentions = [options.groupMentions]);
|
||||
|
||||
let internalOptions = {
|
||||
linkPreview: options.linkPreview === false ? undefined : true,
|
||||
mentionedJidList: options.mentions || [],
|
||||
groupMentions: options.groupMentions,
|
||||
extraOptions: options.extra
|
||||
};
|
||||
|
||||
if (!this.fromMe) {
|
||||
return null;
|
||||
}
|
||||
const messageEdit = await this.client.pupPage.evaluate(async (msgId, message, options) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if (!msg) return null;
|
||||
|
||||
let canEdit = window.Store.MsgActionChecks.canEditText(msg) || window.Store.MsgActionChecks.canEditCaption(msg);
|
||||
if (canEdit) {
|
||||
const msgEdit = await window.WWebJS.editMessage(msg, message, options);
|
||||
return msgEdit.serialize();
|
||||
}
|
||||
return null;
|
||||
}, this.id._serialized, content, internalOptions);
|
||||
if (messageEdit) {
|
||||
return new Message(this.client, messageEdit);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the current ScheduledEvent message.
|
||||
* Once the scheduled event is canceled, it can not be edited.
|
||||
* @param {ScheduledEvent} editedEventObject
|
||||
* @returns {Promise<?Message>}
|
||||
*/
|
||||
async editScheduledEvent(editedEventObject) {
|
||||
if (!this.fromMe) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const edittedEventMsg = await this.client.pupPage.evaluate(async (msgId, editedEventObject) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
if (!msg) return null;
|
||||
|
||||
const { name, startTimeTs, eventSendOptions } = editedEventObject;
|
||||
const eventOptions = {
|
||||
name: name,
|
||||
description: eventSendOptions.description,
|
||||
startTime: startTimeTs,
|
||||
endTime: eventSendOptions.endTimeTs,
|
||||
location: eventSendOptions.location,
|
||||
callType: eventSendOptions.callType,
|
||||
isEventCanceled: eventSendOptions.isEventCanceled,
|
||||
};
|
||||
|
||||
await window.Store.ScheduledEventMsgUtils.sendEventEditMessage(eventOptions, msg);
|
||||
const editedMsg = window.Store.Msg.get(msg.id._serialized);
|
||||
return editedMsg?.serialize();
|
||||
}, this.id._serialized, editedEventObject);
|
||||
|
||||
return edittedEventMsg && new Message(this.client, edittedEventMsg);
|
||||
}
|
||||
/**
|
||||
* Returns the PollVote this poll message
|
||||
* @returns {Promise<PollVote[]>}
|
||||
*/
|
||||
async getPollVotes() {
|
||||
return await this.client.getPollVotes(this.id._serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send votes to the poll message
|
||||
* @param {Array<string>} selectedOptions Array of options selected.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async vote(selectedOptions) {
|
||||
if (this.type != MessageTypes.POLL_CREATION) throw 'Invalid usage! Can only be used with a pollCreation message';
|
||||
|
||||
await this.client.pupPage.evaluate(async (messageId, votes) => {
|
||||
if (!messageId) return null;
|
||||
if (!Array.isArray(votes)) votes = [votes];
|
||||
let localIdSet = new Set();
|
||||
const msg =
|
||||
window.Store.Msg.get(messageId) || (await window.Store.Msg.getMessagesById([messageId]))?.messages?.[0];
|
||||
if (!msg) return null;
|
||||
|
||||
msg.pollOptions.forEach(a => {
|
||||
for (const option of votes) {
|
||||
if (a.name === option) localIdSet.add(a.localId);
|
||||
}
|
||||
});
|
||||
|
||||
await window.Store.PollsSendVote.sendVote(msg, localIdSet);
|
||||
}, this.id._serialized, selectedOptions);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Message;
|
||||
111
node_modules/whatsapp-web.js/src/structures/MessageMedia.js
generated
vendored
Normal file
111
node_modules/whatsapp-web.js/src/structures/MessageMedia.js
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
'use strict';
|
||||
|
||||
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
|
||||
* @param {string} mimetype MIME type of the attachment
|
||||
* @param {string} data Base64-encoded data of the file
|
||||
* @param {?string} filename Document file name. Value can be null
|
||||
* @param {?number} filesize Document file size in bytes. Value can be null
|
||||
*/
|
||||
class MessageMedia {
|
||||
constructor(mimetype, data, filename, filesize) {
|
||||
/**
|
||||
* MIME type of the attachment
|
||||
* @type {string}
|
||||
*/
|
||||
this.mimetype = mimetype;
|
||||
|
||||
/**
|
||||
* Base64 encoded data that represents the file
|
||||
* @type {string}
|
||||
*/
|
||||
this.data = data;
|
||||
|
||||
/**
|
||||
* Document file name. Value can be null
|
||||
* @type {?string}
|
||||
*/
|
||||
this.filename = filename;
|
||||
|
||||
/**
|
||||
* Document file size in bytes. Value can be null
|
||||
* @type {?number}
|
||||
*/
|
||||
this.filesize = filesize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MessageMedia instance from a local file path
|
||||
* @param {string} filePath
|
||||
* @returns {MessageMedia}
|
||||
*/
|
||||
static fromFilePath(filePath) {
|
||||
const b64data = fs.readFileSync(filePath, {encoding: 'base64'});
|
||||
const mimetype = mime.getType(filePath);
|
||||
const filename = path.basename(filePath);
|
||||
|
||||
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 size = response.headers.get('Content-Length');
|
||||
|
||||
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, size };
|
||||
}
|
||||
|
||||
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, res.size || null);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MessageMedia;
|
||||
52
node_modules/whatsapp-web.js/src/structures/Order.js
generated
vendored
Normal file
52
node_modules/whatsapp-web.js/src/structures/Order.js
generated
vendored
Normal 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
node_modules/whatsapp-web.js/src/structures/Payment.js
generated
vendored
Normal file
79
node_modules/whatsapp-web.js/src/structures/Payment.js
generated
vendored
Normal 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;
|
||||
44
node_modules/whatsapp-web.js/src/structures/Poll.js
generated
vendored
Normal file
44
node_modules/whatsapp-web.js/src/structures/Poll.js
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Poll send options
|
||||
* @typedef {Object} PollSendOptions
|
||||
* @property {boolean} [allowMultipleAnswers=false] If false it is a single choice poll, otherwise it is a multiple choice poll (false by default)
|
||||
* @property {?Array<number>} messageSecret The custom message secret, can be used as a poll ID. NOTE: it has to be a unique vector with a length of 32
|
||||
*/
|
||||
|
||||
/** Represents a Poll on WhatsApp */
|
||||
class Poll {
|
||||
/**
|
||||
* @param {string} pollName
|
||||
* @param {Array<string>} pollOptions
|
||||
* @param {PollSendOptions} options
|
||||
*/
|
||||
constructor(pollName, pollOptions, options = {}) {
|
||||
/**
|
||||
* The name of the poll
|
||||
* @type {string}
|
||||
*/
|
||||
this.pollName = pollName.trim();
|
||||
|
||||
/**
|
||||
* The array of poll options
|
||||
* @type {Array.<{name: string, localId: number}>}
|
||||
*/
|
||||
this.pollOptions = pollOptions.map((option, index) => ({
|
||||
name: option.trim(),
|
||||
localId: index
|
||||
}));
|
||||
|
||||
/**
|
||||
* The send options for the poll
|
||||
* @type {PollSendOptions}
|
||||
*/
|
||||
this.options = {
|
||||
allowMultipleAnswers: options.allowMultipleAnswers === true,
|
||||
messageSecret: options.messageSecret
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Poll;
|
||||
75
node_modules/whatsapp-web.js/src/structures/PollVote.js
generated
vendored
Normal file
75
node_modules/whatsapp-web.js/src/structures/PollVote.js
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
'use strict';
|
||||
|
||||
const Message = require('./Message');
|
||||
const Base = require('./Base');
|
||||
|
||||
/**
|
||||
* Selected poll option structure
|
||||
* @typedef {Object} SelectedPollOption
|
||||
* @property {number} id The local selected or deselected option ID
|
||||
* @property {string} name The option name
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a Poll Vote on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class PollVote extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* The person who voted
|
||||
* @type {string}
|
||||
*/
|
||||
this.voter = data.sender;
|
||||
|
||||
/**
|
||||
* The selected poll option(s)
|
||||
* If it's an empty array, the user hasn't selected any options on the poll,
|
||||
* may occur when they deselected all poll options
|
||||
* @type {SelectedPollOption[]}
|
||||
*/
|
||||
if (data.selectedOptionLocalIds.length > 0) {
|
||||
if(data.parentMessage) { // temporary failsafe
|
||||
this.selectedOptions = data.selectedOptionLocalIds.map((e) => ({
|
||||
name: data.parentMessage.pollOptions.find((x) => x.localId === e).name,
|
||||
localId: e
|
||||
}));
|
||||
} else {
|
||||
this.selectedOptions = data.selectedOptionLocalIds.map((e) => ({
|
||||
name: undefined,
|
||||
localId: e
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
this.selectedOptions = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamp the option was selected or deselected at
|
||||
* @type {number}
|
||||
*/
|
||||
this.interractedAtTs = data.senderTimestampMs;
|
||||
|
||||
/**
|
||||
* The poll creation message associated with the poll vote
|
||||
* @type {Message}
|
||||
*/
|
||||
this.parentMessage = new Message(this.client, data.parentMessage);
|
||||
|
||||
/**
|
||||
* The poll creation message id
|
||||
* @type {Object}
|
||||
*/
|
||||
this.parentMsgKey = data.parentMsgKey;
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PollVote;
|
||||
13
node_modules/whatsapp-web.js/src/structures/PrivateChat.js
generated
vendored
Normal file
13
node_modules/whatsapp-web.js/src/structures/PrivateChat.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const Chat = require('./Chat');
|
||||
|
||||
/**
|
||||
* Represents a Private Chat on WhatsApp
|
||||
* @extends {Chat}
|
||||
*/
|
||||
class PrivateChat extends Chat {
|
||||
|
||||
}
|
||||
|
||||
module.exports = PrivateChat;
|
||||
13
node_modules/whatsapp-web.js/src/structures/PrivateContact.js
generated
vendored
Normal file
13
node_modules/whatsapp-web.js/src/structures/PrivateContact.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const Contact = require('./Contact');
|
||||
|
||||
/**
|
||||
* Represents a Private Contact on WhatsApp
|
||||
* @extends {Contact}
|
||||
*/
|
||||
class PrivateContact extends Contact {
|
||||
|
||||
}
|
||||
|
||||
module.exports = PrivateContact;
|
||||
68
node_modules/whatsapp-web.js/src/structures/Product.js
generated
vendored
Normal file
68
node_modules/whatsapp-web.js/src/structures/Product.js
generated
vendored
Normal 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;
|
||||
25
node_modules/whatsapp-web.js/src/structures/ProductMetadata.js
generated
vendored
Normal file
25
node_modules/whatsapp-web.js/src/structures/ProductMetadata.js
generated
vendored
Normal 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;
|
||||
69
node_modules/whatsapp-web.js/src/structures/Reaction.js
generated
vendored
Normal file
69
node_modules/whatsapp-web.js/src/structures/Reaction.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
|
||||
/**
|
||||
* Represents a Reaction on WhatsApp
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Reaction extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
|
||||
if (data) this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
/**
|
||||
* Reaction ID
|
||||
* @type {object}
|
||||
*/
|
||||
this.id = data.msgKey;
|
||||
/**
|
||||
* Orphan
|
||||
* @type {number}
|
||||
*/
|
||||
this.orphan = data.orphan;
|
||||
/**
|
||||
* Orphan reason
|
||||
* @type {?string}
|
||||
*/
|
||||
this.orphanReason = data.orphanReason;
|
||||
/**
|
||||
* Unix timestamp for when the reaction was created
|
||||
* @type {number}
|
||||
*/
|
||||
this.timestamp = data.timestamp;
|
||||
/**
|
||||
* Reaction
|
||||
* @type {string}
|
||||
*/
|
||||
this.reaction = data.reactionText;
|
||||
/**
|
||||
* Read
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.read = data.read;
|
||||
/**
|
||||
* Message ID
|
||||
* @type {object}
|
||||
*/
|
||||
this.msgId = data.parentMsgKey;
|
||||
/**
|
||||
* Sender ID
|
||||
* @type {string}
|
||||
*/
|
||||
this.senderId = data.senderUserJid;
|
||||
/**
|
||||
* ACK
|
||||
* @type {?number}
|
||||
*/
|
||||
this.ack = data.ack;
|
||||
|
||||
|
||||
return super._patch(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Reaction;
|
||||
71
node_modules/whatsapp-web.js/src/structures/ScheduledEvent.js
generated
vendored
Normal file
71
node_modules/whatsapp-web.js/src/structures/ScheduledEvent.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* ScheduledEvent send options
|
||||
* @typedef {Object} ScheduledEventSendOptions
|
||||
* @property {?string} description The scheduled event description
|
||||
* @property {?Date} endTime The end time of the event
|
||||
* @property {?string} location The location of the event
|
||||
* @property {?string} callType The type of a WhatsApp call link to generate, valid values are: `video` | `voice` | `none`
|
||||
* @property {boolean} [isEventCanceled = false] Indicates if a scheduled event should be sent as an already canceled
|
||||
* @property {?Array<number>} messageSecret The custom message secret, can be used as an event ID. NOTE: it has to be a unique vector with a length of 32
|
||||
*/
|
||||
|
||||
/** Represents a ScheduledEvent on WhatsApp */
|
||||
class ScheduledEvent {
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {Date} startTime
|
||||
* @param {ScheduledEventSendOptions} options
|
||||
*/
|
||||
constructor(name, startTime, options = {}) {
|
||||
/**
|
||||
* The name of the event
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = this._validateInputs('name', name).trim();
|
||||
|
||||
/**
|
||||
* The start time of the event
|
||||
* @type {number}
|
||||
*/
|
||||
this.startTimeTs = Math.floor(startTime.getTime() / 1000);
|
||||
|
||||
/**
|
||||
* The send options for the event
|
||||
* @type {Object}
|
||||
*/
|
||||
this.eventSendOptions = {
|
||||
description: options.description?.trim(),
|
||||
endTimeTs: options.endTime ? Math.floor(options.endTime.getTime() / 1000) : null,
|
||||
location: options.location?.trim(),
|
||||
callType: this._validateInputs('callType', options.callType),
|
||||
isEventCanceled: options.isEventCanceled ?? false,
|
||||
messageSecret: options.messageSecret
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner function to validate input values
|
||||
* @param {string} propName The property name to validate the value of
|
||||
* @param {string | number} propValue The property value to validate
|
||||
* @returns {string | number} The property value if a validation succeeded
|
||||
*/
|
||||
_validateInputs(propName, propValue) {
|
||||
if (propName === 'name' && !propValue) {
|
||||
throw new class CreateScheduledEventError extends Error {
|
||||
constructor(m) { super(m); }
|
||||
}(`Empty '${propName}' parameter value is provided.`);
|
||||
}
|
||||
|
||||
if (propName === 'callType' && propValue && !['video', 'voice', 'none'].includes(propValue)) {
|
||||
throw new class CreateScheduledEventError extends Error {
|
||||
constructor(m) { super(m); }
|
||||
}(`Invalid '${propName}' parameter value is provided. Valid values are: 'voice' | 'video' | 'none'.`);
|
||||
}
|
||||
|
||||
return propValue;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ScheduledEvent;
|
||||
27
node_modules/whatsapp-web.js/src/structures/index.js
generated
vendored
Normal file
27
node_modules/whatsapp-web.js/src/structures/index.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
module.exports = {
|
||||
Base: require('./Base'),
|
||||
BusinessContact: require('./BusinessContact'),
|
||||
Chat: require('./Chat'),
|
||||
ClientInfo: require('./ClientInfo'),
|
||||
Contact: require('./Contact'),
|
||||
GroupChat: require('./GroupChat'),
|
||||
Channel: require('./Channel'),
|
||||
Location: require('./Location'),
|
||||
Message: require('./Message'),
|
||||
MessageMedia: require('./MessageMedia'),
|
||||
PrivateChat: require('./PrivateChat'),
|
||||
PrivateContact: require('./PrivateContact'),
|
||||
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'),
|
||||
Reaction: require('./Reaction'),
|
||||
Poll: require('./Poll'),
|
||||
PollVote: require('./PollVote'),
|
||||
Broadcast: require('./Broadcast'),
|
||||
ScheduledEvent: require('./ScheduledEvent'),
|
||||
};
|
||||
186
node_modules/whatsapp-web.js/src/util/Constants.js
generated
vendored
Normal file
186
node_modules/whatsapp-web.js/src/util/Constants.js
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
'use strict';
|
||||
|
||||
exports.WhatsWebURL = 'https://web.whatsapp.com/';
|
||||
|
||||
exports.DefaultOptions = {
|
||||
puppeteer: {
|
||||
headless: true,
|
||||
defaultViewport: null
|
||||
},
|
||||
webVersion: '2.3000.1017054665',
|
||||
webVersionCache: {
|
||||
type: 'local',
|
||||
},
|
||||
authTimeoutMs: 0,
|
||||
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/101.0.4951.67 Safari/537.36',
|
||||
ffmpegPath: 'ffmpeg',
|
||||
bypassCSP: false,
|
||||
proxyAuthentication: undefined,
|
||||
pairWithPhoneNumber: {
|
||||
phoneNumber: '',
|
||||
showNotification: true,
|
||||
intervalMs: 180000,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Client status
|
||||
* @readonly
|
||||
* @enum {number}
|
||||
*/
|
||||
exports.Status = {
|
||||
INITIALIZING: 0,
|
||||
AUTHENTICATING: 1,
|
||||
READY: 3
|
||||
};
|
||||
|
||||
/**
|
||||
* Events that can be emitted by the client
|
||||
* @readonly
|
||||
* @enum {string}
|
||||
*/
|
||||
exports.Events = {
|
||||
AUTHENTICATED: 'authenticated',
|
||||
AUTHENTICATION_FAILURE: 'auth_failure',
|
||||
READY: 'ready',
|
||||
CHAT_REMOVED: 'chat_removed',
|
||||
CHAT_ARCHIVED: 'chat_archived',
|
||||
MESSAGE_RECEIVED: 'message',
|
||||
MESSAGE_CIPHERTEXT: 'message_ciphertext',
|
||||
MESSAGE_CREATE: 'message_create',
|
||||
MESSAGE_REVOKED_EVERYONE: 'message_revoke_everyone',
|
||||
MESSAGE_REVOKED_ME: 'message_revoke_me',
|
||||
MESSAGE_ACK: 'message_ack',
|
||||
MESSAGE_EDIT: 'message_edit',
|
||||
UNREAD_COUNT: 'unread_count',
|
||||
MESSAGE_REACTION: 'message_reaction',
|
||||
MEDIA_UPLOADED: 'media_uploaded',
|
||||
CONTACT_CHANGED: 'contact_changed',
|
||||
GROUP_JOIN: 'group_join',
|
||||
GROUP_LEAVE: 'group_leave',
|
||||
GROUP_ADMIN_CHANGED: 'group_admin_changed',
|
||||
GROUP_MEMBERSHIP_REQUEST: 'group_membership_request',
|
||||
GROUP_UPDATE: 'group_update',
|
||||
QR_RECEIVED: 'qr',
|
||||
CODE_RECEIVED: 'code',
|
||||
LOADING_SCREEN: 'loading_screen',
|
||||
DISCONNECTED: 'disconnected',
|
||||
STATE_CHANGED: 'change_state',
|
||||
BATTERY_CHANGED: 'change_battery',
|
||||
INCOMING_CALL: 'call',
|
||||
REMOTE_SESSION_SAVED: 'remote_session_saved',
|
||||
VOTE_UPDATE: 'vote_update'
|
||||
};
|
||||
|
||||
/**
|
||||
* Message types
|
||||
* @readonly
|
||||
* @enum {string}
|
||||
*/
|
||||
exports.MessageTypes = {
|
||||
TEXT: 'chat',
|
||||
AUDIO: 'audio',
|
||||
VOICE: 'ptt',
|
||||
IMAGE: 'image',
|
||||
ALBUM: 'album',
|
||||
VIDEO: 'video',
|
||||
DOCUMENT: 'document',
|
||||
STICKER: 'sticker',
|
||||
LOCATION: 'location',
|
||||
CONTACT_CARD: 'vcard',
|
||||
CONTACT_CARD_MULTI: 'multi_vcard',
|
||||
ORDER: 'order',
|
||||
REVOKED: 'revoked',
|
||||
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',
|
||||
POLL_CREATION: 'poll_creation',
|
||||
SCHEDULED_EVENT_CREATION: 'scheduled_event_creation',
|
||||
};
|
||||
|
||||
/**
|
||||
* Group notification types
|
||||
* @readonly
|
||||
* @enum {string}
|
||||
*/
|
||||
exports.GroupNotificationTypes = {
|
||||
ADD: 'add',
|
||||
INVITE: 'invite',
|
||||
REMOVE: 'remove',
|
||||
LEAVE: 'leave',
|
||||
PROMOTE: 'promote',
|
||||
DEMOTE: 'demote',
|
||||
SUBJECT: 'subject',
|
||||
DESCRIPTION: 'description',
|
||||
PICTURE: 'picture',
|
||||
ANNOUNCE: 'announce',
|
||||
RESTRICT: 'restrict',
|
||||
};
|
||||
|
||||
/**
|
||||
* Chat types
|
||||
* @readonly
|
||||
* @enum {string}
|
||||
*/
|
||||
exports.ChatTypes = {
|
||||
SOLO: 'solo',
|
||||
GROUP: 'group',
|
||||
UNKNOWN: 'unknown'
|
||||
};
|
||||
|
||||
/**
|
||||
* WhatsApp state
|
||||
* @readonly
|
||||
* @enum {string}
|
||||
*/
|
||||
exports.WAState = {
|
||||
CONFLICT: 'CONFLICT',
|
||||
CONNECTED: 'CONNECTED',
|
||||
DEPRECATED_VERSION: 'DEPRECATED_VERSION',
|
||||
OPENING: 'OPENING',
|
||||
PAIRING: 'PAIRING',
|
||||
PROXYBLOCK: 'PROXYBLOCK',
|
||||
SMB_TOS_BLOCK: 'SMB_TOS_BLOCK',
|
||||
TIMEOUT: 'TIMEOUT',
|
||||
TOS_BLOCK: 'TOS_BLOCK',
|
||||
UNLAUNCHED: 'UNLAUNCHED',
|
||||
UNPAIRED: 'UNPAIRED',
|
||||
UNPAIRED_IDLE: 'UNPAIRED_IDLE'
|
||||
};
|
||||
|
||||
/**
|
||||
* Message ACK
|
||||
* @readonly
|
||||
* @enum {number}
|
||||
*/
|
||||
exports.MessageAck = {
|
||||
ACK_ERROR: -1,
|
||||
ACK_PENDING: 0,
|
||||
ACK_SERVER: 1,
|
||||
ACK_DEVICE: 2,
|
||||
ACK_READ: 3,
|
||||
ACK_PLAYED: 4,
|
||||
};
|
||||
17
node_modules/whatsapp-web.js/src/util/Injected/AuthStore/AuthStore.js
generated
vendored
Normal file
17
node_modules/whatsapp-web.js/src/util/Injected/AuthStore/AuthStore.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
exports.ExposeAuthStore = () => {
|
||||
window.AuthStore = {};
|
||||
window.AuthStore.AppState = window.require('WAWebSocketModel').Socket;
|
||||
window.AuthStore.Cmd = window.require('WAWebCmd').Cmd;
|
||||
window.AuthStore.Conn = window.require('WAWebConnModel').Conn;
|
||||
window.AuthStore.OfflineMessageHandler = window.require('WAWebOfflineHandler').OfflineMessageHandler;
|
||||
window.AuthStore.PairingCodeLinkUtils = window.require('WAWebAltDeviceLinkingApi');
|
||||
window.AuthStore.Base64Tools = window.require('WABase64');
|
||||
window.AuthStore.RegistrationUtils = {
|
||||
...window.require('WAWebCompanionRegClientUtils'),
|
||||
...window.require('WAWebAdvSignatureApi'),
|
||||
...window.require('WAWebUserPrefsInfoStore'),
|
||||
...window.require('WAWebSignalStoreApi'),
|
||||
};
|
||||
};
|
||||
22
node_modules/whatsapp-web.js/src/util/Injected/AuthStore/LegacyAuthStore.js
generated
vendored
Normal file
22
node_modules/whatsapp-web.js/src/util/Injected/AuthStore/LegacyAuthStore.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
//TODO: To be removed by version 2.3000.x hard release
|
||||
|
||||
exports.ExposeLegacyAuthStore = (moduleRaidStr) => {
|
||||
eval('var moduleRaid = ' + moduleRaidStr);
|
||||
// eslint-disable-next-line no-undef
|
||||
window.mR = moduleRaid();
|
||||
window.AuthStore = {};
|
||||
window.AuthStore.AppState = window.mR.findModule('Socket')[0].Socket;
|
||||
window.AuthStore.Cmd = window.mR.findModule('Cmd')[0].Cmd;
|
||||
window.AuthStore.Conn = window.mR.findModule('Conn')[0].Conn;
|
||||
window.AuthStore.OfflineMessageHandler = window.mR.findModule('OfflineMessageHandler')[0].OfflineMessageHandler;
|
||||
window.AuthStore.PairingCodeLinkUtils = window.mR.findModule('initializeAltDeviceLinking')[0];
|
||||
window.AuthStore.Base64Tools = window.mR.findModule('encodeB64')[0];
|
||||
window.AuthStore.RegistrationUtils = {
|
||||
...window.mR.findModule('getCompanionWebClientFromBrowser')[0],
|
||||
...window.mR.findModule('verifyKeyIndexListAccountSignature')[0],
|
||||
...window.mR.findModule('waNoiseInfo')[0],
|
||||
...window.mR.findModule('waSignalStore')[0],
|
||||
};
|
||||
};
|
||||
146
node_modules/whatsapp-web.js/src/util/Injected/LegacyStore.js
generated
vendored
Normal file
146
node_modules/whatsapp-web.js/src/util/Injected/LegacyStore.js
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
'use strict';
|
||||
|
||||
//TODO: To be removed by version 2.3000.x hard release
|
||||
|
||||
// Exposes the internal Store to the WhatsApp Web client
|
||||
exports.ExposeLegacyStore = () => {
|
||||
window.Store = Object.assign({}, window.mR.findModule(m => m.default && m.default.Chat)[0].default);
|
||||
window.Store.AppState = window.mR.findModule('Socket')[0].Socket;
|
||||
window.Store.Conn = window.mR.findModule('Conn')[0].Conn;
|
||||
window.Store.BlockContact = window.mR.findModule('blockContact')[0];
|
||||
window.Store.Call = window.mR.findModule((module) => module.default && module.default.Call)[0].default.Call;
|
||||
window.Store.Cmd = window.mR.findModule('Cmd')[0].Cmd;
|
||||
window.Store.CryptoLib = window.mR.findModule('decryptE2EMedia')[0];
|
||||
window.Store.DownloadManager = window.mR.findModule('downloadManager')[0].downloadManager;
|
||||
window.Store.GroupMetadata = window.mR.findModule('GroupMetadata')[0].default.GroupMetadata;
|
||||
window.Store.GroupQueryAndUpdate = window.mR.findModule('queryAndUpdateGroupMetadataById')[0].queryAndUpdateGroupMetadataById;
|
||||
window.Store.Label = window.mR.findModule('LabelCollection')[0].LabelCollection;
|
||||
window.Store.MediaPrep = window.mR.findModule('prepRawMedia')[0];
|
||||
window.Store.MediaObject = window.mR.findModule('getOrCreateMediaObject')[0];
|
||||
window.Store.NumberInfo = window.mR.findModule('formattedPhoneNumber')[0];
|
||||
window.Store.MediaTypes = window.mR.findModule('msgToMediaType')[0];
|
||||
window.Store.MediaUpload = window.mR.findModule('uploadMedia')[0];
|
||||
window.Store.MsgKey = window.mR.findModule((module) => module.default && module.default.fromString)[0].default;
|
||||
window.Store.OpaqueData = window.mR.findModule(module => module.default && module.default.createFromData)[0].default;
|
||||
window.Store.QueryProduct = window.mR.findModule('queryProduct')[0];
|
||||
window.Store.QueryOrder = window.mR.findModule('queryOrder')[0];
|
||||
window.Store.SendClear = window.mR.findModule('sendClear')[0];
|
||||
window.Store.SendDelete = window.mR.findModule('sendDelete')[0];
|
||||
window.Store.SendMessage = window.mR.findModule('addAndSendMsgToChat')[0];
|
||||
window.Store.EditMessage = window.mR.findModule('addAndSendMessageEdit')[0];
|
||||
window.Store.SendSeen = window.mR.findModule('sendSeen')[0];
|
||||
window.Store.User = window.mR.findModule('getMaybeMeUser')[0];
|
||||
window.Store.ContactMethods = window.mR.findModule('getUserid')[0];
|
||||
window.Store.UploadUtils = window.mR.findModule((module) => (module.default && module.default.encryptAndUpload) ? module.default : null)[0].default;
|
||||
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;
|
||||
window.Store.Validators = window.mR.findModule('findLinks')[0];
|
||||
window.Store.VCard = window.mR.findModule('vcardFromContactModel')[0];
|
||||
window.Store.WidFactory = window.mR.findModule('createWid')[0];
|
||||
window.Store.ProfilePic = window.mR.findModule('profilePicResync')[0];
|
||||
window.Store.PresenceUtils = window.mR.findModule('sendPresenceAvailable')[0];
|
||||
window.Store.ChatState = window.mR.findModule('sendChatStateComposing')[0];
|
||||
window.Store.findCommonGroups = window.mR.findModule('findCommonGroups')[0].findCommonGroups;
|
||||
window.Store.StatusUtils = window.mR.findModule('setMyStatus')[0];
|
||||
window.Store.ConversationMsgs = window.mR.findModule('loadEarlierMsgs')[0];
|
||||
window.Store.sendReactionToMsg = window.mR.findModule('sendReactionToMsg')[0].sendReactionToMsg;
|
||||
window.Store.createOrUpdateReactionsModule = window.mR.findModule('createOrUpdateReactions')[0];
|
||||
window.Store.EphemeralFields = window.mR.findModule('getEphemeralFields')[0];
|
||||
window.Store.MsgActionChecks = window.mR.findModule('canSenderRevokeMsg')[0];
|
||||
window.Store.QuotedMsg = window.mR.findModule('getQuotedMsgObj')[0];
|
||||
window.Store.LinkPreview = window.mR.findModule('getLinkPreview')[0];
|
||||
window.Store.Socket = window.mR.findModule('deprecatedSendIq')[0];
|
||||
window.Store.SocketWap = window.mR.findModule('wap')[0];
|
||||
window.Store.SearchContext = window.mR.findModule('getSearchContext')[0].getSearchContext;
|
||||
window.Store.DrawerManager = window.mR.findModule('DrawerManager')[0].DrawerManager;
|
||||
window.Store.LidUtils = window.mR.findModule('getCurrentLid')[0];
|
||||
window.Store.WidToJid = window.mR.findModule('widToUserJid')[0];
|
||||
window.Store.JidToWid = window.mR.findModule('userJidToUserWid')[0];
|
||||
window.Store.getMsgInfo = (window.mR.findModule('sendQueryMsgInfo')[0] || {}).sendQueryMsgInfo || window.mR.findModule('queryMsgInfo')[0].queryMsgInfo;
|
||||
window.Store.pinUnpinMsg = window.mR.findModule('sendPinInChatMsg')[0].sendPinInChatMsg;
|
||||
|
||||
/* eslint-disable no-undef, no-cond-assign */
|
||||
window.Store.QueryExist = ((m = window.mR.findModule('queryExists')[0]) ? m.queryExists : window.mR.findModule('queryExist')[0].queryWidExists);
|
||||
window.Store.ReplyUtils = (m = window.mR.findModule('canReplyMsg')).length > 0 && m[0];
|
||||
/* eslint-enable no-undef, no-cond-assign */
|
||||
|
||||
window.Store.Settings = {
|
||||
...window.mR.findModule('ChatlistPanelState')[0],
|
||||
setPushname: window.mR.findModule((m) => m.setPushname && !m.ChatlistPanelState)[0].setPushname
|
||||
};
|
||||
window.Store.StickerTools = {
|
||||
...window.mR.findModule('toWebpSticker')[0],
|
||||
...window.mR.findModule('addWebpMetadata')[0]
|
||||
};
|
||||
window.Store.GroupUtils = {
|
||||
...window.mR.findModule('createGroup')[0],
|
||||
...window.mR.findModule('setGroupDescription')[0],
|
||||
...window.mR.findModule('sendExitGroup')[0],
|
||||
...window.mR.findModule('sendSetPicture')[0]
|
||||
};
|
||||
window.Store.GroupParticipants = {
|
||||
...window.mR.findModule('promoteParticipants')[0],
|
||||
...window.mR.findModule('sendAddParticipantsRPC')[0]
|
||||
};
|
||||
window.Store.GroupInvite = {
|
||||
...window.mR.findModule('resetGroupInviteCode')[0],
|
||||
...window.mR.findModule('queryGroupInvite')[0]
|
||||
};
|
||||
window.Store.GroupInviteV4 = {
|
||||
...window.mR.findModule('queryGroupInviteV4')[0],
|
||||
...window.mR.findModule('sendGroupInviteMessage')[0]
|
||||
};
|
||||
window.Store.MembershipRequestUtils = {
|
||||
...window.mR.findModule('getMembershipApprovalRequests')[0],
|
||||
...window.mR.findModule('sendMembershipRequestsActionRPC')[0]
|
||||
};
|
||||
|
||||
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
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
if ((m = window.mR.findModule('ChatCollection')[0]) && m.ChatCollection && typeof m.ChatCollection.findImpl === 'undefined' && typeof m.ChatCollection._find !== 'undefined') m.ChatCollection.findImpl = m.ChatCollection._find;
|
||||
|
||||
const _isMDBackend = window.mR.findModule('isMDBackend');
|
||||
if(_isMDBackend && _isMDBackend[0] && _isMDBackend[0].isMDBackend) {
|
||||
window.Store.MDBackend = _isMDBackend[0].isMDBackend();
|
||||
} else {
|
||||
window.Store.MDBackend = true;
|
||||
}
|
||||
|
||||
const _features = window.mR.findModule('FEATURE_CHANGE_EVENT')[0];
|
||||
if(_features) {
|
||||
window.Store.Features = _features.LegacyPhoneFeatures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Target options object description
|
||||
* @typedef {Object} TargetOptions
|
||||
* @property {string|number} module The name or a key of the target module to search
|
||||
* @property {number} index The index value of the target module
|
||||
* @property {string} function The function name to get from a module
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function to modify functions
|
||||
* @param {TargetOptions} target Options specifying the target function to search for modifying
|
||||
* @param {Function} callback Modified function
|
||||
*/
|
||||
window.injectToFunction = (target, callback) => {
|
||||
const module = typeof target.module === 'string'
|
||||
? window.mR.findModule(target.module)
|
||||
: window.mR.modules[target.module];
|
||||
const originalFunction = module[target.index][target.function];
|
||||
const modifiedFunction = (...args) => callback(originalFunction, ...args);
|
||||
module[target.index][target.function] = modifiedFunction;
|
||||
};
|
||||
|
||||
window.injectToFunction({ module: 'mediaTypeFromProtobuf', index: 0, function: 'mediaTypeFromProtobuf' }, (func, ...args) => { const [proto] = args; return proto.locationMessage ? null : func(...args); });
|
||||
|
||||
window.injectToFunction({ module: 'typeAttributeFromProtobuf', index: 0, function: 'typeAttributeFromProtobuf' }, (func, ...args) => { const [proto] = args; return proto.locationMessage || proto.groupInviteMessage ? 'text' : func(...args); });
|
||||
};
|
||||
265
node_modules/whatsapp-web.js/src/util/Injected/Store.js
generated
vendored
Normal file
265
node_modules/whatsapp-web.js/src/util/Injected/Store.js
generated
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
'use strict';
|
||||
|
||||
exports.ExposeStore = () => {
|
||||
/**
|
||||
* Helper function that compares between two WWeb versions. Its purpose is to help the developer to choose the correct code implementation depending on the comparison value and the WWeb version.
|
||||
* @param {string} lOperand The left operand for the WWeb version string to compare with
|
||||
* @param {string} operator The comparison operator
|
||||
* @param {string} rOperand The right operand for the WWeb version string to compare with
|
||||
* @returns {boolean} Boolean value that indicates the result of the comparison
|
||||
*/
|
||||
window.compareWwebVersions = (lOperand, operator, rOperand) => {
|
||||
if (!['>', '>=', '<', '<=', '='].includes(operator)) {
|
||||
throw new class _ extends Error {
|
||||
constructor(m) { super(m); this.name = 'CompareWwebVersionsError'; }
|
||||
}('Invalid comparison operator is provided');
|
||||
|
||||
}
|
||||
if (typeof lOperand !== 'string' || typeof rOperand !== 'string') {
|
||||
throw new class _ extends Error {
|
||||
constructor(m) { super(m); this.name = 'CompareWwebVersionsError'; }
|
||||
}('A non-string WWeb version type is provided');
|
||||
}
|
||||
|
||||
lOperand = lOperand.replace(/-beta$/, '');
|
||||
rOperand = rOperand.replace(/-beta$/, '');
|
||||
|
||||
while (lOperand.length !== rOperand.length) {
|
||||
lOperand.length > rOperand.length
|
||||
? rOperand = rOperand.concat('0')
|
||||
: lOperand = lOperand.concat('0');
|
||||
}
|
||||
|
||||
lOperand = Number(lOperand.replace(/\./g, ''));
|
||||
rOperand = Number(rOperand.replace(/\./g, ''));
|
||||
|
||||
return (
|
||||
operator === '>' ? lOperand > rOperand :
|
||||
operator === '>=' ? lOperand >= rOperand :
|
||||
operator === '<' ? lOperand < rOperand :
|
||||
operator === '<=' ? lOperand <= rOperand :
|
||||
operator === '=' ? lOperand === rOperand :
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
window.Store = Object.assign({}, window.require('WAWebCollections'));
|
||||
window.Store.AppState = window.require('WAWebSocketModel').Socket;
|
||||
window.Store.BlockContact = window.require('WAWebBlockContactAction');
|
||||
window.Store.Conn = window.require('WAWebConnModel').Conn;
|
||||
window.Store.Cmd = window.require('WAWebCmd').Cmd;
|
||||
window.Store.DownloadManager = window.require('WAWebDownloadManager').downloadManager;
|
||||
window.Store.GroupQueryAndUpdate = window.require('WAWebGroupQueryJob').queryAndUpdateGroupMetadataById;
|
||||
window.Store.MediaPrep = window.require('WAWebPrepRawMedia');
|
||||
window.Store.MediaObject = window.require('WAWebMediaStorage');
|
||||
window.Store.MediaTypes = window.require('WAWebMmsMediaTypes');
|
||||
window.Store.MediaUpload = {
|
||||
...window.require('WAWebMediaMmsV4Upload'),
|
||||
...window.require('WAWebStartMediaUploadQpl')
|
||||
};
|
||||
window.Store.MediaUpdate = window.require('WAWebMediaUpdateMsg');
|
||||
window.Store.MsgKey = window.require('WAWebMsgKey');
|
||||
window.Store.OpaqueData = window.require('WAWebMediaOpaqueData');
|
||||
window.Store.QueryProduct = window.require('WAWebBizProductCatalogBridge');
|
||||
window.Store.QueryOrder = window.require('WAWebBizOrderBridge');
|
||||
window.Store.SendClear = window.require('WAWebChatClearBridge');
|
||||
window.Store.SendDelete = window.require('WAWebDeleteChatAction');
|
||||
window.Store.SendMessage = window.require('WAWebSendMsgChatAction');
|
||||
window.Store.EditMessage = window.require('WAWebSendMessageEditAction');
|
||||
window.Store.MediaDataUtils = window.require('WAWebMediaDataUtils');
|
||||
window.Store.BlobCache = window.require('WAWebMediaInMemoryBlobCache');
|
||||
window.Store.SendSeen = window.require('WAWebUpdateUnreadChatAction');
|
||||
window.Store.User = window.require('WAWebUserPrefsMeUser');
|
||||
window.Store.ContactMethods = {
|
||||
...window.require('WAWebContactGetters'),
|
||||
...window.require('WAWebFrontendContactGetters')
|
||||
};
|
||||
window.Store.UserConstructor = window.require('WAWebWid');
|
||||
window.Store.Validators = window.require('WALinkify');
|
||||
window.Store.WidFactory = window.require('WAWebWidFactory');
|
||||
window.Store.ProfilePic = window.require('WAWebContactProfilePicThumbBridge');
|
||||
window.Store.PresenceUtils = window.require('WAWebPresenceChatAction');
|
||||
window.Store.ChatState = window.require('WAWebChatStateBridge');
|
||||
window.Store.findCommonGroups = window.require('WAWebFindCommonGroupsContactAction').findCommonGroups;
|
||||
window.Store.ConversationMsgs = window.require('WAWebChatLoadMessages');
|
||||
window.Store.sendReactionToMsg = window.require('WAWebSendReactionMsgAction').sendReactionToMsg;
|
||||
window.Store.createOrUpdateReactionsModule = window.require('WAWebDBCreateOrUpdateReactions');
|
||||
window.Store.EphemeralFields = window.require('WAWebGetEphemeralFieldsMsgActionsUtils');
|
||||
window.Store.MsgActionChecks = window.require('WAWebMsgActionCapability');
|
||||
window.Store.QuotedMsg = window.require('WAWebQuotedMsgModelUtils');
|
||||
window.Store.LinkPreview = window.require('WAWebLinkPreviewChatAction');
|
||||
window.Store.Socket = window.require('WADeprecatedSendIq');
|
||||
window.Store.SocketWap = window.require('WAWap');
|
||||
window.Store.SearchContext = window.require('WAWebChatMessageSearch');
|
||||
window.Store.DrawerManager = window.require('WAWebDrawerManager').DrawerManager;
|
||||
window.Store.LidUtils = window.require('WAWebApiContact');
|
||||
window.Store.WidToJid = window.require('WAWebWidToJid');
|
||||
window.Store.JidToWid = window.require('WAWebJidToWid');
|
||||
window.Store.getMsgInfo = window.require('WAWebApiMessageInfoStore').queryMsgInfo;
|
||||
window.Store.QueryExist = window.require('WAWebQueryExistsJob').queryWidExists;
|
||||
window.Store.ReplyUtils = window.require('WAWebMsgReply');
|
||||
window.Store.BotSecret = window.require('WAWebBotMessageSecret');
|
||||
window.Store.BotProfiles = window.require('WAWebBotProfileCollection');
|
||||
window.Store.ContactCollection = window.require('WAWebContactCollection').ContactCollection;
|
||||
window.Store.DeviceList = window.require('WAWebApiDeviceList');
|
||||
window.Store.HistorySync = window.require('WAWebSendNonMessageDataRequest');
|
||||
window.Store.AddonReactionTable = window.require('WAWebAddonReactionTableMode').reactionTableMode;
|
||||
window.Store.AddonPollVoteTable = window.require('WAWebAddonPollVoteTableMode').pollVoteTableMode;
|
||||
window.Store.ChatGetters = window.require('WAWebChatGetters');
|
||||
window.Store.UploadUtils = window.require('WAWebUploadManager');
|
||||
window.Store.WAWebStreamModel = window.require('WAWebStreamModel');
|
||||
window.Store.FindOrCreateChat = window.require('WAWebFindChatAction');
|
||||
window.Store.CustomerNoteUtils = window.require('WAWebNoteAction');
|
||||
window.Store.BusinessGatingUtils = window.require('WAWebBizGatingUtils');
|
||||
window.Store.PollsVotesSchema = window.require('WAWebPollsVotesSchema');
|
||||
window.Store.PollsSendVote = window.require('WAWebPollsSendVoteMsgAction');
|
||||
|
||||
window.Store.Settings = {
|
||||
...window.require('WAWebUserPrefsGeneral'),
|
||||
...window.require('WAWebUserPrefsNotifications'),
|
||||
setPushname: window.require('WAWebSetPushnameConnAction').setPushname
|
||||
};
|
||||
window.Store.NumberInfo = {
|
||||
...window.require('WAPhoneUtils'),
|
||||
...window.require('WAPhoneFindCC')
|
||||
};
|
||||
window.Store.ForwardUtils = {
|
||||
...window.require('WAWebChatForwardMessage')
|
||||
};
|
||||
window.Store.PinnedMsgUtils = {
|
||||
...window.require('WAWebPinInChatSchema'),
|
||||
...window.require('WAWebSendPinMessageAction')
|
||||
};
|
||||
window.Store.ScheduledEventMsgUtils = {
|
||||
...window.require('WAWebGenerateEventCallLink'),
|
||||
...window.require('WAWebSendEventEditMsgAction'),
|
||||
...window.require('WAWebSendEventResponseMsgAction')
|
||||
};
|
||||
window.Store.VCard = {
|
||||
...window.require('WAWebFrontendVcardUtils'),
|
||||
...window.require('WAWebVcardParsingUtils'),
|
||||
...window.require('WAWebVcardGetNameFromParsed')
|
||||
};
|
||||
window.Store.StickerTools = {
|
||||
...window.require('WAWebImageUtils'),
|
||||
...window.require('WAWebAddWebpMetadata')
|
||||
};
|
||||
window.Store.GroupUtils = {
|
||||
...window.require('WAWebGroupCreateJob'),
|
||||
...window.require('WAWebGroupModifyInfoJob'),
|
||||
...window.require('WAWebExitGroupAction'),
|
||||
...window.require('WAWebContactProfilePicThumbBridge'),
|
||||
...window.require('WAWebSetPropertyGroupAction')
|
||||
};
|
||||
window.Store.GroupParticipants = {
|
||||
...window.require('WAWebModifyParticipantsGroupAction'),
|
||||
...window.require('WASmaxGroupsAddParticipantsRPC')
|
||||
};
|
||||
window.Store.GroupInvite = {
|
||||
...window.require('WAWebGroupInviteJob'),
|
||||
...window.require('WAWebGroupQueryJob'),
|
||||
...window.require('WAWebMexFetchGroupInviteCodeJob')
|
||||
};
|
||||
window.Store.GroupInviteV4 = {
|
||||
...window.require('WAWebGroupInviteV4Job'),
|
||||
...window.require('WAWebChatSendMessages')
|
||||
};
|
||||
window.Store.MembershipRequestUtils = {
|
||||
...window.require('WAWebApiMembershipApprovalRequestStore'),
|
||||
...window.require('WASmaxGroupsMembershipRequestsActionRPC')
|
||||
};
|
||||
window.Store.ChannelUtils = {
|
||||
...window.require('WAWebLoadNewsletterPreviewChatAction'),
|
||||
...window.require('WAWebNewsletterMetadataQueryJob'),
|
||||
...window.require('WAWebNewsletterCreateQueryJob'),
|
||||
...window.require('WAWebEditNewsletterMetadataAction'),
|
||||
...window.require('WAWebNewsletterDeleteAction'),
|
||||
...window.require('WAWebNewsletterSubscribeAction'),
|
||||
...window.require('WAWebNewsletterUnsubscribeAction'),
|
||||
...window.require('WAWebNewsletterDirectorySearchAction'),
|
||||
...window.require('WAWebNewsletterGatingUtils'),
|
||||
...window.require('WAWebNewsletterModelUtils'),
|
||||
...window.require('WAWebMexAcceptNewsletterAdminInviteJob'),
|
||||
...window.require('WAWebMexRevokeNewsletterAdminInviteJob'),
|
||||
...window.require('WAWebChangeNewsletterOwnerAction'),
|
||||
...window.require('WAWebDemoteNewsletterAdminAction'),
|
||||
...window.require('WAWebNewsletterDemoteAdminJob'),
|
||||
countryCodesIso: window.require('WAWebCountriesNativeCountryNames'),
|
||||
currentRegion: window.require('WAWebL10N').getRegion(),
|
||||
};
|
||||
window.Store.SendChannelMessage = {
|
||||
...window.require('WAWebNewsletterUpdateMsgsRecordsJob'),
|
||||
...window.require('WAWebMsgDataFromModel'),
|
||||
...window.require('WAWebNewsletterSendMessageJob'),
|
||||
...window.require('WAWebNewsletterSendMsgAction'),
|
||||
...window.require('WAMediaCalculateFilehash')
|
||||
};
|
||||
window.Store.ChannelSubscribers = {
|
||||
...window.require('WAWebMexFetchNewsletterSubscribersJob'),
|
||||
...window.require('WAWebNewsletterSubscriberListAction')
|
||||
};
|
||||
window.Store.AddressbookContactUtils = {
|
||||
...window.require('WAWebSaveContactAction'),
|
||||
...window.require('WAWebDeleteContactAction')
|
||||
};
|
||||
window.Store.StatusUtils = {
|
||||
...window.require('WAWebContactStatusBridge'),
|
||||
...window.require('WAWebSendStatusMsgAction'),
|
||||
...window.require('WAWebRevokeStatusAction'),
|
||||
...window.require('WAWebStatusGatingUtils')
|
||||
};
|
||||
|
||||
if (!window.Store.Chat._find || !window.Store.Chat.findImpl) {
|
||||
window.Store.Chat._find = e => {
|
||||
const target = window.Store.Chat.get(e);
|
||||
return target ? Promise.resolve(target) : Promise.resolve({
|
||||
id: e
|
||||
});
|
||||
};
|
||||
window.Store.Chat.findImpl = window.Store.Chat._find;
|
||||
}
|
||||
|
||||
/**
|
||||
* Target options object description
|
||||
* @typedef {Object} TargetOptions
|
||||
* @property {string|number} module The target module
|
||||
* @property {string} function The function name to get from a module
|
||||
*/
|
||||
/**
|
||||
* Function to modify functions
|
||||
* @param {TargetOptions} target Options specifying the target function to search for modifying
|
||||
* @param {Function} callback Modified function
|
||||
*/
|
||||
window.injectToFunction = (target, callback) => {
|
||||
try {
|
||||
let module = window.require(target.module);
|
||||
if (!module) return;
|
||||
|
||||
const path = target.function.split('.');
|
||||
const funcName = path.pop();
|
||||
|
||||
for (const key of path) {
|
||||
if (!module[key]) return;
|
||||
module = module[key];
|
||||
}
|
||||
|
||||
const originalFunction = module[funcName];
|
||||
if (typeof originalFunction !== 'function') return;
|
||||
|
||||
module[funcName] = (...args) => {
|
||||
try {
|
||||
return callback(originalFunction, ...args);
|
||||
} catch {
|
||||
return originalFunction(...args);
|
||||
}
|
||||
};
|
||||
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
window.injectToFunction({ module: 'WAWebBackendJobsCommon', function: 'mediaTypeFromProtobuf' }, (func, ...args) => { const [proto] = args; return proto.locationMessage ? null : func(...args); });
|
||||
|
||||
window.injectToFunction({ module: 'WAWebE2EProtoUtils', function: 'typeAttributeFromProtobuf' }, (func, ...args) => { const [proto] = args; return proto.locationMessage || proto.groupInviteMessage ? 'text' : func(...args); });
|
||||
};
|
||||
1229
node_modules/whatsapp-web.js/src/util/Injected/Utils.js
generated
vendored
Normal file
1229
node_modules/whatsapp-web.js/src/util/Injected/Utils.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
126
node_modules/whatsapp-web.js/src/util/InterfaceController.js
generated
vendored
Normal file
126
node_modules/whatsapp-web.js/src/util/InterfaceController.js
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Interface Controller
|
||||
*/
|
||||
class InterfaceController {
|
||||
|
||||
constructor(props) {
|
||||
this.pupPage = props.pupPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the Chat Window
|
||||
* @param {string} chatId ID of the chat window that will be opened
|
||||
*/
|
||||
async openChatWindow(chatId) {
|
||||
return await this.pupPage.evaluate(async (chatId) => {
|
||||
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
return await window.Store.Cmd.openChatBottom({'chat':chat});
|
||||
}, chatId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the Chat Drawer
|
||||
* @param {string} chatId ID of the chat drawer that will be opened
|
||||
*/
|
||||
async openChatDrawer(chatId) {
|
||||
await this.pupPage.evaluate(async chatId => {
|
||||
let chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
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.WWebJS.getChat(chatId, { getAsModel: false });
|
||||
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) => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
const chat = window.Store.Chat.get(msg.id.remote) ?? await window.Store.Chat.find(msg.id.remote);
|
||||
const searchContext = await window.Store.SearchContext.getSearchContext(chat, msg.id);
|
||||
await window.Store.Cmd.openChatAt({ chat: chat, msgContext: searchContext });
|
||||
}, msgId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the Message Drawer
|
||||
* @param {string} msgId ID of the message drawer that will be opened
|
||||
*/
|
||||
async openMessageDrawer(msgId) {
|
||||
await this.pupPage.evaluate(async msgId => {
|
||||
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
||||
await window.Store.Cmd.msgInfoDrawer(msg);
|
||||
}, msgId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the Right Drawer
|
||||
*/
|
||||
async closeRightDrawer() {
|
||||
await this.pupPage.evaluate(async () => {
|
||||
await window.Store.DrawerManager.closeDrawerRight();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all Features
|
||||
*/
|
||||
async getFeatures() {
|
||||
return await this.pupPage.evaluate(() => {
|
||||
if(!window.Store.Features) throw new Error('This version of Whatsapp Web does not support features');
|
||||
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) => {
|
||||
if(!window.Store.Features) throw new Error('This version of Whatsapp Web does not support features');
|
||||
return window.Store.Features.supportsFeature(feature);
|
||||
}, feature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Features
|
||||
* @param {string[]} features to be enabled
|
||||
*/
|
||||
async enableFeatures(features) {
|
||||
await this.pupPage.evaluate((features) => {
|
||||
if(!window.Store.Features) throw new Error('This version of Whatsapp Web does not support 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) => {
|
||||
if(!window.Store.Features) throw new Error('This version of Whatsapp Web does not support features');
|
||||
for (const feature in features) {
|
||||
window.Store.Features.setFeature(features[feature], false);
|
||||
}
|
||||
}, features);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = InterfaceController;
|
||||
23
node_modules/whatsapp-web.js/src/util/Puppeteer.js
generated
vendored
Normal file
23
node_modules/whatsapp-web.js/src/util/Puppeteer.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Expose a function to the page if it does not exist
|
||||
*
|
||||
* NOTE:
|
||||
* Rewrite it to 'upsertFunction' after updating Puppeteer to 20.6 or higher
|
||||
* using page.removeExposedFunction
|
||||
* https://pptr.dev/api/puppeteer.page.removeexposedfunction
|
||||
*
|
||||
* @param {object} page - Puppeteer Page instance
|
||||
* @param {string} name
|
||||
* @param {Function} fn
|
||||
*/
|
||||
async function exposeFunctionIfAbsent(page, name, fn) {
|
||||
const exist = await page.evaluate((name) => {
|
||||
return !!window[name];
|
||||
}, name);
|
||||
if (exist) {
|
||||
return;
|
||||
}
|
||||
await page.exposeFunction(name, fn);
|
||||
}
|
||||
|
||||
module.exports = {exposeFunctionIfAbsent};
|
||||
186
node_modules/whatsapp-web.js/src/util/Util.js
generated
vendored
Normal file
186
node_modules/whatsapp-web.js/src/util/Util.js
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
'use strict';
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* Utility methods
|
||||
*/
|
||||
class Util {
|
||||
constructor() {
|
||||
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
|
||||
* @param {Object} given Object to assign defaults to
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
static mergeDefault(def, given) {
|
||||
if (!given) return def;
|
||||
for (const key in def) {
|
||||
if (!has(given, key) || given[key] === undefined) {
|
||||
given[key] = def[key];
|
||||
} else if (given[key] === Object(given[key])) {
|
||||
given[key] = Util.mergeDefault(def[key], given[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return given;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a image to webp
|
||||
* @param {MessageMedia} media
|
||||
*
|
||||
* @returns {Promise<MessageMedia>} media in webp format
|
||||
*/
|
||||
static async formatImageToWebpSticker(media, pupPage) {
|
||||
if (!media.mimetype.includes('image'))
|
||||
throw new Error('media is not a image');
|
||||
|
||||
if (media.mimetype.includes('webp')) {
|
||||
return media;
|
||||
}
|
||||
|
||||
return pupPage.evaluate((media) => {
|
||||
return window.WWebJS.toStickerData(media);
|
||||
}, media);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, pupPage) {
|
||||
let webpMedia;
|
||||
|
||||
if (media.mimetype.includes('image'))
|
||||
webpMedia = await this.formatImageToWebpSticker(media, pupPage);
|
||||
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;
|
||||
40
node_modules/whatsapp-web.js/src/webCache/LocalWebCache.js
generated
vendored
Normal file
40
node_modules/whatsapp-web.js/src/webCache/LocalWebCache.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const { WebCache, VersionResolveError } = require('./WebCache');
|
||||
|
||||
/**
|
||||
* LocalWebCache - Fetches a WhatsApp Web version from a local file store
|
||||
* @param {object} options - options
|
||||
* @param {string} options.path - Path to the directory where cached versions are saved, default is: "./.wwebjs_cache/"
|
||||
* @param {boolean} options.strict - If true, will throw an error if the requested version can't be fetched. If false, will resolve to the latest version.
|
||||
*/
|
||||
class LocalWebCache extends WebCache {
|
||||
constructor(options = {}) {
|
||||
super();
|
||||
|
||||
this.path = options.path || './.wwebjs_cache/';
|
||||
this.strict = options.strict || false;
|
||||
}
|
||||
|
||||
async resolve(version) {
|
||||
const filePath = path.join(this.path, `${version}.html`);
|
||||
|
||||
try {
|
||||
return fs.readFileSync(filePath, 'utf-8');
|
||||
}
|
||||
catch (err) {
|
||||
if (this.strict) throw new VersionResolveError(`Couldn't load version ${version} from the cache`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async persist(indexHtml, version) {
|
||||
// version = (version+'').replace(/[^0-9.]/g,'');
|
||||
const filePath = path.join(this.path, `${version}.html`);
|
||||
fs.mkdirSync(this.path, { recursive: true });
|
||||
fs.writeFileSync(filePath, indexHtml);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LocalWebCache;
|
||||
40
node_modules/whatsapp-web.js/src/webCache/RemoteWebCache.js
generated
vendored
Normal file
40
node_modules/whatsapp-web.js/src/webCache/RemoteWebCache.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
const fetch = require('node-fetch');
|
||||
const { WebCache, VersionResolveError } = require('./WebCache');
|
||||
|
||||
/**
|
||||
* RemoteWebCache - Fetches a WhatsApp Web version index from a remote server
|
||||
* @param {object} options - options
|
||||
* @param {string} options.remotePath - Endpoint that should be used to fetch the version index. Use {version} as a placeholder for the version number.
|
||||
* @param {boolean} options.strict - If true, will throw an error if the requested version can't be fetched. If false, will resolve to the latest version. Defaults to false.
|
||||
*/
|
||||
class RemoteWebCache extends WebCache {
|
||||
constructor(options = {}) {
|
||||
super();
|
||||
|
||||
if (!options.remotePath) throw new Error('webVersionCache.remotePath is required when using the remote cache');
|
||||
this.remotePath = options.remotePath;
|
||||
this.strict = options.strict || false;
|
||||
}
|
||||
|
||||
async resolve(version) {
|
||||
const remotePath = this.remotePath.replace('{version}', version);
|
||||
|
||||
try {
|
||||
const cachedRes = await fetch(remotePath);
|
||||
if (cachedRes.ok) {
|
||||
return cachedRes.text();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Error fetching version ${version} from remote`, err);
|
||||
}
|
||||
|
||||
if (this.strict) throw new VersionResolveError(`Couldn't load version ${version} from the archive`);
|
||||
return null;
|
||||
}
|
||||
|
||||
async persist() {
|
||||
// Nothing to do here
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RemoteWebCache;
|
||||
14
node_modules/whatsapp-web.js/src/webCache/WebCache.js
generated
vendored
Normal file
14
node_modules/whatsapp-web.js/src/webCache/WebCache.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Default implementation of a web version cache that does nothing.
|
||||
*/
|
||||
class WebCache {
|
||||
async resolve() { return null; }
|
||||
async persist() { }
|
||||
}
|
||||
|
||||
class VersionResolveError extends Error { }
|
||||
|
||||
module.exports = {
|
||||
WebCache,
|
||||
VersionResolveError
|
||||
};
|
||||
20
node_modules/whatsapp-web.js/src/webCache/WebCacheFactory.js
generated
vendored
Normal file
20
node_modules/whatsapp-web.js/src/webCache/WebCacheFactory.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
const RemoteWebCache = require('./RemoteWebCache');
|
||||
const LocalWebCache = require('./LocalWebCache');
|
||||
const { WebCache } = require('./WebCache');
|
||||
|
||||
const createWebCache = (type, options) => {
|
||||
switch (type) {
|
||||
case 'remote':
|
||||
return new RemoteWebCache(options);
|
||||
case 'local':
|
||||
return new LocalWebCache(options);
|
||||
case 'none':
|
||||
return new WebCache();
|
||||
default:
|
||||
throw new Error(`Invalid WebCache type ${type}`);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
createWebCache,
|
||||
};
|
||||
Reference in New Issue
Block a user