Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e60d972bff | ||
|
|
3c4a139f52 | ||
|
|
bf615efa96 | ||
|
|
2af3940be7 | ||
|
|
64e145909e | ||
|
|
e90f34cc96 | ||
|
|
a23cf2dd26 | ||
|
|
7b623d0faa | ||
|
|
14788b1d53 | ||
|
|
e1bf8cf735 | ||
|
|
2117731b46 | ||
|
|
74f8fe1caf | ||
|
|
9388a3b277 | ||
|
|
13e7a05e1b | ||
|
|
885fa25c0c |
No files matched your search
+15
-6
@@ -1,4 +1,13 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: 'v2.7.1'
|
||||
hooks:
|
||||
- id: prettier
|
||||
types_or: [javascript, ts]
|
||||
files: |
|
||||
(?x)^(
|
||||
src/.*|
|
||||
)$
|
||||
- repo: https://github.com/Lucas-C/pre-commit-hooks-nodejs
|
||||
rev: v1.1.2
|
||||
hooks:
|
||||
@@ -12,9 +21,9 @@ repos:
|
||||
language: pygrep
|
||||
entry: 'plus'
|
||||
files: |
|
||||
(?x)^(
|
||||
src/api/.*|
|
||||
src/core/.*|
|
||||
src/structures/.*|
|
||||
src/config.service.ts|
|
||||
)$
|
||||
(?x)^(
|
||||
src/api/.*|
|
||||
src/core/.*|
|
||||
src/structures/.*|
|
||||
src/config.service.ts|
|
||||
)$
|
||||
+1
-1
@@ -9,7 +9,7 @@ ENV PUPPETEER_SKIP_DOWNLOAD=True
|
||||
WORKDIR /
|
||||
RUN git clone https://github.com/WhiskeySockets/Baileys WhiskeySockets-Baileys && \
|
||||
cd WhiskeySockets-Baileys && \
|
||||
git checkout b7878e531144133b48d9e5970787e7b256d21063 && \
|
||||
git checkout e3ac5f596f16b706420ed016a349fa75bd3a157f && \
|
||||
yarn install && \
|
||||
yarn build:all
|
||||
|
||||
|
||||
@@ -1,26 +1,8 @@
|
||||
build:
|
||||
docker build . -t devlikeapro/whatsapp-http-api
|
||||
|
||||
run-webjs:
|
||||
docker run \
|
||||
--rm -d \
|
||||
-p 127.0.0.1:3000:3000/tcp \
|
||||
-v `pwd`/.sessions:/app/.sessions \
|
||||
-e WHATSAPP_HOOK_URL=https://httpbin.org/post \
|
||||
-e WHATSAPP_HOOK_EVENTS=* \
|
||||
-e WHATSAPP_API_KEY=321 \
|
||||
--name whatsapp-http-api devlikeapro/whatsapp-http-api
|
||||
|
||||
run-venom:
|
||||
docker run \
|
||||
--rm -d \
|
||||
-p 127.0.0.1:3000:3000/tcp \
|
||||
-v `pwd`/.sessions:/app/.sessions \
|
||||
-e WHATSAPP_HOOK_URL=https://httpbin.org/post \
|
||||
-e WHATSAPP_HOOK_EVENTS=* \
|
||||
-e WHATSAPP_DEFAULT_ENGINE=VENOM \
|
||||
-e WHATSAPP_API_KEY=321 \
|
||||
--name whatsapp-http-api devlikeapro/whatsapp-http-api
|
||||
build-plus:
|
||||
docker build . -t devlikeapro/whatsapp-http-api-plus
|
||||
|
||||
stop:
|
||||
docker stop whatsapp-http-api
|
||||
|
||||
@@ -121,7 +121,7 @@ Read more about how to get `PASSWORD` for [Plus Version →]({{< relref "plus-ve
|
||||
Run WhatsApp HTTP API:
|
||||
|
||||
```bash
|
||||
docker run -it --rm -p 127.0.0.1:3000:3000/tcp --name whatsapp-http-api devlikeapro/whatsapp-http-api
|
||||
docker run -it --rm -p 3000:3000/tcp --name whatsapp-http-api devlikeapro/whatsapp-http-api
|
||||
|
||||
# It prints logs and the last line must be
|
||||
# WhatsApp HTTP API is running on: http://[::1]:3000
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
version: '3'
|
||||
services:
|
||||
whatsapp-http-api:
|
||||
image: devlikeapro/whatsapp-http-api
|
||||
container_name: whatsapp-http-api
|
||||
ports:
|
||||
- "3000:3000/tcp"
|
||||
environment:
|
||||
# Environment variables from https://waha.devlike.pro/docs/how-to/config/
|
||||
- WHATSAPP_HOOK_URL=https://httpbin.org/post
|
||||
- WHATSAPP_HOOK_EVENTS=message
|
||||
- WHATSAPP_DEFAULT_ENGINE=WEBJS
|
||||
restart: always
|
||||
|
||||
whatsapp-http-api-plus:
|
||||
image: devlikeapro/whatsapp-http-api-plus
|
||||
container_name: whatsapp-http-api-plus
|
||||
ports:
|
||||
- "3000:3000/tcp"
|
||||
volumes:
|
||||
- "./.sessions:/app/.sessions"
|
||||
environment:
|
||||
# Environment variables from https://waha.devlike.pro/docs/how-to/config/
|
||||
- WHATSAPP_RESTART_ALL_SESSIONS=True
|
||||
- WHATSAPP_HOOK_URL=https://httpbin.org/post
|
||||
- WHATSAPP_HOOK_EVENTS=message
|
||||
- WHATSAPP_DEFAULT_ENGINE=WEBJS
|
||||
- WHATSAPP_API_KEY=321
|
||||
- WHATSAPP_SWAGGER_USERNAME=admin
|
||||
- WHATSAPP_SWAGGER_PASSWORD=123
|
||||
- WHATSAPP_API_HOSTNAME=localhost
|
||||
restart: always
|
||||
@@ -13,6 +13,39 @@ weight: 600
|
||||
toc: true
|
||||
---
|
||||
|
||||
## 2021.6 - June 2023
|
||||
|
||||
Improvements on session management, restarting sessions and more:
|
||||
|
||||
- Added `WHATSAPP_RESTART_ALL_SESSIONS=True`: Set this variable to `True` to start all **STOPPED** sessions after
|
||||
container restarts. By default, this variable is set to `False`.
|
||||
- Please note that this will start all **STOPPED** sessions, not just the sessions that were working before the
|
||||
restart. You can maintain the session list by
|
||||
using `POST /api/session/stop` with the `logout: True` parameter or by calling `POST /api/session/logout` to remove
|
||||
**STOPPED** sessions. You can see all sessions, including **STOPPED** sessions, in the `GET /api/sessions/all=True`
|
||||
response.
|
||||
- `WHATSAPP_START_SESSION` now support more than one session! Separate session names by command, and it'll start them
|
||||
ALWAYS after container restart `WHATSAPP_START_SESSION=session1,session2`
|
||||
- `WHATSAPP_SWAGGER_CONFIG_ADVANCED=true` enables advanced configuration options for Swagger documentation - you can customize host, port and base URL for the requests.
|
||||
Disabled by default.
|
||||
- Added `?all=true` parameter to `GET /api/session?all=True` endpoint - it'll show you ALL session, included **STOPPED
|
||||
**, so you can know which one will be restarted if you set `WHATSAPP_RESTART_ALL_SESSIONS=True` environment variable.
|
||||
- Added `POST /api/sessions/logout` that allow you to logout from session - remove saved credentials.
|
||||
- Added `logout` boolean parameter to `POST /api/sessions/stop` request that allow you to stop the session AND logout at
|
||||
the same time.
|
||||
- Added [How to deploy page ->]({{< relref "/docs/how-to/deploy" >}}) with
|
||||
[docker-compose.yaml](https://github.com/devlikeapro/whatsapp-http-api/blob/core/docker-compose.yaml) example
|
||||
- Added `engine` field in webhook payload
|
||||
|
||||
```json
|
||||
{
|
||||
"event": "message",
|
||||
"session": "default",
|
||||
"engine": "WEBJS",
|
||||
"payload": {}
|
||||
}
|
||||
```
|
||||
|
||||
## 2021.5 - May 2023
|
||||
|
||||
- Added new [NOWEB engine]({{< relref "/docs/how-to/engines" >}}). **NOWEB** engine does not require a browser to work
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
---
|
||||
title : "Configuration"
|
||||
title: "Configuration"
|
||||
description: "Configuration"
|
||||
lead: ""
|
||||
date: 2020-10-06T08:48:45+00:00
|
||||
lastmod: 2020-10-06T08:48:45+00:00
|
||||
draft: false
|
||||
images: []
|
||||
images: [ ]
|
||||
weight: 800
|
||||
---
|
||||
|
||||
You can configure WhatsApp HTTP API behaviour via environment variables, by adding `-e WHATSAPP_VARNAME=value` at the
|
||||
begging of the command line or by using [other options](https://docs.docker.com/engine/reference/commandline/run/)
|
||||
|
||||
@@ -15,22 +16,118 @@ begging of the command line or by using [other options](https://docs.docker.com/
|
||||
docker run -it -e "WHATSAPP_HOOK_EVENTS=*" -e WHATSAPP_HOOK_URL=https://httpbin.org/post devlikeapro/whatsapp-http-api
|
||||
```
|
||||
|
||||
It's not necessary to always run such a long command - you can save all data in
|
||||
[docker-compose.yaml](https://github.com/devlikeapro/whatsapp-http-api/blob/core/docker-compose.yaml)
|
||||
file as described on [How to deploy page ->]({{< relref "/docs/how-to/deploy" >}}).
|
||||
|
||||
## Environment variables
|
||||
|
||||
- `DEBUG=1` - show debug and verbose logs, set in any value
|
||||
- `WHATSAPP_API_PORT=3000` - listen port for HTTP server (default: `3000`)
|
||||
- `WHATSAPP_API_HOSTNAME=localhost` - Hostname for HTTP server (default: `localhost`)
|
||||
- `WHATSAPP_API_KEY=mysecret` - protect the api with a secret code. If you set it - add `X-Api-Key: mysecret` to all
|
||||
requests.
|
||||
- `WHATSAPP_SWAGGER_USERNAME=admin` + `WHATSAPP_SWAGGER_PASSWORD=admin` - protect the Swagger panel with `admin / admin`
|
||||
credentials. It doesn't affect api access!
|
||||
- `WHATSAPP_START_SESSION=default` - start session with the name right after launching the app
|
||||
The following environment variables can be used to configure the WAHA:
|
||||
|
||||
## File storage 
|
||||
- `DEBUG=1`: Set this variable to any value to enable debug and verbose logs.
|
||||
- `WHATSAPP_API_PORT=3000`: The port number that the HTTP server will listen on. The default value is `3000`.
|
||||
- `WHATSAPP_API_HOSTNAME=localhost`: The hostname for the HTTP server. The default value is `localhost`.
|
||||
- `WHATSAPP_API_KEY=mysecret`: If you set this variable, you must include the `X-Api-Key: mysecret` header in all
|
||||
requests to the API. This will protect the API with a secret code.
|
||||
- `WHATSAPP_SWAGGER_USERNAME=admin` and `WHATSAPP_SWAGGER_PASSWORD=admin`: These variables can be used to protect the
|
||||
Swagger panel with `admin / admin` credentials. This does not affect API access.
|
||||
- `WHATSAPP_SWAGGER_CONFIG_ADVANCED=true` - enables advanced configuration options for Swagger documentation - you can customize host, port and base URL for the requests.
|
||||
Disabled by default.
|
||||
- `WHATSAPP_RESTART_ALL_SESSIONS=True`: Set this variable to `True` to start all **STOPPED** sessions after container
|
||||
restarts. By default, this variable is set to `False`.
|
||||
- Please note that this will start all **STOPPED** sessions, not just the sessions that were working before the restart. You can maintain the session list by
|
||||
using `POST /api/session/stop` with the `logout: True` parameter or by calling `POST /api/session/logout` to remove
|
||||
**STOPPED** sessions. You can see all sessions, including **STOPPED** sessions, in the `GET /api/sessions/all=True`
|
||||
response.
|
||||
- `WHATSAPP_START_SESSION=session1,session2`: This variable can be used to start sessions with the specified names right
|
||||
after launching the API. Separate session names with a comma.
|
||||
|
||||
- `WHATSAPP_FILES_MIMETYPES` - download only these mimetypes from messages (download all files be default). Mimetypes
|
||||
must be separated by a comma, without spaces: `audio,image/png,image/gif`. In order to choose type use prefix (
|
||||
like `audio,image`).
|
||||
- `WHATSAPP_FILES_LIFETIME`- to keep free space files will be removed after this time (default: `180`, in seconds)
|
||||
- `WHATSAPP_FILES_FOLDER` - folder where will be stored files from chats (images, voice messages) (
|
||||
default: `/tmp/whatsapp-files`)
|
||||
### Examples
|
||||
|
||||
#### Debug Mode
|
||||
|
||||
To enable debug mode, set the `DEBUG` environment variable to any value:
|
||||
|
||||
```
|
||||
DEBUG=1
|
||||
```
|
||||
|
||||
#### Protecting the API with a Secret Code
|
||||
|
||||
To protect the API with a secret code, set the `WHATSAPP_API_KEY` environment variable to your secret code:
|
||||
|
||||
```
|
||||
WHATSAPP_API_KEY=mysecret
|
||||
```
|
||||
|
||||
You must include the `X-Api-Key: mysecret` header in all requests to the API.
|
||||
|
||||
#### Starting Sessions Automatically
|
||||
|
||||
To start sessions automatically when the API is launched, set the `WHATSAPP_START_SESSION` environment variable to a
|
||||
comma-separated list of session names:
|
||||
|
||||
```
|
||||
WHATSAPP_START_SESSION=session1,session2
|
||||
```
|
||||
|
||||
#### Restarting All Sessions
|
||||
|
||||
To start all **STOPPED** sessions after container restarts, set the `WHATSAPP_RESTART_ALL_SESSIONS` environment variable
|
||||
to `True`:
|
||||
|
||||
```
|
||||
WHATSAPP_RESTART_ALL_SESSIONS=True
|
||||
```
|
||||
|
||||
#### Protecting the Swagger Panel
|
||||
|
||||
To protect the Swagger panel with `admin / admin` credentials, set the `WHATSAPP_SWAGGER_USERNAME`
|
||||
and `WHATSAPP_SWAGGER_PASSWORD` environment variables:
|
||||
|
||||
```
|
||||
WHATSAPP_SWAGGER_USERNAME=admin
|
||||
WHATSAPP_SWAGGER_PASSWORD=admin
|
||||
```
|
||||
|
||||
## File storage variables 
|
||||
|
||||
|
||||
The following environment variables can be used to configure the file storage options for the WAHA:
|
||||
|
||||
- `WHATSAPP_FILES_MIMETYPES`: This variable can be used to download only specific mimetypes from messages. By default,
|
||||
all files are downloaded. The mimetypes must be separated by a comma, without spaces. For
|
||||
example: `audio,image/png,image/gif`. To choose a specific type, use a prefix (like `audio,image`).
|
||||
- `WHATSAPP_FILES_LIFETIME`: This variable can be used to set the time (in seconds) after which files will be removed to
|
||||
free up space. The default value is `180`.
|
||||
- `WHATSAPP_FILES_FOLDER`: This variable can be used to set the folder where files from chats (images, voice messages)
|
||||
will be stored. The default value is `/tmp/whatsapp-files`.
|
||||
|
||||
### Examples
|
||||
|
||||
#### Downloading Specific Mimetypes
|
||||
|
||||
To download only specific mimetypes from messages, set the `WHATSAPP_FILES_MIMETYPES` environment variable to a
|
||||
comma-separated list of mimetypes:
|
||||
|
||||
```
|
||||
WHATSAPP_FILES_MIMETYPES=audio,image/png,image/gif
|
||||
```
|
||||
|
||||
#### Setting the File Lifetime
|
||||
|
||||
To set the time (in seconds) after which files will be removed to free up space, set the `WHATSAPP_FILES_LIFETIME`
|
||||
environment variable:
|
||||
|
||||
```
|
||||
WHATSAPP_FILES_LIFETIME=300
|
||||
```
|
||||
|
||||
#### Setting the File Storage Folder
|
||||
|
||||
To set the folder where files from chats (images, voice messages) will be stored, set the `WHATSAPP_FILES_FOLDER`
|
||||
environment variable:
|
||||
|
||||
```
|
||||
WHATSAPP_FILES_FOLDER=/home/user/whatsapp-files
|
||||
```
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
title: "Deploy"
|
||||
description: "How to deploy WAHA"
|
||||
lead: ""
|
||||
date: 2020-10-06T08:48:45+00:00
|
||||
lastmod: 2020-10-06T08:48:45+00:00
|
||||
draft: false
|
||||
images: [ ]
|
||||
weight: 801
|
||||
---
|
||||
|
||||
This page provides useful information to assist you in deploying the project.
|
||||
It includes tips on how to avoid running long command lines, how to view logs, and other helpful advice.
|
||||
|
||||
## How to Use Docker Compose
|
||||
|
||||
Docker Compose is a tool that allows you to define and run multi-container Docker applications. It simplifies the
|
||||
process of managing multiple containers and their dependencies. In this topic, we will walk you through how to use
|
||||
Docker Compose with the WhatsApp HTTP API.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before you start, you need to have Docker and Docker Compose installed on your machine. You can download Docker from the
|
||||
official website [here](https://www.docker.com/products/docker-desktop). Docker Compose is included with Docker Desktop
|
||||
for Windows and macOS, but for Linux, you need to install it separately. You can find the installation
|
||||
instructions [here](https://docs.docker.com/compose/install/).
|
||||
|
||||
### Getting Started
|
||||
|
||||
To get started, you need to clone the docker-compose file to your local machine.
|
||||
Open your terminal and run the following command:
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/devlikeapro/whatsapp-http-api/core/docker-compose.yaml
|
||||
```
|
||||
|
||||
### Running the WhatsApp HTTP API Service
|
||||
|
||||
To start the `whatsapp-http-api` service, run the following command:
|
||||
|
||||
```
|
||||
docker-compose up -d whatsapp-http-api
|
||||
```
|
||||
|
||||
This will start the container in detached mode and map port 3000 to 3000 on the host machine.
|
||||
|
||||
To stop the service, run the command:
|
||||
|
||||
```
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
This will stop and remove the container.
|
||||
|
||||
To restart the service, run the command:
|
||||
|
||||
```
|
||||
docker-compose restart whtasapp-http-api
|
||||
```
|
||||
|
||||
This will restart the container.
|
||||
|
||||
### Viewing the Logs
|
||||
|
||||
To view the logs for the `whatsapp-http-api` service, run the command:
|
||||
|
||||
```
|
||||
docker-compose logs -f whatsapp-http-api
|
||||
```
|
||||
|
||||
This will show the logs in real-time. To view the logs for the `whatsapp-http-api-plus` service,
|
||||
replace `whatsapp-http-api` with `whatsapp-http-api-plus`.
|
||||
|
||||
To view the logs for a specific period, run the command:
|
||||
|
||||
```
|
||||
docker-compose logs --since <time>
|
||||
```
|
||||
|
||||
Replace `<time>` with the time period you want to view the logs for. For example, `docker-compose logs --since 1h` will
|
||||
show the logs for the past hour.
|
||||
|
||||
### Using the WhatsApp HTTP API Services
|
||||
|
||||
There are two services provided in the `docker-compose.yml` file - `whatsapp-http-api` and `whatsapp-http-api-plus`.
|
||||
It is important to note that these services must not be run at the same time.
|
||||
By default, the `whatsapp-http-api` service will be used.
|
||||
|
||||
To use the `whatsapp-http-api-plus` service, you need to specify it in the command.
|
||||
|
||||
@@ -37,6 +37,7 @@ On the URL that you set via `WHATSAPP_HOOK_URL` you receive JSON-data with follo
|
||||
{
|
||||
"event": "message",
|
||||
"session": "default",
|
||||
"engine": "WEBJS",
|
||||
"payload": {}
|
||||
}
|
||||
```
|
||||
@@ -50,7 +51,7 @@ Below the list of all events that WhatsApp HTTP API sends to your.
|
||||
Run the bellow command and see look at the logs - it prints body request for all events that happen in your WhatsApp!
|
||||
|
||||
```bash
|
||||
docker run -it -e "WHATSAPP_HOOK_EVENTS=*" -e WHATSAPP_HOOK_URL=https://httpbin.org/post devlikeapro/whatsapp-http-api
|
||||
docker run -it -e "WHATSAPP_HOOK_EVENTS=*" -e WHATSAPP_HOOK_URL=https://httpbin.org/post -p 3000:3000 devlikeapro/whatsapp-http-api
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
@@ -26,7 +26,7 @@ to the container. WAHA stores authentication information in the directory and re
|
||||
|
||||
The full command would be:
|
||||
```bash
|
||||
docker run --rm -d -v `pwd`/.sessions:/app/.sessions -p 127.0.0.1:3000:3000/tcp --name whatsapp-http-api devlikeapro/whatsapp-http-api
|
||||
docker run --rm -d -v `pwd`/.sessions:/app/.sessions -p 3000:3000/tcp --name whatsapp-http-api devlikeapro/whatsapp-http-api
|
||||
```
|
||||
|
||||
### Remote storage 
|
||||
@@ -69,11 +69,26 @@ The response:
|
||||
|
||||
In order to stop a new session - call `POST /api/sessions/stop`
|
||||
|
||||
{{< alert icon="👉" text="The stop request does not log out the account. Manually remove the session storage." />}}
|
||||
{{< alert icon="👉" text="The stop request does not log out the account by default. Set 'logout' field to 'true'." />}}
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "default"
|
||||
"name": "default",
|
||||
"logout": true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Logout
|
||||
|
||||
In order to log out the session - call `POST /api/sessions/logout`
|
||||
|
||||
{{< alert icon="👉" text="You must stop session first." />}}
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "default",
|
||||
"logout": true
|
||||
}
|
||||
```
|
||||
|
||||
@@ -95,7 +95,7 @@ docker tag devlikeapro/whatsapp-http-api-plus:arm devlikeapro/whatsapp-http-api
|
||||
Run WhatsApp HTTP API:
|
||||
|
||||
```bash
|
||||
docker run -it --rm -p 127.0.0.1:3000:3000/tcp --name whatsapp-http-api devlikeapro/whatsapp-http-api
|
||||
docker run -it --rm -p 3000:3000/tcp --name whatsapp-http-api devlikeapro/whatsapp-http-api
|
||||
|
||||
# It prints logs and the last line must be
|
||||
# WhatsApp HTTP API is running on: http://[::1]:3000
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"openapi":"3.0.0","paths":{"/api/sessions/start":{"post":{"operationId":"SessionsController_start","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionStartRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionDTO"}}}}},"tags":["sessions"],"security":[{"api_key":[]}]}},"/api/sessions/stop":{"post":{"operationId":"SessionsController_stop","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionStopRequest"}}}},"responses":{"201":{"description":""}},"tags":["sessions"],"security":[{"api_key":[]}]}},"/api/sessions":{"get":{"operationId":"SessionsController_list","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SessionDTO"}}}}}},"tags":["sessions"],"security":[{"api_key":[]}]}},"/api/checkNumberStatus":{"get":{"operationId":"ChattingController_checkNumberStatus","summary":"Check number status","parameters":[{"name":"phone","required":true,"in":"query","schema":{"type":"string"}},{"name":"session","required":true,"in":"query","schema":{"default":"default","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WANumberExistResult"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendContactVcard":{"post":{"operationId":"ChattingController_sendContactVcard","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageContactVcardRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendText":{"get":{"operationId":"ChattingController_sendTextGet","summary":"Send a text message","parameters":[{"name":"phone","required":true,"in":"query","schema":{"type":"string"}},{"name":"text","required":true,"in":"query","schema":{"type":"string"}},{"name":"session","required":true,"in":"query","schema":{"default":"default","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]},"post":{"operationId":"ChattingController_sendText","summary":"Send a text message","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTextRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WAMessage"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendTextButtons":{"post":{"operationId":"ChattingController_sendTextButtons","summary":"Send a text message with buttons","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTextButtonsRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendLocation":{"post":{"operationId":"ChattingController_sendLocation","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageLocationRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendLinkPreview":{"post":{"operationId":"ChattingController_sendLinkPreview","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageLinkPreviewRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendImage":{"post":{"operationId":"ChattingController_sendImage","summary":"Send an image. Either from an URL or base64 data - look at the request schemas for details.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageImageRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendFile":{"post":{"operationId":"ChattingController_sendFile","summary":"Send a file. Either from an URL or base64 data - look at the request schemas for details.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageFileRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendVoice":{"post":{"operationId":"ChattingController_sendVoice","summary":"Send an voice message. Either from an URL or basLine truncated
|
||||
{"openapi":"3.0.0","paths":{"/api/sessions/start":{"post":{"operationId":"SessionsController_start","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionStartRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionDTO"}}}}},"tags":["sessions"],"security":[{"api_key":[]}]}},"/api/sessions/stop":{"post":{"operationId":"SessionsController_stop","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionStopRequest"}}}},"responses":{"201":{"description":""}},"tags":["sessions"],"security":[{"api_key":[]}]}},"/api/sessions":{"get":{"operationId":"SessionsController_list","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SessionDTO"}}}}}},"tags":["sessions"],"security":[{"api_key":[]}]}},"/api/checkNumberStatus":{"get":{"operationId":"ChattingController_checkNumberStatus","summary":"Check number status","parameters":[{"name":"phone","required":true,"in":"query","schema":{"type":"string"}},{"name":"session","required":true,"in":"query","schema":{"default":"default","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WANumberExistResult"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendContactVcard":{"post":{"operationId":"ChattingController_sendContactVcard","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageContactVcardRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendText":{"get":{"operationId":"ChattingController_sendTextGet","summary":"Send a text message","parameters":[{"name":"phone","required":true,"in":"query","schema":{"type":"string"}},{"name":"text","required":true,"in":"query","schema":{"type":"string"}},{"name":"session","required":true,"in":"query","schema":{"default":"default","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]},"post":{"operationId":"ChattingController_sendText","summary":"Send a text message","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTextRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WAMessage"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendTextButtons":{"post":{"operationId":"ChattingController_sendTextButtons","summary":"Send a text message with buttons","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageTextButtonsRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendLocation":{"post":{"operationId":"ChattingController_sendLocation","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageLocationRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendLinkPreview":{"post":{"operationId":"ChattingController_sendLinkPreview","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageLinkPreviewRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendImage":{"post":{"operationId":"ChattingController_sendImage","summary":"Send an image. Either from an URL or base64 data - look at the request schemas for details.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageImageRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendFile":{"post":{"operationId":"ChattingController_sendFile","summary":"Send a file. Either from an URL or base64 data - look at the request schemas for details.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageFileRequest"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["chatting"],"security":[{"api_key":[]}]}},"/api/sendVoice":{"post":{"operationId":"ChattingController_sendVoice","summary":"Send an voice message. Either from an URL or basLine truncated
|
||||
@@ -1,2 +1,3 @@
|
||||
flask~=1.0
|
||||
requests~=2.0
|
||||
markupsafe==2.0.1
|
||||
+3
-1
@@ -31,12 +31,14 @@
|
||||
"@nestjs/platform-express": "^9.0.9",
|
||||
"@nestjs/serve-static": "^2.1.3",
|
||||
"@nestjs/swagger": "^6.0.5",
|
||||
"@types/lodash": "^4.14.194",
|
||||
"@types/ws": "^8.5.4",
|
||||
"class-validator": "^0.12.2",
|
||||
"del": "^6.0.0",
|
||||
"express-basic-auth": "^1.2.1",
|
||||
"file-type": "16.5.4",
|
||||
"link-preview-js": "^3.0.4",
|
||||
"lodash": "^4.17.21",
|
||||
"mime-types": "^2.1.27",
|
||||
"passport": "^0.6.0",
|
||||
"passport-headerapikey": "^1.2.2",
|
||||
@@ -48,7 +50,7 @@
|
||||
"rimraf": "^3.0.2",
|
||||
"rxjs": "^7.1.0",
|
||||
"swagger-ui-express": "^4.1.4",
|
||||
"venom-bot": "^4.3.7",
|
||||
"venom-bot": "^5.0.1",
|
||||
"whatsapp-web.js": "https://github.com/pedroslopez/whatsapp-web.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
+128
-118
@@ -1,141 +1,151 @@
|
||||
import {Body, Controller, Get, Post, Put, Query} from '@nestjs/common';
|
||||
import {ApiOperation, ApiSecurity, ApiTags} from "@nestjs/swagger";
|
||||
import { Body, Controller, Get, Post, Put, Query } from '@nestjs/common';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import {
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery, GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextQuery,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest, SendSeenRequest
|
||||
} from "../structures/chatting.dto";
|
||||
import {WAMessage, WANumberExistResult} from "../structures/responses.dto";
|
||||
import {SessionManager} from "../core/abc/manager.abc";
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextQuery,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest,
|
||||
SendSeenRequest,
|
||||
} from '../structures/chatting.dto';
|
||||
import { WAMessage, WANumberExistResult } from '../structures/responses.dto';
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api')
|
||||
@ApiTags('chatting')
|
||||
export class ChattingController {
|
||||
constructor(private manager: SessionManager) {
|
||||
}
|
||||
constructor(private manager: SessionManager) {}
|
||||
|
||||
@Get('/checkNumberStatus')
|
||||
@ApiOperation({summary: 'Check number status'})
|
||||
async checkNumberStatus(@Query() request: CheckNumberStatusQuery): Promise<WANumberExistResult> {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.checkNumberStatus(request)
|
||||
}
|
||||
@Get('/checkNumberStatus')
|
||||
@ApiOperation({ summary: 'Check number status' })
|
||||
async checkNumberStatus(
|
||||
@Query() request: CheckNumberStatusQuery,
|
||||
): Promise<WANumberExistResult> {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.checkNumberStatus(request);
|
||||
}
|
||||
|
||||
@Post('/sendContactVcard')
|
||||
sendContactVcard(@Body() request: MessageContactVcardRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendContactVCard(request)
|
||||
}
|
||||
@Post('/sendContactVcard')
|
||||
sendContactVcard(@Body() request: MessageContactVcardRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendContactVCard(request);
|
||||
}
|
||||
|
||||
@Get('/sendText')
|
||||
@ApiOperation({summary: 'Send a text message'})
|
||||
sendTextGet(
|
||||
@Query() query: MessageTextQuery,
|
||||
) {
|
||||
const whatsapp = this.manager.getSession(query.session)
|
||||
const msg = new MessageTextRequest()
|
||||
msg.chatId = query.phone
|
||||
msg.text = query.text
|
||||
return whatsapp.sendText(msg)
|
||||
}
|
||||
@Get('/sendText')
|
||||
@ApiOperation({ summary: 'Send a text message' })
|
||||
sendTextGet(@Query() query: MessageTextQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session);
|
||||
const msg = new MessageTextRequest();
|
||||
msg.chatId = query.phone;
|
||||
msg.text = query.text;
|
||||
return whatsapp.sendText(msg);
|
||||
}
|
||||
|
||||
@Post('/sendText')
|
||||
@ApiOperation({summary: 'Send a text message'})
|
||||
sendText(@Body() request: MessageTextRequest): Promise<WAMessage> {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendText(request)
|
||||
}
|
||||
@Post('/sendText')
|
||||
@ApiOperation({ summary: 'Send a text message' })
|
||||
sendText(@Body() request: MessageTextRequest): Promise<WAMessage> {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendText(request);
|
||||
}
|
||||
|
||||
@Post('/sendTextButtons')
|
||||
@ApiOperation({summary: 'Send a text message with buttons'})
|
||||
sendTextButtons(@Body() request: MessageTextButtonsRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendTextButtons(request)
|
||||
}
|
||||
@Post('/sendTextButtons')
|
||||
@ApiOperation({ summary: 'Send a text message with buttons' })
|
||||
sendTextButtons(@Body() request: MessageTextButtonsRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendTextButtons(request);
|
||||
}
|
||||
|
||||
@Post('/sendLocation')
|
||||
sendLocation(@Body() request: MessageLocationRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendLocation(request)
|
||||
}
|
||||
@Post('/sendLocation')
|
||||
sendLocation(@Body() request: MessageLocationRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendLocation(request);
|
||||
}
|
||||
|
||||
@Post('/sendLinkPreview')
|
||||
sendLinkPreview(@Body() request: MessageLinkPreviewRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendLinkPreview(request)
|
||||
}
|
||||
@Post('/sendLinkPreview')
|
||||
sendLinkPreview(@Body() request: MessageLinkPreviewRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendLinkPreview(request);
|
||||
}
|
||||
|
||||
@Post('/sendImage')
|
||||
@ApiOperation({summary: "Send an image. Either from an URL or base64 data - look at the request schemas for details."})
|
||||
sendImage(@Body() request: MessageImageRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendImage(request)
|
||||
}
|
||||
@Post('/sendImage')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Send an image. Either from an URL or base64 data - look at the request schemas for details.',
|
||||
})
|
||||
sendImage(@Body() request: MessageImageRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendImage(request);
|
||||
}
|
||||
|
||||
@Post('/sendFile')
|
||||
@ApiOperation({summary: "Send a file. Either from an URL or base64 data - look at the request schemas for details."})
|
||||
sendFile(@Body() request: MessageFileRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendFile(request)
|
||||
}
|
||||
@Post('/sendFile')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Send a file. Either from an URL or base64 data - look at the request schemas for details.',
|
||||
})
|
||||
sendFile(@Body() request: MessageFileRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendFile(request);
|
||||
}
|
||||
|
||||
@Post('/sendVoice')
|
||||
@ApiOperation({summary: "Send an voice message. Either from an URL or base64 data - look at the request schemas for details."})
|
||||
sendVoice(@Body() request: MessageVoiceRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.sendVoice(request)
|
||||
}
|
||||
@Post('/sendVoice')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Send an voice message. Either from an URL or base64 data - look at the request schemas for details.',
|
||||
})
|
||||
sendVoice(@Body() request: MessageVoiceRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.sendVoice(request);
|
||||
}
|
||||
|
||||
@Post('/reply')
|
||||
@ApiOperation({summary: 'Reply to a text message'})
|
||||
reply(@Body() request: MessageReplyRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.reply(request)
|
||||
}
|
||||
@Post('/reply')
|
||||
@ApiOperation({ summary: 'Reply to a text message' })
|
||||
reply(@Body() request: MessageReplyRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.reply(request);
|
||||
}
|
||||
|
||||
@Post('/sendSeen')
|
||||
sendSeen(@Body() chat: SendSeenRequest) {
|
||||
const whatsapp = this.manager.getSession(chat.session)
|
||||
return whatsapp.sendSeen(chat)
|
||||
}
|
||||
@Post('/sendSeen')
|
||||
sendSeen(@Body() chat: SendSeenRequest) {
|
||||
const whatsapp = this.manager.getSession(chat.session);
|
||||
return whatsapp.sendSeen(chat);
|
||||
}
|
||||
|
||||
@Post('/startTyping')
|
||||
async startTyping(@Body() chat: ChatRequest) {
|
||||
// It's infinitive action
|
||||
const whatsapp = this.manager.getSession(chat.session)
|
||||
await whatsapp.startTyping(chat)
|
||||
return {result: true}
|
||||
}
|
||||
@Post('/startTyping')
|
||||
async startTyping(@Body() chat: ChatRequest) {
|
||||
// It's infinitive action
|
||||
const whatsapp = this.manager.getSession(chat.session);
|
||||
await whatsapp.startTyping(chat);
|
||||
return { result: true };
|
||||
}
|
||||
|
||||
@Post('/stopTyping')
|
||||
async stopTyping(@Body() chat: ChatRequest) {
|
||||
const whatsapp = this.manager.getSession(chat.session)
|
||||
await whatsapp.stopTyping(chat)
|
||||
return {result: true}
|
||||
}
|
||||
@Post('/stopTyping')
|
||||
async stopTyping(@Body() chat: ChatRequest) {
|
||||
const whatsapp = this.manager.getSession(chat.session);
|
||||
await whatsapp.stopTyping(chat);
|
||||
return { result: true };
|
||||
}
|
||||
|
||||
@Put('/reaction')
|
||||
@ApiOperation({summary: 'React to a message with an emoji'})
|
||||
setReaction(@Body() request: MessageReactionRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.setReaction(request)
|
||||
}
|
||||
@Put('/reaction')
|
||||
@ApiOperation({ summary: 'React to a message with an emoji' })
|
||||
setReaction(@Body() request: MessageReactionRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.setReaction(request);
|
||||
}
|
||||
|
||||
@Get('/messages')
|
||||
@ApiOperation({summary: 'Get messages in a chat'})
|
||||
getMessages( @Query() query: GetMessageQuery ) {
|
||||
const whatsapp = this.manager.getSession(query.session)
|
||||
return whatsapp.getMessages(query)
|
||||
}
|
||||
@Get('/messages')
|
||||
@ApiOperation({ summary: 'Get messages in a chat' })
|
||||
getMessages(@Query() query: GetMessageQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session);
|
||||
return whatsapp.getMessages(query);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +1,73 @@
|
||||
import {Body, Controller, Get, Post, Query} from '@nestjs/common';
|
||||
import {ApiOperation, ApiSecurity, ApiTags} from "@nestjs/swagger";
|
||||
import {SessionManager} from "../core/abc/manager.abc";
|
||||
import {ContactQuery, ContactRequest} from "../structures/contacts.dto";
|
||||
import {SessionQuery} from "../structures/base.dto";
|
||||
import {CheckNumberStatusQuery} from "../structures/chatting.dto";
|
||||
import {WANumberExistResult} from "../structures/responses.dto";
|
||||
import { Body, Controller, Get, Post, Query } from '@nestjs/common';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import { ContactQuery, ContactRequest } from '../structures/contacts.dto';
|
||||
import { SessionQuery } from '../structures/base.dto';
|
||||
import { CheckNumberStatusQuery } from '../structures/chatting.dto';
|
||||
import { WANumberExistResult } from '../structures/responses.dto';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api/contacts')
|
||||
@ApiTags('contacts')
|
||||
export class ContactsController {
|
||||
constructor(private manager: SessionManager) {
|
||||
}
|
||||
constructor(private manager: SessionManager) {}
|
||||
|
||||
@Get('/')
|
||||
@ApiOperation({summary: 'Get contact basic info. The method always return result, even if the phone number is not registered in WhatsApp. For that - use /check-exists endpoint below.'})
|
||||
get(@Query() query: ContactQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session)
|
||||
return whatsapp.getContact(query)
|
||||
}
|
||||
@Get('/')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Get contact basic info. The method always return result, even if the phone number is not registered in WhatsApp. For that - use /check-exists endpoint below.',
|
||||
})
|
||||
get(@Query() query: ContactQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session);
|
||||
return whatsapp.getContact(query);
|
||||
}
|
||||
|
||||
@Get('/all')
|
||||
@ApiOperation({summary: 'Get all contacts'})
|
||||
getAll(@Query() query: SessionQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session)
|
||||
return whatsapp.getContacts()
|
||||
}
|
||||
@Get('/all')
|
||||
@ApiOperation({ summary: 'Get all contacts' })
|
||||
getAll(@Query() query: SessionQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session);
|
||||
return whatsapp.getContacts();
|
||||
}
|
||||
|
||||
@Get('/check-exists')
|
||||
@ApiOperation({summary: 'Check phone number is registered in WhatsApp.'})
|
||||
async checkExists(@Query() request: CheckNumberStatusQuery): Promise<WANumberExistResult> {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.checkNumberStatus(request)
|
||||
}
|
||||
@Get('/check-exists')
|
||||
@ApiOperation({ summary: 'Check phone number is registered in WhatsApp.' })
|
||||
async checkExists(
|
||||
@Query() request: CheckNumberStatusQuery,
|
||||
): Promise<WANumberExistResult> {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.checkNumberStatus(request);
|
||||
}
|
||||
|
||||
@Get('/about')
|
||||
@ApiOperation({summary: 'Gets the Contact\'s current "about" info. Returns null if you don\'t have permission to read their status.'})
|
||||
getAbout(@Query() query: ContactQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session)
|
||||
return whatsapp.getContactAbout(query)
|
||||
}
|
||||
@Get('/about')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Gets the Contact\'s current "about" info. Returns null if you don\'t have permission to read their status.',
|
||||
})
|
||||
getAbout(@Query() query: ContactQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session);
|
||||
return whatsapp.getContactAbout(query);
|
||||
}
|
||||
|
||||
@Get('/profile-picture')
|
||||
@ApiOperation({summary: 'Returns the contact\'s profile picture URL, if privacy settings allow it.'})
|
||||
getProfilePicture(@Query() query: ContactQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session)
|
||||
return whatsapp.getContactProfilePicture(query)
|
||||
}
|
||||
@Get('/profile-picture')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
"Returns the contact's profile picture URL, if privacy settings allow it.",
|
||||
})
|
||||
getProfilePicture(@Query() query: ContactQuery) {
|
||||
const whatsapp = this.manager.getSession(query.session);
|
||||
return whatsapp.getContactProfilePicture(query);
|
||||
}
|
||||
|
||||
@Post('/block')
|
||||
@ApiOperation({summary:"Block contact"})
|
||||
block(@Body() request: ContactRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.blockContact(request)
|
||||
}
|
||||
@Post('/unblock')
|
||||
@ApiOperation({summary:"Unblock contact"})
|
||||
unblock(@Body() request: ContactRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session)
|
||||
return whatsapp.unblockContact(request)
|
||||
}
|
||||
@Post('/block')
|
||||
@ApiOperation({ summary: 'Block contact' })
|
||||
block(@Body() request: ContactRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.blockContact(request);
|
||||
}
|
||||
@Post('/unblock')
|
||||
@ApiOperation({ summary: 'Unblock contact' })
|
||||
unblock(@Body() request: ContactRequest) {
|
||||
const whatsapp = this.manager.getSession(request.session);
|
||||
return whatsapp.unblockContact(request);
|
||||
}
|
||||
}
|
||||
+35
-35
@@ -1,6 +1,12 @@
|
||||
import {ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus,} from '@nestjs/common';
|
||||
import {Request, Response} from 'express';
|
||||
import {VERSION} from "../version";
|
||||
import {
|
||||
ArgumentsHost,
|
||||
Catch,
|
||||
ExceptionFilter,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
import { Request, Response } from 'express';
|
||||
import { VERSION } from '../version';
|
||||
|
||||
/**
|
||||
* Serializer error to JSON.
|
||||
@@ -8,42 +14,36 @@ import {VERSION} from "../version";
|
||||
* Credits: https://stackoverflow.com/a/72707578/6753144
|
||||
*/
|
||||
export function serializeError(err: unknown) {
|
||||
const properties = Object.getOwnPropertyNames(err)
|
||||
// getOwnPropertyNames does not get 'name', like "ReferenceError"
|
||||
properties.push('name')
|
||||
return JSON.parse(JSON.stringify(err, properties))
|
||||
const properties = Object.getOwnPropertyNames(err);
|
||||
// getOwnPropertyNames does not get 'name', like "ReferenceError"
|
||||
properties.push('name');
|
||||
return JSON.parse(JSON.stringify(err, properties));
|
||||
}
|
||||
|
||||
@Catch()
|
||||
export class AllExceptionsFilter implements ExceptionFilter {
|
||||
catch(exception: HttpException | Error, host: ArgumentsHost): void {
|
||||
|
||||
const ctx = host.switchToHttp();
|
||||
const response = ctx.getResponse<Response>();
|
||||
const request = ctx.getRequest<Request>();
|
||||
|
||||
if (exception instanceof HttpException) {
|
||||
response
|
||||
.status(exception.getStatus())
|
||||
.json(exception.getResponse());
|
||||
return
|
||||
}
|
||||
|
||||
const httpStatus = HttpStatus.INTERNAL_SERVER_ERROR
|
||||
response
|
||||
.status(httpStatus)
|
||||
.json({
|
||||
statusCode: httpStatus,
|
||||
timestamp: new Date().toISOString(),
|
||||
exception: serializeError(exception),
|
||||
request: {
|
||||
path: request.url,
|
||||
method: request.method,
|
||||
body: request.body,
|
||||
query: request.query,
|
||||
},
|
||||
version: VERSION,
|
||||
});
|
||||
catch(exception: HttpException | Error, host: ArgumentsHost): void {
|
||||
const ctx = host.switchToHttp();
|
||||
const response = ctx.getResponse<Response>();
|
||||
const request = ctx.getRequest<Request>();
|
||||
|
||||
if (exception instanceof HttpException) {
|
||||
response.status(exception.getStatus()).json(exception.getResponse());
|
||||
return;
|
||||
}
|
||||
|
||||
const httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
response.status(httpStatus).json({
|
||||
statusCode: httpStatus,
|
||||
timestamp: new Date().toISOString(),
|
||||
exception: serializeError(exception),
|
||||
request: {
|
||||
path: request.url,
|
||||
method: request.method,
|
||||
body: request.body,
|
||||
query: request.query,
|
||||
},
|
||||
version: VERSION,
|
||||
});
|
||||
}
|
||||
}
|
||||
+153
-145
@@ -1,165 +1,173 @@
|
||||
import {Body, Controller, Delete, Get, Param, Post, Put} from '@nestjs/common';
|
||||
import {ApiOperation, ApiSecurity, ApiTags} from "@nestjs/swagger";
|
||||
import {SessionManager} from "../core/abc/manager.abc";
|
||||
import {CreateGroupRequest, DescriptionRequest, ParticipantsRequest, SubjectRequest} from "../structures/groups.dto";
|
||||
import {WhatsappSession} from "../core/abc/session.abc";
|
||||
import {SessionApiParam, SessionParam} from "./helpers";
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Param,
|
||||
Post,
|
||||
Put,
|
||||
} from '@nestjs/common';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import {
|
||||
CreateGroupRequest,
|
||||
DescriptionRequest,
|
||||
ParticipantsRequest,
|
||||
SubjectRequest,
|
||||
} from '../structures/groups.dto';
|
||||
import { WhatsappSession } from '../core/abc/session.abc';
|
||||
import { SessionApiParam, SessionParam } from './helpers';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api/:session/groups')
|
||||
@ApiTags('groups')
|
||||
export class GroupsController {
|
||||
constructor(private manager: SessionManager) {
|
||||
}
|
||||
constructor(private manager: SessionManager) {}
|
||||
|
||||
@Post('')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Create a new group."})
|
||||
createGroup(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Body() request: CreateGroupRequest,
|
||||
) {
|
||||
return session.createGroup(request)
|
||||
}
|
||||
@Post('')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Create a new group.' })
|
||||
createGroup(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Body() request: CreateGroupRequest,
|
||||
) {
|
||||
return session.createGroup(request);
|
||||
}
|
||||
|
||||
@Get('')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Get all groups."})
|
||||
getGroups(
|
||||
@SessionParam session: WhatsappSession,
|
||||
) {
|
||||
return session.getGroups()
|
||||
}
|
||||
@Get('')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Get all groups.' })
|
||||
getGroups(@SessionParam session: WhatsappSession) {
|
||||
return session.getGroups();
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Get the group."})
|
||||
getGroup(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
return session.getGroup(id)
|
||||
}
|
||||
@Get(':id')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Get the group.' })
|
||||
getGroup(@SessionParam session: WhatsappSession, @Param('id') id: string) {
|
||||
return session.getGroup(id);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Delete the group."})
|
||||
deleteGroup(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
return session.deleteGroup(id)
|
||||
}
|
||||
@Delete(':id')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Delete the group.' })
|
||||
deleteGroup(@SessionParam session: WhatsappSession, @Param('id') id: string) {
|
||||
return session.deleteGroup(id);
|
||||
}
|
||||
|
||||
@Post(':id/leave')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Leave the group."})
|
||||
leaveGroup(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
return session.leaveGroup(id)
|
||||
}
|
||||
@Post(':id/leave')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Leave the group.' })
|
||||
leaveGroup(@SessionParam session: WhatsappSession, @Param('id') id: string) {
|
||||
return session.leaveGroup(id);
|
||||
}
|
||||
|
||||
@Put(':id/description')
|
||||
@ApiOperation({
|
||||
summary: "Updates the group description.\n" +
|
||||
"Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.\n"
|
||||
})
|
||||
@SessionApiParam
|
||||
setDescription(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: DescriptionRequest
|
||||
) {
|
||||
return session.setDescription(id, request.description)
|
||||
}
|
||||
@Put(':id/description')
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Updates the group description.\n' +
|
||||
'Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.\n',
|
||||
})
|
||||
@SessionApiParam
|
||||
setDescription(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: DescriptionRequest,
|
||||
) {
|
||||
return session.setDescription(id, request.description);
|
||||
}
|
||||
|
||||
@Put(':id/subject')
|
||||
@SessionApiParam
|
||||
@ApiOperation({
|
||||
summary: "Updates the group subject.\n" +
|
||||
"Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.\n"
|
||||
})
|
||||
setSubject(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: SubjectRequest
|
||||
) {
|
||||
return session.setSubject(id, request.subject)
|
||||
}
|
||||
@Put(':id/subject')
|
||||
@SessionApiParam
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Updates the group subject.\n' +
|
||||
'Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.\n',
|
||||
})
|
||||
setSubject(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: SubjectRequest,
|
||||
) {
|
||||
return session.setSubject(id, request.subject);
|
||||
}
|
||||
|
||||
@Get(':id/invite-code')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Gets the invite code for a specific group."})
|
||||
getInviteCode(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
): Promise<string> {
|
||||
return session.getInviteCode(id)
|
||||
}
|
||||
@Get(':id/invite-code')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Gets the invite code for a specific group.' })
|
||||
getInviteCode(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
): Promise<string> {
|
||||
return session.getInviteCode(id);
|
||||
}
|
||||
|
||||
@Post(':id/invite-code/revoke')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: "Invalidates the current group invite code and generates a new one."})
|
||||
revokeInviteCode(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
): Promise<string> {
|
||||
return session.revokeInviteCode(id)
|
||||
}
|
||||
@Post(':id/invite-code/revoke')
|
||||
@SessionApiParam
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Invalidates the current group invite code and generates a new one.',
|
||||
})
|
||||
revokeInviteCode(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
): Promise<string> {
|
||||
return session.revokeInviteCode(id);
|
||||
}
|
||||
|
||||
@Get(':id/participants/')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: 'Get a list of participants by in the group.'})
|
||||
getParticipants(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
return session.getParticipants(id)
|
||||
}
|
||||
@Get(':id/participants/')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Get a list of participants by in the group.' })
|
||||
getParticipants(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
return session.getParticipants(id);
|
||||
}
|
||||
|
||||
@Post(':id/participants/add')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: 'Adds a list of participants by ID to the group.'})
|
||||
addParticipants(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest
|
||||
) {
|
||||
return session.addParticipants(id, request)
|
||||
}
|
||||
@Post(':id/participants/add')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Adds a list of participants by ID to the group.' })
|
||||
addParticipants(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest,
|
||||
) {
|
||||
return session.addParticipants(id, request);
|
||||
}
|
||||
|
||||
@Post(':id/participants/remove')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: 'Removes a list of participants by ID to the group.'})
|
||||
removeParticipants(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest
|
||||
) {
|
||||
return session.removeParticipants(id, request)
|
||||
}
|
||||
@Post(':id/participants/remove')
|
||||
@SessionApiParam
|
||||
@ApiOperation({
|
||||
summary: 'Removes a list of participants by ID to the group.',
|
||||
})
|
||||
removeParticipants(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest,
|
||||
) {
|
||||
return session.removeParticipants(id, request);
|
||||
}
|
||||
|
||||
@Post(':id/admin/promote')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: 'Promote participants to admin users.'})
|
||||
promoteToAdmin(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest
|
||||
) {
|
||||
return session.promoteParticipantsToAdmin(id, request)
|
||||
}
|
||||
@Post(':id/admin/promote')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Promote participants to admin users.' })
|
||||
promoteToAdmin(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest,
|
||||
) {
|
||||
return session.promoteParticipantsToAdmin(id, request);
|
||||
}
|
||||
|
||||
@Post(':id/admin/demote')
|
||||
@SessionApiParam
|
||||
@ApiOperation({summary: 'Demotes participants by to regular users.'})
|
||||
demoteToAdmin(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest
|
||||
) {
|
||||
return session.demoteParticipantsToUser(id, request)
|
||||
}
|
||||
@Post(':id/admin/demote')
|
||||
@SessionApiParam
|
||||
@ApiOperation({ summary: 'Demotes participants by to regular users.' })
|
||||
demoteToAdmin(
|
||||
@SessionParam session: WhatsappSession,
|
||||
@Param('id') id: string,
|
||||
@Body() request: ParticipantsRequest,
|
||||
) {
|
||||
return session.demoteParticipantsToUser(id, request);
|
||||
}
|
||||
}
|
||||
+14
-15
@@ -1,7 +1,7 @@
|
||||
import {ApiParam} from "@nestjs/swagger";
|
||||
import {Injectable, Param, PipeTransform} from "@nestjs/common";
|
||||
import {SessionManager} from "../core/abc/manager.abc";
|
||||
import {WhatsappSession} from "../core/abc/session.abc";
|
||||
import { ApiParam } from '@nestjs/swagger';
|
||||
import { Injectable, Param, PipeTransform } from '@nestjs/common';
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import { WhatsappSession } from '../core/abc/session.abc';
|
||||
|
||||
/**
|
||||
* Get session name and return Whatsapp session back (if exists)
|
||||
@@ -10,26 +10,25 @@ import {WhatsappSession} from "../core/abc/session.abc";
|
||||
*/
|
||||
@Injectable()
|
||||
export class SessionPipe implements PipeTransform<WhatsappSession> {
|
||||
constructor(private manager: SessionManager) {
|
||||
}
|
||||
constructor(private manager: SessionManager) {}
|
||||
|
||||
async transform(value: any) {
|
||||
return this.manager.getSession(value)
|
||||
}
|
||||
async transform(value: any) {
|
||||
return this.manager.getSession(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorator for a method that uses SessionPipe above
|
||||
*/
|
||||
export const SessionApiParam = ApiParam({
|
||||
name: 'session',
|
||||
required: true,
|
||||
type: "string",
|
||||
description: "WhatsApp session name",
|
||||
})
|
||||
name: 'session',
|
||||
required: true,
|
||||
type: 'string',
|
||||
description: 'WhatsApp session name',
|
||||
});
|
||||
|
||||
/**
|
||||
* Session param
|
||||
@SessionParam session: WhatsappSession,
|
||||
*/
|
||||
export const SessionParam = Param('session', SessionPipe)
|
||||
export const SessionParam = Param('session', SessionPipe);
|
||||
@@ -1,34 +1,28 @@
|
||||
import {Controller, Get, Query, Res} from '@nestjs/common';
|
||||
import {ApiSecurity, ApiTags} from "@nestjs/swagger";
|
||||
import {Readable} from "stream";
|
||||
import {Response} from 'express';
|
||||
import {SessionManager} from "../core/abc/manager.abc";
|
||||
import {SessionQuery} from "../structures/base.dto";
|
||||
|
||||
import { Controller, Get, Query, Res } from '@nestjs/common';
|
||||
import { ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { Readable } from 'stream';
|
||||
import { Response } from 'express';
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import { SessionQuery } from '../structures/base.dto';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api')
|
||||
@ApiTags('screenshot')
|
||||
export class ScreenshotController {
|
||||
constructor(private manager: SessionManager) {
|
||||
}
|
||||
constructor(private manager: SessionManager) {}
|
||||
|
||||
@Get('/screenshot')
|
||||
async screenshot(
|
||||
@Res() res: Response,
|
||||
@Query() sessionQuery: SessionQuery,
|
||||
) {
|
||||
const whatsappService = this.manager.getSession(sessionQuery.session)
|
||||
const buffer = await whatsappService.getScreenshot();
|
||||
const stream = new Readable();
|
||||
stream.push(buffer);
|
||||
stream.push(null);
|
||||
@Get('/screenshot')
|
||||
async screenshot(@Res() res: Response, @Query() sessionQuery: SessionQuery) {
|
||||
const whatsappService = this.manager.getSession(sessionQuery.session);
|
||||
const buffer = await whatsappService.getScreenshot();
|
||||
const stream = new Readable();
|
||||
stream.push(buffer);
|
||||
stream.push(null);
|
||||
|
||||
res.set({
|
||||
'Content-Type': 'image/png',
|
||||
'Content-Length': buffer.length,
|
||||
});
|
||||
stream.pipe(res)
|
||||
}
|
||||
res.set({
|
||||
'Content-Type': 'image/png',
|
||||
'Content-Length': buffer.length,
|
||||
});
|
||||
stream.pipe(res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,52 @@
|
||||
import {Body, Controller, Get, Post} from '@nestjs/common';
|
||||
import {ApiSecurity, ApiTags} from "@nestjs/swagger";
|
||||
import {SessionDTO, SessionStartRequest, SessionStopRequest} from "../structures/sessions.dto";
|
||||
import {SessionManager} from "../core/abc/manager.abc";
|
||||
|
||||
import { Body, Controller, Get, Post, Query } from '@nestjs/common';
|
||||
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import {
|
||||
SessionLogoutRequest,
|
||||
SessionDTO,
|
||||
SessionStartRequest,
|
||||
SessionStopRequest,
|
||||
ListSessionsQuery,
|
||||
} from '../structures/sessions.dto';
|
||||
import { SessionManager } from '../core/abc/manager.abc';
|
||||
import { UnprocessableEntityException } from '@nestjs/common/exceptions/unprocessable-entity.exception';
|
||||
import { parseBool } from '../helpers';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api/sessions')
|
||||
@ApiTags('sessions')
|
||||
export class SessionsController {
|
||||
constructor(private manager: SessionManager) {
|
||||
}
|
||||
constructor(private manager: SessionManager) {}
|
||||
|
||||
@Post('/start/')
|
||||
start(@Body() request: SessionStartRequest): SessionDTO {
|
||||
return this.manager.start(request);
|
||||
}
|
||||
|
||||
@Post('/start/')
|
||||
start(@Body() request: SessionStartRequest): SessionDTO {
|
||||
return this.manager.start(request)
|
||||
@Post('/stop/')
|
||||
@ApiOperation({ summary: 'Stop session' })
|
||||
async stop(@Body() request: SessionStopRequest): Promise<void> {
|
||||
await this.manager.stop(request);
|
||||
if (request.logout) {
|
||||
await this.manager.logout(request);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@Post('/stop/')
|
||||
stop(@Body() request: SessionStopRequest): Promise<void> {
|
||||
return this.manager.stop(request)
|
||||
@Post('/logout/')
|
||||
@ApiOperation({ summary: 'Logout from session.' })
|
||||
clean(@Body() request: SessionLogoutRequest): Promise<void> {
|
||||
const session = this.manager.getSession(request.name, false);
|
||||
if (session) {
|
||||
throw new UnprocessableEntityException(
|
||||
`Can not clean running session, please stop it first. You can set 'clean' field to 'True' in stop request so it stops and cleans at the same time.`,
|
||||
);
|
||||
}
|
||||
return this.manager.logout(request);
|
||||
}
|
||||
|
||||
@Get('/')
|
||||
list(): SessionDTO[] {
|
||||
return this.manager.getSessions()
|
||||
}
|
||||
@Get('/')
|
||||
list(@Query() query: ListSessionsQuery): SessionDTO[] {
|
||||
const all = parseBool(query.all);
|
||||
return this.manager.getSessions(all);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import {Controller, Get} from '@nestjs/common';
|
||||
import {ApiSecurity, ApiTags} from "@nestjs/swagger";
|
||||
import {VERSION} from "../version";
|
||||
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { ApiSecurity, ApiTags } from '@nestjs/swagger';
|
||||
import { VERSION } from '../version';
|
||||
|
||||
@ApiSecurity('api_key')
|
||||
@Controller('api/version')
|
||||
@ApiTags('other')
|
||||
export class VersionController {
|
||||
@Get('')
|
||||
async get() {
|
||||
return VERSION
|
||||
}
|
||||
@Get('')
|
||||
async get() {
|
||||
return VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
+92
-79
@@ -1,90 +1,103 @@
|
||||
import {Injectable} from "@nestjs/common";
|
||||
import {ConfigService} from "@nestjs/config";
|
||||
import {WhatsappEngine} from "./structures/enums.dto";
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { WhatsappEngine } from './structures/enums.dto';
|
||||
import { parseBool } from './helpers';
|
||||
|
||||
@Injectable()
|
||||
export class WhatsappConfigService {
|
||||
public files_uri = '/api/files'
|
||||
public schema = "http"
|
||||
public files_uri = '/api/files';
|
||||
public schema = 'http';
|
||||
|
||||
constructor(private configService: ConfigService) {
|
||||
constructor(private configService: ConfigService) {}
|
||||
|
||||
get filesURL(): string {
|
||||
return `${this.schema}://${this.hostname}:${this.port}${this.files_uri}/`;
|
||||
}
|
||||
|
||||
get hostname(): string {
|
||||
return this.configService.get('WHATSAPP_API_HOSTNAME', 'localhost');
|
||||
}
|
||||
|
||||
get port(): string {
|
||||
return this.configService.get('WHATSAPP_API_PORT', '3000');
|
||||
}
|
||||
|
||||
get filesFolder(): string {
|
||||
return this.configService.get(
|
||||
'WHATSAPP_FILES_FOLDER',
|
||||
'/tmp/whatsapp-files',
|
||||
);
|
||||
}
|
||||
|
||||
get filesLifetime(): number {
|
||||
return this.configService.get<number>('WHATSAPP_FILES_LIFETIME', 180);
|
||||
}
|
||||
|
||||
get mimetypes(): string[] | null {
|
||||
const types = this.configService.get('WHATSAPP_FILES_MIMETYPES', '');
|
||||
return types ? types.split(',') : null;
|
||||
}
|
||||
|
||||
get startSessions(): string[] {
|
||||
const value: string = this.configService.get('WHATSAPP_START_SESSION', '');
|
||||
if (!value) {
|
||||
return [];
|
||||
}
|
||||
return value.split(',');
|
||||
}
|
||||
|
||||
get filesURL(): string {
|
||||
return `${this.schema}://${this.hostname}:${this.port}${this.files_uri}/`
|
||||
get shouldRestartAllSessions(): boolean {
|
||||
const value: string = this.configService.get(
|
||||
'WHATSAPP_RESTART_ALL_SESSIONS',
|
||||
'false',
|
||||
);
|
||||
return parseBool(value);
|
||||
}
|
||||
|
||||
getWebhookUrl(): string | undefined {
|
||||
return this.get('WHATSAPP_HOOK_URL');
|
||||
}
|
||||
|
||||
getWebhookEvents(): string[] {
|
||||
const value = this.get('WHATSAPP_HOOK_EVENTS', '');
|
||||
return value ? value.split(',') : [];
|
||||
}
|
||||
|
||||
getDefaultEngineName(): WhatsappEngine {
|
||||
const value = this.get('WHATSAPP_DEFAULT_ENGINE', WhatsappEngine.WEBJS);
|
||||
if (value in WhatsappEngine) {
|
||||
return WhatsappEngine[value];
|
||||
}
|
||||
console.log(
|
||||
`Unknown WhatsApp default engine, using WEBJS. WHATSAPP_DEFAULT_ENGINE=${value}`,
|
||||
);
|
||||
}
|
||||
|
||||
get hostname(): string {
|
||||
return this.configService.get(
|
||||
'WHATSAPP_API_HOSTNAME',
|
||||
'localhost',
|
||||
)
|
||||
get(name: string, defaultValue = undefined): any {
|
||||
return this.configService.get(name, defaultValue);
|
||||
}
|
||||
|
||||
getApiKey(): string | undefined {
|
||||
return this.configService.get('WHATSAPP_API_KEY', '');
|
||||
}
|
||||
|
||||
getSwaggerUsernamePassword(): [string, string] | undefined {
|
||||
const user = this.configService.get('WHATSAPP_SWAGGER_USERNAME', undefined);
|
||||
const password = this.configService.get(
|
||||
'WHATSAPP_SWAGGER_PASSWORD',
|
||||
undefined,
|
||||
);
|
||||
if (!user && !password) {
|
||||
console.log(
|
||||
'Please set up both WHATSAPP_SWAGGER_USERNAME and WHATSAPP_SWAGGER_PASSWORD ' +
|
||||
'to enable swagger authentication.',
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
return [user, password];
|
||||
}
|
||||
|
||||
get port(): string {
|
||||
return this.configService.get(
|
||||
'WHATSAPP_API_PORT',
|
||||
'3000',
|
||||
)
|
||||
}
|
||||
|
||||
get filesFolder(): string {
|
||||
return this.configService.get(
|
||||
'WHATSAPP_FILES_FOLDER',
|
||||
'/tmp/whatsapp-files',
|
||||
)
|
||||
}
|
||||
|
||||
get filesLifetime(): number {
|
||||
return this.configService.get<number>(
|
||||
'WHATSAPP_FILES_LIFETIME',
|
||||
180,
|
||||
)
|
||||
}
|
||||
|
||||
get mimetypes(): string[] | null {
|
||||
const types = this.configService.get('WHATSAPP_FILES_MIMETYPES', "")
|
||||
return types ? types.split(',') : null
|
||||
}
|
||||
|
||||
get startSession(): string | undefined {
|
||||
return this.configService.get('WHATSAPP_START_SESSION', undefined)
|
||||
}
|
||||
|
||||
getWebhookUrl(): string | undefined {
|
||||
return this.get('WHATSAPP_HOOK_URL')
|
||||
}
|
||||
|
||||
getWebhookEvents(): string[] {
|
||||
const value = this.get('WHATSAPP_HOOK_EVENTS', "")
|
||||
return value ? value.split(',') : []
|
||||
}
|
||||
|
||||
getDefaultEngineName(): WhatsappEngine {
|
||||
const value = this.get("WHATSAPP_DEFAULT_ENGINE", WhatsappEngine.WEBJS)
|
||||
if (value in WhatsappEngine) {
|
||||
return WhatsappEngine[value]
|
||||
}
|
||||
console.log(`Unknown WhatsApp default engine, using WEBJS. WHATSAPP_DEFAULT_ENGINE=${value}`)
|
||||
|
||||
}
|
||||
|
||||
get(name: string, defaultValue = undefined): any {
|
||||
return this.configService.get(name, defaultValue)
|
||||
}
|
||||
|
||||
getApiKey(): string | undefined {
|
||||
return this.configService.get("WHATSAPP_API_KEY", "")
|
||||
}
|
||||
|
||||
getSwaggerUsernamePassword(): [string, string] | undefined {
|
||||
const user = this.configService.get("WHATSAPP_SWAGGER_USERNAME", undefined)
|
||||
const password = this.configService.get("WHATSAPP_SWAGGER_PASSWORD", undefined)
|
||||
if (!user && !password) {
|
||||
console.log("Please set up both WHATSAPP_SWAGGER_USERNAME and WHATSAPP_SWAGGER_PASSWORD " +
|
||||
"to enable swagger authentication.")
|
||||
return undefined
|
||||
}
|
||||
return [user, password]
|
||||
}
|
||||
getSwaggerAdvancedConfigEnabled(): boolean {
|
||||
return this.configService.get('WHATSAPP_SWAGGER_CONFIG_ADVANCED', false);
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -1,11 +1,11 @@
|
||||
export class QR {
|
||||
private base64: string;
|
||||
private base64: string;
|
||||
|
||||
save(base64) {
|
||||
this.base64 = base64.replace(/^data:image\/png;base64,/, '');
|
||||
}
|
||||
save(base64) {
|
||||
this.base64 = base64.replace(/^data:image\/png;base64,/, '');
|
||||
}
|
||||
|
||||
get(): Buffer {
|
||||
return Buffer.from(this.base64, "base64")
|
||||
}
|
||||
get(): Buffer {
|
||||
return Buffer.from(this.base64, 'base64');
|
||||
}
|
||||
}
|
||||
+24
-16
@@ -1,28 +1,36 @@
|
||||
import {OnApplicationShutdown} from "@nestjs/common";
|
||||
import {SessionDTO, SessionStartRequest, SessionStopRequest} from "../../structures/sessions.dto";
|
||||
import {WhatsappSession} from "./session.abc";
|
||||
import {WhatsappEngine} from "../../structures/enums.dto";
|
||||
import {MediaStorage} from "./storage.abc";
|
||||
import {WebhookConductor} from "./webhooks.abc";
|
||||
import { OnApplicationShutdown } from '@nestjs/common';
|
||||
import {
|
||||
SessionLogoutRequest,
|
||||
SessionDTO,
|
||||
SessionStartRequest,
|
||||
SessionStopRequest,
|
||||
} from '../../structures/sessions.dto';
|
||||
import { WhatsappSession } from './session.abc';
|
||||
import { WhatsappEngine } from '../../structures/enums.dto';
|
||||
import { MediaStorage } from './storage.abc';
|
||||
import { WebhookConductor } from './webhooks.abc';
|
||||
|
||||
export abstract class SessionManager implements OnApplicationShutdown {
|
||||
protected abstract getEngine(engine: WhatsappEngine): typeof WhatsappSession;
|
||||
|
||||
abstract start(request: SessionStartRequest): SessionDTO
|
||||
protected abstract get EngineClass(): typeof WhatsappSession;
|
||||
|
||||
abstract stop(request: SessionStopRequest): Promise<void>
|
||||
protected abstract get WebhookConductorClass(): typeof WebhookConductor;
|
||||
|
||||
abstract getSession(name: string): WhatsappSession
|
||||
protected abstract get MediaStorageClass(): typeof MediaStorage;
|
||||
|
||||
abstract getSessions(): SessionDTO[]
|
||||
abstract onApplicationShutdown(signal?: string);
|
||||
|
||||
abstract onApplicationShutdown(signal ?: string)
|
||||
//
|
||||
// API Methods
|
||||
//
|
||||
abstract start(request: SessionStartRequest): SessionDTO;
|
||||
|
||||
protected abstract getEngine(engine: WhatsappEngine): typeof WhatsappSession
|
||||
abstract stop(request: SessionStopRequest): Promise<void>;
|
||||
|
||||
protected abstract get EngineClass(): typeof WhatsappSession
|
||||
abstract logout(request: SessionLogoutRequest): Promise<void>;
|
||||
|
||||
protected abstract get WebhookConductorClass(): typeof WebhookConductor
|
||||
abstract getSession(name: string, error?: boolean): WhatsappSession;
|
||||
|
||||
protected abstract get MediaStorageClass(): typeof MediaStorage
|
||||
abstract getSessions(all: boolean): SessionDTO[];
|
||||
}
|
||||
|
||||
+205
-190
@@ -1,249 +1,264 @@
|
||||
import {WAEvents, WhatsappStatus} from "../../structures/enums.dto";
|
||||
import {ConsoleLogger} from "@nestjs/common";
|
||||
import {
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery, GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest
|
||||
} from "../../structures/chatting.dto";
|
||||
import {MediaStorage} from "./storage.abc";
|
||||
import {MessageId} from "whatsapp-web.js";
|
||||
import {ContactQuery, ContactRequest} from "../../structures/contacts.dto";
|
||||
import {NotImplementedByEngineError} from "../exceptions";
|
||||
import {CreateGroupRequest, ParticipantsRequest} from "../../structures/groups.dto";
|
||||
import * as fs from "fs";
|
||||
|
||||
const CHROME_PATH = "/usr/bin/google-chrome-stable"
|
||||
const CHROMIUM_PATH = "/usr/bin/chromium"
|
||||
import { EventEmitter } from 'events'
|
||||
WAEvents,
|
||||
WhatsappEngine,
|
||||
WhatsappStatus,
|
||||
} from '../../structures/enums.dto';
|
||||
import { ConsoleLogger } from '@nestjs/common';
|
||||
import {
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest,
|
||||
} from '../../structures/chatting.dto';
|
||||
import { LocalSessionStorage, MediaStorage } from './storage.abc';
|
||||
import { MessageId } from 'whatsapp-web.js';
|
||||
import { ContactQuery, ContactRequest } from '../../structures/contacts.dto';
|
||||
import { NotImplementedByEngineError } from '../exceptions';
|
||||
import {
|
||||
CreateGroupRequest,
|
||||
ParticipantsRequest,
|
||||
} from '../../structures/groups.dto';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const CHROME_PATH = '/usr/bin/google-chrome-stable';
|
||||
const CHROMIUM_PATH = '/usr/bin/chromium';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
export function getBrowserExecutablePath() {
|
||||
if (fs.existsSync(CHROME_PATH)) {
|
||||
return CHROME_PATH
|
||||
}
|
||||
return CHROMIUM_PATH
|
||||
if (fs.existsSync(CHROME_PATH)) {
|
||||
return CHROME_PATH;
|
||||
}
|
||||
return CHROMIUM_PATH;
|
||||
}
|
||||
export function ensureSuffix(phone) {
|
||||
const suffix = "@c.us"
|
||||
if (phone.includes("@")) {
|
||||
return phone
|
||||
}
|
||||
return phone + suffix
|
||||
const suffix = '@c.us';
|
||||
if (phone.includes('@')) {
|
||||
return phone;
|
||||
}
|
||||
return phone + suffix;
|
||||
}
|
||||
|
||||
export enum WAHAInternalEvent {
|
||||
engine_start = "engine.start",
|
||||
engine_start = 'engine.start',
|
||||
}
|
||||
|
||||
export interface WhatsAppSessionConfig {
|
||||
name: string;
|
||||
storage: MediaStorage;
|
||||
log: ConsoleLogger;
|
||||
sessionStorage: LocalSessionStorage;
|
||||
}
|
||||
|
||||
export abstract class WhatsappSession {
|
||||
public status: WhatsappStatus;
|
||||
public events: EventEmitter
|
||||
public status: WhatsappStatus;
|
||||
public events: EventEmitter;
|
||||
public engine: WhatsappEngine;
|
||||
|
||||
public constructor(public name: string, protected storage: MediaStorage, protected log: ConsoleLogger) {
|
||||
this.name = name
|
||||
this.status = WhatsappStatus.STARTING
|
||||
this.log = log
|
||||
this.events = new EventEmitter()
|
||||
}
|
||||
public name: string;
|
||||
protected storage: MediaStorage;
|
||||
protected log: ConsoleLogger;
|
||||
protected sessionStorage: LocalSessionStorage;
|
||||
|
||||
getBrowserExecutablePath() {
|
||||
return getBrowserExecutablePath()
|
||||
}
|
||||
public constructor({ name, log, sessionStorage }: WhatsAppSessionConfig) {
|
||||
this.name = name;
|
||||
this.status = WhatsappStatus.STARTING;
|
||||
this.log = log;
|
||||
this.sessionStorage = sessionStorage;
|
||||
this.events = new EventEmitter();
|
||||
}
|
||||
|
||||
getBrowserArgsForPuppeteer() {
|
||||
// Run optimized version of Chrome
|
||||
// References:
|
||||
// https://github.com/pedroslopez/whatsapp-web.js/issues/1420
|
||||
// https://www.bannerbear.com/blog/ways-to-speed-up-puppeteer-screenshots/
|
||||
return [
|
||||
'--no-sandbox',
|
||||
'--disable-client-side-phishing-detection',
|
||||
'--disable-setuid-sandbox',
|
||||
'--disable-component-update',
|
||||
'--disable-default-apps',
|
||||
'--disable-popup-blocking',
|
||||
'--disable-offer-store-unmasked-wallet-cards',
|
||||
'--disable-speech-api',
|
||||
'--hide-scrollbars',
|
||||
'--mute-audio',
|
||||
'--disable-extensions',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-accelerated-2d-canvas',
|
||||
'--no-first-run',
|
||||
'--no-default-browser-check',
|
||||
'--no-pings',
|
||||
'--password-store=basic',
|
||||
'--use-mock-keychain',
|
||||
'--no-zygote',
|
||||
'--single-process',
|
||||
'--disable-gpu'
|
||||
]
|
||||
}
|
||||
getBrowserExecutablePath() {
|
||||
return getBrowserExecutablePath();
|
||||
}
|
||||
|
||||
getBrowserArgsForPuppeteer() {
|
||||
// Run optimized version of Chrome
|
||||
// References:
|
||||
// https://github.com/pedroslopez/whatsapp-web.js/issues/1420
|
||||
// https://www.bannerbear.com/blog/ways-to-speed-up-puppeteer-screenshots/
|
||||
return [
|
||||
'--no-sandbox',
|
||||
'--disable-client-side-phishing-detection',
|
||||
'--disable-setuid-sandbox',
|
||||
'--disable-component-update',
|
||||
'--disable-default-apps',
|
||||
'--disable-popup-blocking',
|
||||
'--disable-offer-store-unmasked-wallet-cards',
|
||||
'--disable-speech-api',
|
||||
'--hide-scrollbars',
|
||||
'--mute-audio',
|
||||
'--disable-extensions',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-accelerated-2d-canvas',
|
||||
'--no-first-run',
|
||||
'--no-default-browser-check',
|
||||
'--no-pings',
|
||||
'--password-store=basic',
|
||||
'--use-mock-keychain',
|
||||
'--no-zygote',
|
||||
'--single-process',
|
||||
'--disable-gpu',
|
||||
];
|
||||
}
|
||||
|
||||
/** Start the session */
|
||||
abstract start()
|
||||
/** Start the session */
|
||||
abstract start();
|
||||
|
||||
/** Stop the session */
|
||||
abstract stop(): void
|
||||
/** Stop the session */
|
||||
abstract stop(): void;
|
||||
|
||||
/** Subscribe the handler to specific hook */
|
||||
abstract subscribe(hook: WAEvents | string, handler: (message) => void)
|
||||
/** Subscribe the handler to specific hook */
|
||||
abstract subscribe(hook: WAEvents | string, handler: (message) => void);
|
||||
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
abstract getScreenshot(): Promise<Buffer | string>
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
abstract getScreenshot(): Promise<Buffer | string>;
|
||||
|
||||
abstract checkNumberStatus(request: CheckNumberStatusQuery)
|
||||
abstract checkNumberStatus(request: CheckNumberStatusQuery);
|
||||
|
||||
abstract sendText(request: MessageTextRequest)
|
||||
abstract sendText(request: MessageTextRequest);
|
||||
|
||||
abstract sendContactVCard(request: MessageContactVcardRequest)
|
||||
abstract sendContactVCard(request: MessageContactVcardRequest);
|
||||
|
||||
abstract sendTextButtons(request: MessageTextButtonsRequest)
|
||||
abstract sendTextButtons(request: MessageTextButtonsRequest);
|
||||
|
||||
abstract sendLocation(request: MessageLocationRequest)
|
||||
abstract sendLocation(request: MessageLocationRequest);
|
||||
|
||||
abstract sendLinkPreview(request: MessageLinkPreviewRequest)
|
||||
abstract sendLinkPreview(request: MessageLinkPreviewRequest);
|
||||
|
||||
abstract sendImage(request: MessageImageRequest)
|
||||
abstract sendImage(request: MessageImageRequest);
|
||||
|
||||
abstract sendFile(request: MessageFileRequest)
|
||||
abstract sendFile(request: MessageFileRequest);
|
||||
|
||||
abstract sendVoice(request: MessageVoiceRequest)
|
||||
abstract sendVoice(request: MessageVoiceRequest);
|
||||
|
||||
abstract reply(request: MessageReplyRequest)
|
||||
abstract reply(request: MessageReplyRequest);
|
||||
|
||||
abstract sendSeen(chat: ChatRequest)
|
||||
abstract sendSeen(chat: ChatRequest);
|
||||
|
||||
abstract startTyping(chat: ChatRequest)
|
||||
abstract startTyping(chat: ChatRequest);
|
||||
|
||||
abstract stopTyping(chat: ChatRequest)
|
||||
abstract stopTyping(chat: ChatRequest);
|
||||
|
||||
abstract getMessages(query: GetMessageQuery)
|
||||
abstract getMessages(query: GetMessageQuery);
|
||||
|
||||
abstract setReaction(request: MessageReactionRequest)
|
||||
abstract setReaction(request: MessageReactionRequest);
|
||||
|
||||
/**
|
||||
* Contacts methods
|
||||
*/
|
||||
public getContact(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Contacts methods
|
||||
*/
|
||||
public getContact(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public getContacts() {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getContacts() {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public getContactAbout(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getContactAbout(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public getContactProfilePicture(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getContactProfilePicture(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public blockContact(request: ContactRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public blockContact(request: ContactRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public unblockContact(request: ContactRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public unblockContact(request: ContactRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
/**
|
||||
* Group methods
|
||||
*/
|
||||
public createGroup(request: CreateGroupRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Group methods
|
||||
*/
|
||||
public createGroup(request: CreateGroupRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public getGroups() {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getGroups() {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public getGroup(id) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getGroup(id) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public deleteGroup(id) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public deleteGroup(id) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public leaveGroup(id) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public leaveGroup(id) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public setDescription(id, description) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public setDescription(id, description) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public setSubject(id, description) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public setSubject(id, description) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public getInviteCode(id): Promise<string> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getInviteCode(id): Promise<string> {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public revokeInviteCode(id): Promise<string> {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public revokeInviteCode(id): Promise<string> {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public getParticipants(id) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public getParticipants(id) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public addParticipants(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public addParticipants(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public removeParticipants(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public removeParticipants(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public promoteParticipantsToAdmin(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public promoteParticipantsToAdmin(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
public demoteParticipantsToUser(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public demoteParticipantsToUser(id, request: ParticipantsRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add WhatsApp suffix (@c.us) to the phone number if it doesn't have it yet
|
||||
* @param phone
|
||||
*/
|
||||
protected ensureSuffix(phone) {
|
||||
return ensureSuffix(phone);
|
||||
}
|
||||
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add WhatsApp suffix (@c.us) to the phone number if it doesn't have it yet
|
||||
* @param phone
|
||||
*/
|
||||
protected ensureSuffix(phone) {
|
||||
return ensureSuffix(phone)
|
||||
}
|
||||
|
||||
protected deserializeId(messageId: string): MessageId {
|
||||
const parts = messageId.split("_")
|
||||
return {
|
||||
"fromMe": parts[0] === "true",
|
||||
"remote": parts[1],
|
||||
"id": parts[2],
|
||||
"_serialized": messageId
|
||||
}
|
||||
}
|
||||
|
||||
protected deserializeId(messageId: string): MessageId {
|
||||
const parts = messageId.split('_');
|
||||
return {
|
||||
fromMe: parts[0] === 'true',
|
||||
remote: parts[1],
|
||||
id: parts[2],
|
||||
_serialized: messageId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
export abstract class MediaStorage {
|
||||
abstract save(messageId: string, mimetype: string, buffer: Buffer): Promise<string>
|
||||
abstract save(
|
||||
messageId: string,
|
||||
mimetype: string,
|
||||
buffer: Buffer,
|
||||
): Promise<string>;
|
||||
}
|
||||
|
||||
export abstract class LocalSessionStorage {
|
||||
public sessionsFolder: string;
|
||||
|
||||
protected constructor(public engine: string) {
|
||||
this.engine = engine;
|
||||
}
|
||||
|
||||
abstract init();
|
||||
|
||||
abstract getFolderPath(sessionName: string): string;
|
||||
|
||||
abstract clean(sessionName: string);
|
||||
|
||||
abstract getAll(): string[];
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import {WhatsappSession} from "./session.abc";
|
||||
import { WhatsappSession } from './session.abc';
|
||||
|
||||
export abstract class WebhookConductor {
|
||||
abstract configure(session: WhatsappSession)
|
||||
abstract configure(session: WhatsappSession);
|
||||
}
|
||||
+49
-50
@@ -1,57 +1,56 @@
|
||||
import {ConsoleLogger, Module} from '@nestjs/common';
|
||||
import {ScreenshotController} from "../api/screenshot.controller";
|
||||
import {ConfigModule} from "@nestjs/config";
|
||||
import {WhatsappConfigService} from "../config.service";
|
||||
import {ServeStaticModule} from "@nestjs/serve-static";
|
||||
import {SessionsController} from "../api/sessions.controller";
|
||||
import {ChattingController} from "../api/chatting.controller";
|
||||
import {ContactsController} from "../api/contacts.controller";
|
||||
import {VersionController} from "../api/version.controller";
|
||||
import {PassportModule} from "@nestjs/passport";
|
||||
import {SessionManager} from "./abc/manager.abc";
|
||||
import {SessionManagerCore} from "./manager.core";
|
||||
import {GroupsController} from "../api/groups.controller";
|
||||
import { ConsoleLogger, Module } from '@nestjs/common';
|
||||
import { ScreenshotController } from '../api/screenshot.controller';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { WhatsappConfigService } from '../config.service';
|
||||
import { ServeStaticModule } from '@nestjs/serve-static';
|
||||
import { SessionsController } from '../api/sessions.controller';
|
||||
import { ChattingController } from '../api/chatting.controller';
|
||||
import { ContactsController } from '../api/contacts.controller';
|
||||
import { VersionController } from '../api/version.controller';
|
||||
import { PassportModule } from '@nestjs/passport';
|
||||
import { SessionManager } from './abc/manager.abc';
|
||||
import { SessionManagerCore } from './manager.core';
|
||||
import { GroupsController } from '../api/groups.controller';
|
||||
|
||||
export const IMPORTS = [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
}),
|
||||
ServeStaticModule.forRootAsync({
|
||||
imports: [],
|
||||
extraProviders: [WhatsappConfigService],
|
||||
inject: [WhatsappConfigService],
|
||||
useFactory: (config: WhatsappConfigService) => {
|
||||
return [{
|
||||
rootPath: config.filesFolder,
|
||||
serveRoot: config.files_uri,
|
||||
}]
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
}),
|
||||
ServeStaticModule.forRootAsync({
|
||||
imports: [],
|
||||
extraProviders: [WhatsappConfigService],
|
||||
inject: [WhatsappConfigService],
|
||||
useFactory: (config: WhatsappConfigService) => {
|
||||
return [
|
||||
{
|
||||
rootPath: config.filesFolder,
|
||||
serveRoot: config.files_uri,
|
||||
},
|
||||
}),
|
||||
PassportModule,
|
||||
]
|
||||
export const CONTROLLERS = [
|
||||
SessionsController,
|
||||
ChattingController,
|
||||
ContactsController,
|
||||
GroupsController,
|
||||
ScreenshotController,
|
||||
VersionController,
|
||||
]
|
||||
const PROVIDERS = [
|
||||
{
|
||||
provide: SessionManager,
|
||||
useClass: SessionManagerCore,
|
||||
];
|
||||
},
|
||||
WhatsappConfigService,
|
||||
ConsoleLogger,
|
||||
]
|
||||
|
||||
}),
|
||||
PassportModule,
|
||||
];
|
||||
export const CONTROLLERS = [
|
||||
SessionsController,
|
||||
ChattingController,
|
||||
ContactsController,
|
||||
GroupsController,
|
||||
ScreenshotController,
|
||||
VersionController,
|
||||
];
|
||||
const PROVIDERS = [
|
||||
{
|
||||
provide: SessionManager,
|
||||
useClass: SessionManagerCore,
|
||||
},
|
||||
WhatsappConfigService,
|
||||
ConsoleLogger,
|
||||
];
|
||||
|
||||
@Module({
|
||||
imports: IMPORTS,
|
||||
controllers: CONTROLLERS,
|
||||
providers: PROVIDERS,
|
||||
imports: IMPORTS,
|
||||
controllers: CONTROLLERS,
|
||||
providers: PROVIDERS,
|
||||
})
|
||||
export class AppModuleCore {
|
||||
|
||||
}
|
||||
export class AppModuleCore {}
|
||||
+13
-12
@@ -1,20 +1,21 @@
|
||||
import {UnprocessableEntityException} from "@nestjs/common";
|
||||
import { UnprocessableEntityException } from '@nestjs/common';
|
||||
|
||||
export const DOCS_URL = "https://waha.devlike.pro/"
|
||||
export const DOCS_URL = 'https://waha.devlike.pro/';
|
||||
|
||||
export class NotImplementedByEngineError extends UnprocessableEntityException {
|
||||
constructor(msg = "") {
|
||||
let error = "The method is not implemented by the engine."
|
||||
if (msg) {
|
||||
error += ` ${msg}`
|
||||
}
|
||||
super(error);
|
||||
constructor(msg = '') {
|
||||
let error = 'The method is not implemented by the engine.';
|
||||
if (msg) {
|
||||
error += ` ${msg}`;
|
||||
}
|
||||
super(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class AvailableInPlusVersion extends UnprocessableEntityException {
|
||||
constructor() {
|
||||
super(`The feature is available only in Plus version. Check this out: ${DOCS_URL}`);
|
||||
}
|
||||
constructor() {
|
||||
super(
|
||||
`The feature is available only in Plus version. Check this out: ${DOCS_URL}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
+152
-104
@@ -1,120 +1,168 @@
|
||||
import {ConsoleLogger, Injectable, NotFoundException, UnprocessableEntityException} from "@nestjs/common";
|
||||
import {SessionManager} from "./abc/manager.abc";
|
||||
import {WAHAInternalEvent, WhatsappSession} from "./abc/session.abc";
|
||||
import {WhatsappEngine} from "../structures/enums.dto";
|
||||
import {SessionDTO, SessionStartRequest, SessionStopRequest} from "../structures/sessions.dto";
|
||||
import {WhatsappConfigService} from "../config.service";
|
||||
import {WhatsappSessionVenomCore} from "./session.venom.core";
|
||||
import {WhatsappSessionWebJSCore} from "./session.webjs.core";
|
||||
import {DOCS_URL} from "./exceptions";
|
||||
import {WebhookConductorCore} from "./webhooks.core";
|
||||
import {MediaStorageCore} from "./storage.core";
|
||||
import {WhatsappSessionNoWebCore} from "./session.noweb.core";
|
||||
import {
|
||||
ConsoleLogger,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
UnprocessableEntityException,
|
||||
} from '@nestjs/common';
|
||||
import { SessionManager } from './abc/manager.abc';
|
||||
import {
|
||||
WAHAInternalEvent,
|
||||
WhatsappSession,
|
||||
WhatsAppSessionConfig,
|
||||
} from './abc/session.abc';
|
||||
import { WhatsappEngine, WhatsappStatus } from '../structures/enums.dto';
|
||||
import {
|
||||
SessionLogoutRequest,
|
||||
SessionDTO,
|
||||
SessionStartRequest,
|
||||
SessionStopRequest,
|
||||
} from '../structures/sessions.dto';
|
||||
import { WhatsappConfigService } from '../config.service';
|
||||
import { WhatsappSessionVenomCore } from './session.venom.core';
|
||||
import { WhatsappSessionWebJSCore } from './session.webjs.core';
|
||||
import { DOCS_URL } from './exceptions';
|
||||
import { WebhookConductorCore } from './webhooks.core';
|
||||
import { MediaStorageCore, SessionStorageCore } from './storage.core';
|
||||
import { WhatsappSessionNoWebCore } from './session.noweb.core';
|
||||
import { LocalSessionStorage } from './abc/storage.abc';
|
||||
|
||||
export class OnlyDefaultSessionIsAllowed extends UnprocessableEntityException {
|
||||
constructor() {
|
||||
super(`WAHA Core support only 'default' session. If you want to run more then one WhatsApp account - please get WAHA PLUS version. Check this out: ${DOCS_URL}`);
|
||||
}
|
||||
constructor() {
|
||||
super(
|
||||
`WAHA Core support only 'default' session. If you want to run more then one WhatsApp account - please get WAHA PLUS version. Check this out: ${DOCS_URL}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SessionManagerCore extends SessionManager {
|
||||
private session: WhatsappSession;
|
||||
DEFAULT = "default"
|
||||
private session: WhatsappSession;
|
||||
DEFAULT = 'default';
|
||||
|
||||
// @ts-ignore
|
||||
protected MediaStorageClass = MediaStorageCore;
|
||||
// @ts-ignore
|
||||
protected WebhookConductorClass = WebhookConductorCore;
|
||||
protected readonly EngineClass: typeof WhatsappSession;
|
||||
protected sessionStorage: LocalSessionStorage;
|
||||
|
||||
constructor(
|
||||
private config: WhatsappConfigService,
|
||||
private log: ConsoleLogger,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.log.setContext('SessionManager');
|
||||
this.session = undefined;
|
||||
const engineName = this.config.getDefaultEngineName();
|
||||
this.EngineClass = this.getEngine(engineName);
|
||||
this.sessionStorage = new SessionStorageCore(engineName.toLowerCase());
|
||||
this.sessionStorage.init();
|
||||
|
||||
this.startPredefinedSessions();
|
||||
}
|
||||
|
||||
protected startPredefinedSessions() {
|
||||
const startSessions = this.config.startSessions;
|
||||
startSessions.forEach((sessionName) => {
|
||||
this.start({ name: sessionName });
|
||||
});
|
||||
}
|
||||
|
||||
protected getEngine(engine: WhatsappEngine): typeof WhatsappSession {
|
||||
if (engine === WhatsappEngine.WEBJS) {
|
||||
return WhatsappSessionWebJSCore;
|
||||
} else if (engine === WhatsappEngine.VENOM) {
|
||||
return WhatsappSessionVenomCore;
|
||||
} else if (engine === WhatsappEngine.NOWEB) {
|
||||
return WhatsappSessionNoWebCore;
|
||||
} else {
|
||||
throw new NotFoundException(`Unknown whatsapp engine '${engine}'.`);
|
||||
}
|
||||
}
|
||||
|
||||
private onlyDefault(name: string) {
|
||||
if (name !== this.DEFAULT) {
|
||||
throw new OnlyDefaultSessionIsAllowed();
|
||||
}
|
||||
}
|
||||
|
||||
async onApplicationShutdown(signal?: string) {
|
||||
if (!this.session) {
|
||||
return;
|
||||
}
|
||||
await this.stop({ name: this.DEFAULT, logout: false });
|
||||
}
|
||||
|
||||
//
|
||||
// API Methods
|
||||
//
|
||||
start(request: SessionStartRequest): SessionDTO {
|
||||
this.onlyDefault(request.name);
|
||||
|
||||
const name = request.name;
|
||||
this.log.log(`'${name}' - starting session...`);
|
||||
const log = new ConsoleLogger(`WhatsappSession - ${name}`);
|
||||
const storage = new this.MediaStorageClass();
|
||||
const webhookLog = new ConsoleLogger(`Webhook - ${name}`);
|
||||
const webhook = new this.WebhookConductorClass(
|
||||
webhookLog,
|
||||
this.config.getWebhookUrl(),
|
||||
this.config.getWebhookEvents(),
|
||||
);
|
||||
|
||||
const sessionConfig: WhatsAppSessionConfig = {
|
||||
name,
|
||||
storage,
|
||||
log,
|
||||
sessionStorage: this.sessionStorage,
|
||||
};
|
||||
// @ts-ignore
|
||||
protected MediaStorageClass = MediaStorageCore
|
||||
// @ts-ignore
|
||||
protected WebhookConductorClass = WebhookConductorCore
|
||||
protected readonly EngineClass: typeof WhatsappSession;
|
||||
const session = new this.EngineClass(sessionConfig);
|
||||
this.session = session;
|
||||
|
||||
session.events.on(WAHAInternalEvent.engine_start, () =>
|
||||
webhook.configure(session),
|
||||
);
|
||||
session.start();
|
||||
return { name: session.name, status: session.status };
|
||||
}
|
||||
|
||||
constructor(
|
||||
private config: WhatsappConfigService,
|
||||
private log: ConsoleLogger,
|
||||
) {
|
||||
super()
|
||||
async stop(request: SessionStopRequest): Promise<void> {
|
||||
this.onlyDefault(request.name);
|
||||
|
||||
this.log.setContext('SessionManager')
|
||||
this.session = undefined
|
||||
this.EngineClass = this.getEngine(this.config.getDefaultEngineName())
|
||||
const name = request.name;
|
||||
this.log.log(`Stopping ${name} session...`);
|
||||
const session = this.getSession(name);
|
||||
await session.stop();
|
||||
this.log.log(`"${name}" has been stopped.`);
|
||||
this.session = undefined;
|
||||
}
|
||||
|
||||
// Start session from the start
|
||||
if (config.startSession) {
|
||||
this.start({name: config.startSession})
|
||||
}
|
||||
async logout(request: SessionLogoutRequest) {
|
||||
this.sessionStorage.clean(request.name);
|
||||
}
|
||||
|
||||
getSession(name: string, error = true): WhatsappSession {
|
||||
this.onlyDefault(name);
|
||||
const session = this.session;
|
||||
if (!session) {
|
||||
if (error) {
|
||||
throw new NotFoundException(
|
||||
`We didn't find a session with name '${name}'. Please start it first by using POST /sessions/start request`,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
protected getEngine(engine: WhatsappEngine): typeof WhatsappSession {
|
||||
if (engine === WhatsappEngine.WEBJS) {
|
||||
return WhatsappSessionWebJSCore
|
||||
} else if (engine === WhatsappEngine.VENOM) {
|
||||
return WhatsappSessionVenomCore
|
||||
} else if (engine === WhatsappEngine.NOWEB) {
|
||||
return WhatsappSessionNoWebCore
|
||||
} else {
|
||||
throw new NotFoundException(`Unknown whatsapp engine '${engine}'.`)
|
||||
}
|
||||
|
||||
getSessions(all: boolean): SessionDTO[] {
|
||||
if (!this.session) {
|
||||
return all
|
||||
? [{ name: this.DEFAULT, status: WhatsappStatus.STOPPED }]
|
||||
: [];
|
||||
}
|
||||
|
||||
private onlyDefault(name: string) {
|
||||
if (name !== this.DEFAULT) {
|
||||
throw new OnlyDefaultSessionIsAllowed()
|
||||
}
|
||||
}
|
||||
|
||||
getSession(name: string): WhatsappSession {
|
||||
this.onlyDefault(name)
|
||||
if (!this.session) {
|
||||
throw new NotFoundException(
|
||||
`We didn't find a session with name '${name}'. Please start it first by using POST /sessions/start request`,
|
||||
);
|
||||
}
|
||||
return this.session
|
||||
}
|
||||
|
||||
getSessions(): SessionDTO[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
async onApplicationShutdown(signal?: string) {
|
||||
if (!this.session){
|
||||
return
|
||||
}
|
||||
await this.stop({name: this.DEFAULT})
|
||||
}
|
||||
|
||||
start(request: SessionStartRequest): SessionDTO {
|
||||
this.onlyDefault(request.name)
|
||||
|
||||
const name = request.name
|
||||
this.log.log(`'${name}' - starting session...`)
|
||||
const log = new ConsoleLogger(`WhatsappSession - ${name}`)
|
||||
const storage = new this.MediaStorageClass()
|
||||
const webhookLog = new ConsoleLogger(`Webhook - ${name}`)
|
||||
const webhook = new this.WebhookConductorClass(
|
||||
webhookLog,
|
||||
this.config.getWebhookUrl(),
|
||||
this.config.getWebhookEvents()
|
||||
)
|
||||
|
||||
// @ts-ignore
|
||||
const session = new this.EngineClass(name, storage, log)
|
||||
this.session = session
|
||||
|
||||
session.events.on(WAHAInternalEvent.engine_start, () => webhook.configure(session))
|
||||
session.start()
|
||||
return {name: session.name, status: session.status}
|
||||
}
|
||||
|
||||
async stop(request: SessionStopRequest): Promise<void> {
|
||||
const name = request.name
|
||||
this.log.log(`Stopping ${name} session...`)
|
||||
const session = this.getSession(name)
|
||||
await session.stop()
|
||||
this.log.log(`"${name}" has been stopped.`)
|
||||
this.session = undefined
|
||||
}
|
||||
|
||||
return [{ name: this.session.name, status: this.session.status }];
|
||||
}
|
||||
}
|
||||
+470
-426
@@ -1,432 +1,475 @@
|
||||
import {SECOND, WAEvents, WhatsappStatus} from "../structures/enums.dto";
|
||||
import makeWASocket, {DisconnectReason, makeInMemoryStore, isJidGroup, useMultiFileAuthState} from '@adiwajshing/baileys'
|
||||
|
||||
import {ensureSuffix, WAHAInternalEvent, WhatsappSession} from "./abc/session.abc";
|
||||
import {WAMessage, WANumberExistResult} from "../structures/responses.dto";
|
||||
import {
|
||||
Button,
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest,
|
||||
SendSeenRequest
|
||||
} from "../structures/chatting.dto";
|
||||
import {AvailableInPlusVersion, NotImplementedByEngineError} from "./exceptions";
|
||||
import {ContactQuery, ContactRequest} from "../structures/contacts.dto";
|
||||
import {CreateGroupRequest, ParticipantsRequest} from "../structures/groups.dto";
|
||||
import {QR} from "./QR";
|
||||
import {MediaStorage} from "./abc/storage.abc";
|
||||
import {ConsoleLogger, UnprocessableEntityException} from "@nestjs/common";
|
||||
import {Message} from "whatsapp-web.js";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as os from "os";
|
||||
SECOND,
|
||||
WAEvents,
|
||||
WhatsappEngine,
|
||||
WhatsappStatus,
|
||||
} from '../structures/enums.dto';
|
||||
import makeWASocket, {
|
||||
DisconnectReason,
|
||||
isJidGroup,
|
||||
makeInMemoryStore,
|
||||
useMultiFileAuthState,
|
||||
} from '@adiwajshing/baileys';
|
||||
|
||||
import {
|
||||
ensureSuffix,
|
||||
WAHAInternalEvent,
|
||||
WhatsappSession,
|
||||
} from './abc/session.abc';
|
||||
import { WAMessage, WANumberExistResult } from '../structures/responses.dto';
|
||||
import {
|
||||
Button,
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest,
|
||||
SendSeenRequest,
|
||||
} from '../structures/chatting.dto';
|
||||
import {
|
||||
AvailableInPlusVersion,
|
||||
NotImplementedByEngineError,
|
||||
} from './exceptions';
|
||||
import { ContactQuery, ContactRequest } from '../structures/contacts.dto';
|
||||
import {
|
||||
CreateGroupRequest,
|
||||
ParticipantsRequest,
|
||||
} from '../structures/groups.dto';
|
||||
import { QR } from './QR';
|
||||
import { MediaStorage } from './abc/storage.abc';
|
||||
import { ConsoleLogger, UnprocessableEntityException } from '@nestjs/common';
|
||||
import { Message } from 'whatsapp-web.js';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const QRCode = require('qrcode')
|
||||
const QRCode = require('qrcode');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const logger = require('pino')()
|
||||
|
||||
const logger = require('pino')();
|
||||
|
||||
export const BaileysEvents = {
|
||||
CONNECTION_UPDATE: "connection.update",
|
||||
CREDS_UPDATE: "creds.update",
|
||||
MESSAGES_UPSERT: "messages.upsert",
|
||||
GROUPS_UPSERT: 'groups.upsert',
|
||||
}
|
||||
CONNECTION_UPDATE: 'connection.update',
|
||||
CREDS_UPDATE: 'creds.update',
|
||||
MESSAGES_UPSERT: 'messages.upsert',
|
||||
GROUPS_UPSERT: 'groups.upsert',
|
||||
};
|
||||
|
||||
export class WhatsappSessionNoWebCore extends WhatsappSession {
|
||||
sock: any
|
||||
store: any
|
||||
private qr: QR
|
||||
authFolder: string
|
||||
engine = WhatsappEngine.NOWEB;
|
||||
|
||||
public constructor(public name: string, protected storage: MediaStorage, protected log: ConsoleLogger) {
|
||||
super(name, storage, log);
|
||||
this.qr = new QR()
|
||||
this.authFolder = this.getAuthFolder()
|
||||
}
|
||||
sock: any;
|
||||
store: any;
|
||||
private qr: QR;
|
||||
authFolder: string;
|
||||
|
||||
start() {
|
||||
return this.buildClient()
|
||||
}
|
||||
public constructor(config) {
|
||||
super(config);
|
||||
this.qr = new QR();
|
||||
this.authFolder = this.getAuthFolder();
|
||||
}
|
||||
|
||||
protected getAuthFolder() {
|
||||
return fs.mkdtempSync(path.join(os.tmpdir(), 'noweb-'))
|
||||
}
|
||||
start() {
|
||||
return this.buildClient();
|
||||
}
|
||||
|
||||
async makeSocket() {
|
||||
const {state, saveCreds} = await useMultiFileAuthState(this.authFolder)
|
||||
const sock: any = makeWASocket({
|
||||
auth: state,
|
||||
printQRInTerminal: true,
|
||||
browser: ['Linux', 'Chrome', '111.0.5563.64'],
|
||||
logger: logger,
|
||||
})
|
||||
sock.ev.on(BaileysEvents.CREDS_UPDATE, saveCreds)
|
||||
return sock
|
||||
protected getAuthFolder() {
|
||||
const folder = this.sessionStorage.getFolderPath(this.name);
|
||||
return fs.mkdtempSync(folder);
|
||||
}
|
||||
|
||||
async makeSocket() {
|
||||
const { state, saveCreds } = await useMultiFileAuthState(this.authFolder);
|
||||
const sock: any = makeWASocket({
|
||||
auth: state,
|
||||
printQRInTerminal: true,
|
||||
browser: ['Linux', 'Chrome', '111.0.5563.64'],
|
||||
logger: logger,
|
||||
});
|
||||
sock.ev.on(BaileysEvents.CREDS_UPDATE, saveCreds);
|
||||
return sock;
|
||||
}
|
||||
|
||||
connectStore() {
|
||||
if (!this.store) {
|
||||
this.store = makeInMemoryStore({});
|
||||
}
|
||||
connectStore(){
|
||||
if (!this.store){
|
||||
this.store = makeInMemoryStore({ })
|
||||
this.store.bind(this.sock.ev);
|
||||
}
|
||||
|
||||
async buildClient() {
|
||||
this.sock = await this.makeSocket();
|
||||
this.connectStore();
|
||||
this.sock.ev.on(BaileysEvents.CONNECTION_UPDATE, async (update) => {
|
||||
const { connection, lastDisconnect, qr } = update;
|
||||
if (connection === 'connecting') {
|
||||
this.qr.save('');
|
||||
this.status = WhatsappStatus.WORKING;
|
||||
return;
|
||||
} else if (connection === 'close') {
|
||||
const shouldReconnect =
|
||||
lastDisconnect.error?.output?.statusCode !==
|
||||
DisconnectReason.loggedOut;
|
||||
this.log.error(
|
||||
'connection closed due to ',
|
||||
lastDisconnect.error,
|
||||
', reconnecting ',
|
||||
shouldReconnect,
|
||||
);
|
||||
this.qr.save('');
|
||||
this.status = WhatsappStatus.FAILED;
|
||||
// reconnect if not logged out
|
||||
if (shouldReconnect) {
|
||||
setTimeout(() => this.buildClient(), 2 * SECOND);
|
||||
}
|
||||
this.store.bind(this.sock.ev)
|
||||
}
|
||||
|
||||
async buildClient() {
|
||||
this.sock = await this.makeSocket()
|
||||
this.connectStore()
|
||||
this.sock.ev.on(BaileysEvents.CONNECTION_UPDATE, async (update) => {
|
||||
const {connection, lastDisconnect, qr} = update
|
||||
if (connection === 'connecting') {
|
||||
this.qr.save("")
|
||||
this.status = WhatsappStatus.WORKING
|
||||
return
|
||||
} else if (connection === 'close') {
|
||||
const shouldReconnect = (lastDisconnect.error)?.output?.statusCode !== DisconnectReason.loggedOut
|
||||
this.log.error('connection closed due to ', lastDisconnect.error, ', reconnecting ', shouldReconnect)
|
||||
this.qr.save("")
|
||||
this.status = WhatsappStatus.FAILED
|
||||
// reconnect if not logged out
|
||||
if (shouldReconnect) {
|
||||
setTimeout(() => this.buildClient(), 2 * SECOND)
|
||||
}
|
||||
}
|
||||
|
||||
// Save QR
|
||||
if (qr) {
|
||||
this.status = WhatsappStatus.SCAN_QR_CODE
|
||||
QRCode.toDataURL(qr).then((url) => {
|
||||
this.qr.save(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
this.events.emit(WAHAInternalEvent.engine_start)
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.sock.ws.removeAllListeners()
|
||||
this.log.log('socket connection terminated')
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
async getScreenshot(): Promise<Buffer | string> {
|
||||
if (this.status === WhatsappStatus.STARTING) {
|
||||
throw new UnprocessableEntityException(`The session is starting, please try again after few seconds`);
|
||||
} else if (this.status === WhatsappStatus.SCAN_QR_CODE) {
|
||||
return Promise.resolve(this.qr.get())
|
||||
} else if (this.status === WhatsappStatus.WORKING) {
|
||||
throw new UnprocessableEntityException(`Can not get screenshot for non chrome based engine.`);
|
||||
} else {
|
||||
throw new UnprocessableEntityException(`Unknown status - ${this.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
async checkNumberStatus(request: CheckNumberStatusQuery): Promise<WANumberExistResult> {
|
||||
const phone = request.phone.split("@")[0]
|
||||
const [result] = await this.sock.onWhatsApp(phone)
|
||||
if (!result) {
|
||||
return {numberExists: false}
|
||||
}
|
||||
return {numberExists: result.exists}
|
||||
}
|
||||
|
||||
sendText(request: MessageTextRequest) {
|
||||
const chatId = this.ensureSuffix(request.chatId)
|
||||
return this.sock.sendMessage(chatId, {text: request.text})
|
||||
}
|
||||
|
||||
sendTextButtons(request: MessageTextButtonsRequest) {
|
||||
const buttons = request.buttons.map((button: Button) => {
|
||||
return {
|
||||
buttonId: button.id, buttonText: {displayText: button.text}, type: 1
|
||||
}
|
||||
})
|
||||
|
||||
const buttonMessage = {
|
||||
text: request.title,
|
||||
buttons: buttons,
|
||||
headerType: 1
|
||||
}
|
||||
|
||||
return this.sock.sendMessage(request.chatId, buttonMessage)
|
||||
}
|
||||
|
||||
sendContactVCard(request: MessageContactVcardRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
async reply(request: MessageReplyRequest) {
|
||||
const {id} = parseMessageId(request.reply_to)
|
||||
const message = await this.store.loadMessage(toJID(request.chatId), id)
|
||||
return await this.sock.sendMessage(request.chatId, {text: request.text}, {quoted: message})
|
||||
}
|
||||
|
||||
sendImage(request: MessageImageRequest) {
|
||||
throw new AvailableInPlusVersion()
|
||||
}
|
||||
|
||||
sendFile(request: MessageFileRequest) {
|
||||
throw new AvailableInPlusVersion()
|
||||
}
|
||||
|
||||
sendVoice(request: MessageVoiceRequest) {
|
||||
throw new AvailableInPlusVersion()
|
||||
}
|
||||
|
||||
sendLocation(request: MessageLocationRequest) {
|
||||
return this.sock.sendMessage(
|
||||
request.chatId,
|
||||
{location: {degreesLatitude: request.latitude, degreesLongitude: request.longitude}}
|
||||
)
|
||||
}
|
||||
|
||||
sendLinkPreview(request: MessageLinkPreviewRequest) {
|
||||
const text = `${request.title}\n${request.url}`
|
||||
const chatId = this.ensureSuffix(request.chatId)
|
||||
return this.sock.sendMessage(chatId, {text: text})
|
||||
}
|
||||
|
||||
|
||||
async sendSeen(request: SendSeenRequest) {
|
||||
const key = parseMessageId(request.messageId)
|
||||
const data = {
|
||||
remoteJid: key.remoteJid,
|
||||
id: key.id,
|
||||
participant: request.participant
|
||||
}
|
||||
return this.sock.readMessages([data])
|
||||
}
|
||||
|
||||
async startTyping(request: ChatRequest) {
|
||||
return this.sock.sendPresenceUpdate('composing', request.chatId)
|
||||
}
|
||||
|
||||
async stopTyping(request: ChatRequest) {
|
||||
return this.sock.sendPresenceUpdate("paused", request.chatId)
|
||||
}
|
||||
|
||||
async getMessages(query: GetMessageQuery) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
async setReaction(request: MessageReactionRequest) {
|
||||
const key = parseMessageId(request.messageId)
|
||||
const reactionMessage = {
|
||||
react: {
|
||||
text: request.reaction,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
return this.sock.sendMessage(key.remoteJid, reactionMessage)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Contacts methods
|
||||
*/
|
||||
getContact(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
getContacts() {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
public async getContactAbout(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
public async getContactProfilePicture(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
public async blockContact(request: ContactRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
public async unblockContact(request: ContactRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
/**
|
||||
* Group methods
|
||||
*/
|
||||
public createGroup(request: CreateGroupRequest) {
|
||||
const participants = request.participants.map(getId)
|
||||
return this.sock.groupCreate(request.name, participants)
|
||||
}
|
||||
|
||||
public async getGroups() {
|
||||
return await this.sock.groupFetchAllParticipating()
|
||||
}
|
||||
|
||||
public async getGroup(id) {
|
||||
const groups = await this.sock.groupFetchAllParticipating()
|
||||
return groups[id]
|
||||
}
|
||||
|
||||
public async deleteGroup(id) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
public async leaveGroup(id) {
|
||||
return this.sock.groupLeave(id)
|
||||
}
|
||||
|
||||
public async setDescription(id, description) {
|
||||
return this.sock.groupUpdateDescription(id, description)
|
||||
}
|
||||
|
||||
public async setSubject(id, subject) {
|
||||
return this.sock.groupUpdateSubject(id, subject)
|
||||
}
|
||||
|
||||
public async getInviteCode(id): Promise<string> {
|
||||
return this.sock.groupInviteCode(id)
|
||||
}
|
||||
|
||||
public async revokeInviteCode(id): Promise<string> {
|
||||
await this.sock.groupRevokeInvite(id)
|
||||
return this.sock.groupInviteCode(id)
|
||||
}
|
||||
|
||||
public async getParticipants(id) {
|
||||
const groups = await this.sock.groupFetchAllParticipating()
|
||||
return groups[id].participants
|
||||
}
|
||||
|
||||
public async addParticipants(id, request: ParticipantsRequest) {
|
||||
const participants = request.participants.map(getId)
|
||||
return this.sock.groupParticipantsUpdate(id, participants, "add")
|
||||
}
|
||||
|
||||
public async removeParticipants(id, request: ParticipantsRequest) {
|
||||
const participants = request.participants.map(getId)
|
||||
return this.sock.groupParticipantsUpdate(id, participants, "remove")
|
||||
}
|
||||
|
||||
public async promoteParticipantsToAdmin(id, request: ParticipantsRequest) {
|
||||
const participants = request.participants.map(getId)
|
||||
return this.sock.groupParticipantsUpdate(id, participants, "promote")
|
||||
}
|
||||
|
||||
public async demoteParticipantsToUser(id, request: ParticipantsRequest) {
|
||||
const participants = request.participants.map(getId)
|
||||
return this.sock.groupParticipantsUpdate(id, participants, "demote")
|
||||
}
|
||||
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
subscribe(event, handler) {
|
||||
if (event === WAEvents.MESSAGE) {
|
||||
return this.sock.ev.on(BaileysEvents.MESSAGES_UPSERT,
|
||||
({messages}) => this.handleIncomingMessages(messages, handler, false)
|
||||
)
|
||||
} else if (event === WAEvents.MESSAGE_ANY) {
|
||||
return this.sock.ev.on(BaileysEvents.MESSAGES_UPSERT,
|
||||
({messages}) => this.handleIncomingMessages(messages, handler, true)
|
||||
)
|
||||
} else if (event === WAEvents.STATE_CHANGE) {
|
||||
return this.sock.ev.on(BaileysEvents.CONNECTION_UPDATE, handler)
|
||||
} else if (event === WAEvents.GROUP_JOIN) {
|
||||
return this.sock.ev.on(BaileysEvents.GROUPS_UPSERT, handler)
|
||||
} else {
|
||||
throw new NotImplementedByEngineError(`Engine does not support webhook event: ${event}`)
|
||||
}
|
||||
}
|
||||
|
||||
private handleIncomingMessages(messages, handler, includeFromMe) {
|
||||
for (const message of messages) {
|
||||
// if there is no text or media message
|
||||
if (!message) return;
|
||||
if (!message.message) return
|
||||
// Do not include my messages
|
||||
if (!includeFromMe && message.key.fromMe) {
|
||||
continue
|
||||
}
|
||||
this.processIncomingMessage(message).then(handler)
|
||||
}
|
||||
}
|
||||
|
||||
private processIncomingMessage(message) {
|
||||
return this.downloadMedia(message).then(this.toWAMessage)
|
||||
}
|
||||
|
||||
protected toWAMessage(message): Promise<WAMessage> {
|
||||
const isGroupMessage = Boolean(message.key.participant)
|
||||
let participant: string
|
||||
let to: string
|
||||
if (isGroupMessage) {
|
||||
participant = message.key.participant
|
||||
to = message.key.remoteJid
|
||||
}
|
||||
const from = message.key.remoteJid
|
||||
const id = buildMessageId(message.key)
|
||||
let body = message.message.conversation
|
||||
if (!body){
|
||||
// Some of the messages have no conversation, but instead have text in extendedTextMessage
|
||||
// https://github.com/devlikeapro/whatsapp-http-api/issues/90
|
||||
body = message.message.extendedTextMessage?.text
|
||||
}
|
||||
return Promise.resolve({
|
||||
id: id,
|
||||
timestamp: message.messageTimestamp,
|
||||
from: toCusFormat(from),
|
||||
fromMe: message.key.fromMe,
|
||||
body: body,
|
||||
to: toCusFormat(to),
|
||||
participant: toCusFormat(participant),
|
||||
// @ts-ignore
|
||||
hasMedia: Boolean(message.mediaUrl),
|
||||
// @ts-ignore
|
||||
mediaUrl: message.mediaUrl,
|
||||
// @ts-ignore
|
||||
ack: message.ack,
|
||||
location: message.location,
|
||||
vCards: message.vCards,
|
||||
_data: message,
|
||||
})
|
||||
}
|
||||
|
||||
protected async downloadMedia(message: Message) {
|
||||
if (!message.hasMedia) {
|
||||
return message
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
message.mediaUrl = await this.storage.save(message.key.id, "", undefined)
|
||||
return message
|
||||
}
|
||||
|
||||
// Save QR
|
||||
if (qr) {
|
||||
this.status = WhatsappStatus.SCAN_QR_CODE;
|
||||
QRCode.toDataURL(qr).then((url) => {
|
||||
this.qr.save(url);
|
||||
});
|
||||
}
|
||||
});
|
||||
this.events.emit(WAHAInternalEvent.engine_start);
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.sock.ws.removeAllListeners();
|
||||
this.log.log('socket connection terminated');
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
async getScreenshot(): Promise<Buffer | string> {
|
||||
if (this.status === WhatsappStatus.STARTING) {
|
||||
throw new UnprocessableEntityException(
|
||||
`The session is starting, please try again after few seconds`,
|
||||
);
|
||||
} else if (this.status === WhatsappStatus.SCAN_QR_CODE) {
|
||||
return Promise.resolve(this.qr.get());
|
||||
} else if (this.status === WhatsappStatus.WORKING) {
|
||||
throw new UnprocessableEntityException(
|
||||
`Can not get screenshot for non chrome based engine.`,
|
||||
);
|
||||
} else {
|
||||
throw new UnprocessableEntityException(`Unknown status - ${this.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
async checkNumberStatus(
|
||||
request: CheckNumberStatusQuery,
|
||||
): Promise<WANumberExistResult> {
|
||||
const phone = request.phone.split('@')[0];
|
||||
const [result] = await this.sock.onWhatsApp(phone);
|
||||
if (!result) {
|
||||
return { numberExists: false };
|
||||
}
|
||||
return { numberExists: result.exists };
|
||||
}
|
||||
|
||||
sendText(request: MessageTextRequest) {
|
||||
const chatId = this.ensureSuffix(request.chatId);
|
||||
return this.sock.sendMessage(chatId, { text: request.text });
|
||||
}
|
||||
|
||||
sendTextButtons(request: MessageTextButtonsRequest) {
|
||||
const buttons = request.buttons.map((button: Button) => {
|
||||
return {
|
||||
buttonId: button.id,
|
||||
buttonText: { displayText: button.text },
|
||||
type: 1,
|
||||
};
|
||||
});
|
||||
|
||||
const buttonMessage = {
|
||||
text: request.title,
|
||||
buttons: buttons,
|
||||
headerType: 1,
|
||||
};
|
||||
|
||||
return this.sock.sendMessage(request.chatId, buttonMessage);
|
||||
}
|
||||
|
||||
sendContactVCard(request: MessageContactVcardRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
async reply(request: MessageReplyRequest) {
|
||||
const { id } = parseMessageId(request.reply_to);
|
||||
const message = await this.store.loadMessage(toJID(request.chatId), id);
|
||||
return await this.sock.sendMessage(
|
||||
request.chatId,
|
||||
{ text: request.text },
|
||||
{ quoted: message },
|
||||
);
|
||||
}
|
||||
|
||||
sendImage(request: MessageImageRequest) {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
sendFile(request: MessageFileRequest) {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
sendVoice(request: MessageVoiceRequest) {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
sendLocation(request: MessageLocationRequest) {
|
||||
return this.sock.sendMessage(request.chatId, {
|
||||
location: {
|
||||
degreesLatitude: request.latitude,
|
||||
degreesLongitude: request.longitude,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
sendLinkPreview(request: MessageLinkPreviewRequest) {
|
||||
const text = `${request.title}\n${request.url}`;
|
||||
const chatId = this.ensureSuffix(request.chatId);
|
||||
return this.sock.sendMessage(chatId, { text: text });
|
||||
}
|
||||
|
||||
async sendSeen(request: SendSeenRequest) {
|
||||
const key = parseMessageId(request.messageId);
|
||||
const data = {
|
||||
remoteJid: key.remoteJid,
|
||||
id: key.id,
|
||||
participant: request.participant,
|
||||
};
|
||||
return this.sock.readMessages([data]);
|
||||
}
|
||||
|
||||
async startTyping(request: ChatRequest) {
|
||||
return this.sock.sendPresenceUpdate('composing', request.chatId);
|
||||
}
|
||||
|
||||
async stopTyping(request: ChatRequest) {
|
||||
return this.sock.sendPresenceUpdate('paused', request.chatId);
|
||||
}
|
||||
|
||||
async getMessages(query: GetMessageQuery) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
async setReaction(request: MessageReactionRequest) {
|
||||
const key = parseMessageId(request.messageId);
|
||||
const reactionMessage = {
|
||||
react: {
|
||||
text: request.reaction,
|
||||
key: key,
|
||||
},
|
||||
};
|
||||
return this.sock.sendMessage(key.remoteJid, reactionMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contacts methods
|
||||
*/
|
||||
getContact(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
getContacts() {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public async getContactAbout(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public async getContactProfilePicture(query: ContactQuery) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public async blockContact(request: ContactRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public async unblockContact(request: ContactRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Group methods
|
||||
*/
|
||||
public createGroup(request: CreateGroupRequest) {
|
||||
const participants = request.participants.map(getId);
|
||||
return this.sock.groupCreate(request.name, participants);
|
||||
}
|
||||
|
||||
public async getGroups() {
|
||||
return await this.sock.groupFetchAllParticipating();
|
||||
}
|
||||
|
||||
public async getGroup(id) {
|
||||
const groups = await this.sock.groupFetchAllParticipating();
|
||||
return groups[id];
|
||||
}
|
||||
|
||||
public async deleteGroup(id) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
public async leaveGroup(id) {
|
||||
return this.sock.groupLeave(id);
|
||||
}
|
||||
|
||||
public async setDescription(id, description) {
|
||||
return this.sock.groupUpdateDescription(id, description);
|
||||
}
|
||||
|
||||
public async setSubject(id, subject) {
|
||||
return this.sock.groupUpdateSubject(id, subject);
|
||||
}
|
||||
|
||||
public async getInviteCode(id): Promise<string> {
|
||||
return this.sock.groupInviteCode(id);
|
||||
}
|
||||
|
||||
public async revokeInviteCode(id): Promise<string> {
|
||||
await this.sock.groupRevokeInvite(id);
|
||||
return this.sock.groupInviteCode(id);
|
||||
}
|
||||
|
||||
public async getParticipants(id) {
|
||||
const groups = await this.sock.groupFetchAllParticipating();
|
||||
return groups[id].participants;
|
||||
}
|
||||
|
||||
public async addParticipants(id, request: ParticipantsRequest) {
|
||||
const participants = request.participants.map(getId);
|
||||
return this.sock.groupParticipantsUpdate(id, participants, 'add');
|
||||
}
|
||||
|
||||
public async removeParticipants(id, request: ParticipantsRequest) {
|
||||
const participants = request.participants.map(getId);
|
||||
return this.sock.groupParticipantsUpdate(id, participants, 'remove');
|
||||
}
|
||||
|
||||
public async promoteParticipantsToAdmin(id, request: ParticipantsRequest) {
|
||||
const participants = request.participants.map(getId);
|
||||
return this.sock.groupParticipantsUpdate(id, participants, 'promote');
|
||||
}
|
||||
|
||||
public async demoteParticipantsToUser(id, request: ParticipantsRequest) {
|
||||
const participants = request.participants.map(getId);
|
||||
return this.sock.groupParticipantsUpdate(id, participants, 'demote');
|
||||
}
|
||||
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
subscribe(event, handler) {
|
||||
if (event === WAEvents.MESSAGE) {
|
||||
return this.sock.ev.on(BaileysEvents.MESSAGES_UPSERT, ({ messages }) =>
|
||||
this.handleIncomingMessages(messages, handler, false),
|
||||
);
|
||||
} else if (event === WAEvents.MESSAGE_ANY) {
|
||||
return this.sock.ev.on(BaileysEvents.MESSAGES_UPSERT, ({ messages }) =>
|
||||
this.handleIncomingMessages(messages, handler, true),
|
||||
);
|
||||
} else if (event === WAEvents.STATE_CHANGE) {
|
||||
return this.sock.ev.on(BaileysEvents.CONNECTION_UPDATE, handler);
|
||||
} else if (event === WAEvents.GROUP_JOIN) {
|
||||
return this.sock.ev.on(BaileysEvents.GROUPS_UPSERT, handler);
|
||||
} else {
|
||||
throw new NotImplementedByEngineError(
|
||||
`Engine does not support webhook event: ${event}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private handleIncomingMessages(messages, handler, includeFromMe) {
|
||||
for (const message of messages) {
|
||||
// if there is no text or media message
|
||||
if (!message) return;
|
||||
if (!message.message) return;
|
||||
// Do not include my messages
|
||||
if (!includeFromMe && message.key.fromMe) {
|
||||
continue;
|
||||
}
|
||||
this.processIncomingMessage(message).then(handler);
|
||||
}
|
||||
}
|
||||
|
||||
private processIncomingMessage(message) {
|
||||
return this.downloadMedia(message).then(this.toWAMessage);
|
||||
}
|
||||
|
||||
protected toWAMessage(message): Promise<WAMessage> {
|
||||
const isGroupMessage = Boolean(message.key.participant);
|
||||
let participant: string;
|
||||
let to: string;
|
||||
if (isGroupMessage) {
|
||||
participant = message.key.participant;
|
||||
to = message.key.remoteJid;
|
||||
}
|
||||
const from = message.key.remoteJid;
|
||||
const id = buildMessageId(message.key);
|
||||
let body = message.message.conversation;
|
||||
if (!body) {
|
||||
// Some of the messages have no conversation, but instead have text in extendedTextMessage
|
||||
// https://github.com/devlikeapro/whatsapp-http-api/issues/90
|
||||
body = message.message.extendedTextMessage?.text;
|
||||
}
|
||||
return Promise.resolve({
|
||||
id: id,
|
||||
timestamp: message.messageTimestamp,
|
||||
from: toCusFormat(from),
|
||||
fromMe: message.key.fromMe,
|
||||
body: body,
|
||||
to: toCusFormat(to),
|
||||
participant: toCusFormat(participant),
|
||||
// @ts-ignore
|
||||
hasMedia: Boolean(message.mediaUrl),
|
||||
// @ts-ignore
|
||||
mediaUrl: message.mediaUrl,
|
||||
// @ts-ignore
|
||||
ack: message.ack,
|
||||
location: message.location,
|
||||
vCards: message.vCards,
|
||||
_data: message,
|
||||
});
|
||||
}
|
||||
|
||||
protected async downloadMedia(message: Message) {
|
||||
if (!message.hasMedia) {
|
||||
return message;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
message.mediaUrl = await this.storage.save(message.key.id, '', undefined);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from 11111111111@s.whatsapp.net to 11111111111@c.us
|
||||
*/
|
||||
function toCusFormat(remoteJid) {
|
||||
if (isJidGroup(remoteJid)) {
|
||||
return remoteJid
|
||||
}
|
||||
if (!remoteJid) {
|
||||
return
|
||||
}
|
||||
const number = remoteJid.split("@")[0]
|
||||
return ensureSuffix(number)
|
||||
if (isJidGroup(remoteJid)) {
|
||||
return remoteJid;
|
||||
}
|
||||
if (!remoteJid) {
|
||||
return;
|
||||
}
|
||||
const number = remoteJid.split('@')[0];
|
||||
return ensureSuffix(number);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -434,11 +477,11 @@ function toCusFormat(remoteJid) {
|
||||
* @param chatId
|
||||
*/
|
||||
function toJID(chatId) {
|
||||
if (isJidGroup(chatId)) {
|
||||
return chatId
|
||||
}
|
||||
const number = chatId.split("@")[0]
|
||||
return number + "@s.whatsapp.net"
|
||||
if (isJidGroup(chatId)) {
|
||||
return chatId;
|
||||
}
|
||||
const number = chatId.split('@')[0];
|
||||
return number + '@s.whatsapp.net';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -446,9 +489,9 @@ function toJID(chatId) {
|
||||
* {id: "AAA", remoteJid: "11111111111@s.whatsapp.net", "fromMe": false}
|
||||
* false_11111111111@c.us_AA
|
||||
*/
|
||||
function buildMessageId({id, remoteJid, fromMe}) {
|
||||
const chatId = toCusFormat(remoteJid)
|
||||
return `${fromMe || false}_${chatId}_${id}`
|
||||
function buildMessageId({ id, remoteJid, fromMe }) {
|
||||
const chatId = toCusFormat(remoteJid);
|
||||
return `${fromMe || false}_${chatId}_${id}`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -457,18 +500,19 @@ function buildMessageId({id, remoteJid, fromMe}) {
|
||||
* {id: "AAA", remoteJid: "11111111111@s.whatsapp.net", "fromMe": false}
|
||||
*/
|
||||
function parseMessageId(messageId) {
|
||||
const parts = messageId.split("_")
|
||||
if (parts.length != 3) {
|
||||
throw new Error("Message id be in format false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA")
|
||||
}
|
||||
const fromMe = parts[0] == "true"
|
||||
const chatId = parts[1]
|
||||
const remoteJid = toJID(chatId)
|
||||
const id = parts[2]
|
||||
return {fromMe: fromMe, id: id, remoteJid: remoteJid}
|
||||
const parts = messageId.split('_');
|
||||
if (parts.length != 3) {
|
||||
throw new Error(
|
||||
'Message id be in format false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
);
|
||||
}
|
||||
const fromMe = parts[0] == 'true';
|
||||
const chatId = parts[1];
|
||||
const remoteJid = toJID(chatId);
|
||||
const id = parts[2];
|
||||
return { fromMe: fromMe, id: id, remoteJid: remoteJid };
|
||||
}
|
||||
|
||||
|
||||
function getId(object) {
|
||||
return object.id
|
||||
return object.id;
|
||||
}
|
||||
+255
-220
@@ -1,239 +1,274 @@
|
||||
import {WAHAInternalEvent, WhatsappSession} from "./abc/session.abc";
|
||||
import { WAHAInternalEvent, WhatsappSession } from './abc/session.abc';
|
||||
import {
|
||||
Button,
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest
|
||||
} from "../structures/chatting.dto";
|
||||
import {WAMessage, WANumberExistResult} from "../structures/responses.dto";
|
||||
import {create, Message, Whatsapp} from "venom-bot";
|
||||
import {WAEvents, WhatsappStatus} from "../structures/enums.dto";
|
||||
import {NotImplementedByEngineError} from "./exceptions";
|
||||
import {MediaStorage} from "./abc/storage.abc";
|
||||
import {UnprocessableEntityException} from "@nestjs/common/exceptions/unprocessable-entity.exception";
|
||||
import {ConsoleLogger} from "@nestjs/common";
|
||||
import {QR} from "./QR";
|
||||
Button,
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest,
|
||||
} from '../structures/chatting.dto';
|
||||
import { WAMessage, WANumberExistResult } from '../structures/responses.dto';
|
||||
import { create, Message, Whatsapp } from 'venom-bot';
|
||||
import {
|
||||
WAEvents,
|
||||
WhatsappEngine,
|
||||
WhatsappStatus,
|
||||
} from '../structures/enums.dto';
|
||||
import { NotImplementedByEngineError } from './exceptions';
|
||||
import { UnprocessableEntityException } from '@nestjs/common/exceptions/unprocessable-entity.exception';
|
||||
import { QR } from './QR';
|
||||
|
||||
export class WhatsappSessionVenomCore extends WhatsappSession {
|
||||
whatsapp: Whatsapp;
|
||||
private qr: QR
|
||||
engine = WhatsappEngine.NOWEB;
|
||||
|
||||
public constructor(public name: string, protected storage: MediaStorage, protected log: ConsoleLogger) {
|
||||
super(name, storage, log);
|
||||
this.qr = new QR()
|
||||
whatsapp: Whatsapp;
|
||||
private qr: QR;
|
||||
|
||||
public constructor(config) {
|
||||
super(config);
|
||||
this.qr = new QR();
|
||||
}
|
||||
|
||||
protected buildClient() {
|
||||
return create(this.name, this.getCatchQR(), undefined, {
|
||||
headless: true,
|
||||
devtools: false,
|
||||
debug: false,
|
||||
logQR: true,
|
||||
browserArgs: this.getBrowserArgsForPuppeteer(),
|
||||
autoClose: 60000,
|
||||
puppeteerOptions: {},
|
||||
});
|
||||
}
|
||||
|
||||
protected getCatchQR() {
|
||||
return (base64Qrimg, asciiQR, attempts, urlCode) => {
|
||||
this.qr.save(base64Qrimg);
|
||||
this.status = WhatsappStatus.SCAN_QR_CODE;
|
||||
this.log.debug('Number of attempts to read the qrcode: ', attempts);
|
||||
this.log.log('Terminal qrcode:');
|
||||
// Log QR image in console without this.log to make it pretty
|
||||
console.log(asciiQR);
|
||||
};
|
||||
}
|
||||
|
||||
async start() {
|
||||
try {
|
||||
this.whatsapp = await this.buildClient();
|
||||
} catch (error) {
|
||||
this.status = WhatsappStatus.FAILED;
|
||||
this.log.error(error);
|
||||
this.qr.save('');
|
||||
return;
|
||||
}
|
||||
|
||||
protected buildClient() {
|
||||
return create(this.name,
|
||||
this.getCatchQR(),
|
||||
undefined,
|
||||
{
|
||||
headless: true,
|
||||
devtools: false,
|
||||
useChrome: true,
|
||||
debug: false,
|
||||
logQR: true,
|
||||
browserArgs: this.getBrowserArgsForPuppeteer(),
|
||||
autoClose: 60000,
|
||||
puppeteerOptions: {},
|
||||
multidevice: true,
|
||||
}
|
||||
)
|
||||
this.status = WhatsappStatus.WORKING;
|
||||
this.events.emit(WAHAInternalEvent.engine_start);
|
||||
return this;
|
||||
}
|
||||
|
||||
stop() {
|
||||
return this.whatsapp.close();
|
||||
}
|
||||
|
||||
subscribe(event: WAEvents | string, handler: (message) => void) {
|
||||
if (event === WAEvents.MESSAGE) {
|
||||
return this.whatsapp.onMessage((message: Message) =>
|
||||
this.processIncomingMessage(message).then(handler),
|
||||
);
|
||||
} else if (event === WAEvents.MESSAGE_ANY) {
|
||||
return this.whatsapp.onAnyMessage((message: Message) =>
|
||||
this.processIncomingMessage(message).then(handler),
|
||||
);
|
||||
} else if (event === WAEvents.STATE_CHANGE) {
|
||||
return this.whatsapp.onStateChange(handler);
|
||||
} else if (event === WAEvents.MESSAGE_ACK) {
|
||||
return this.whatsapp.onAck(handler);
|
||||
} else if (event === WAEvents.GROUP_JOIN) {
|
||||
return this.whatsapp.onAddedToGroup(handler);
|
||||
} else {
|
||||
throw new NotImplementedByEngineError(
|
||||
`Engine does not support webhook event: ${event}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected getCatchQR() {
|
||||
return (base64Qrimg, asciiQR, attempts, urlCode) => {
|
||||
this.qr.save(base64Qrimg)
|
||||
this.status = WhatsappStatus.SCAN_QR_CODE
|
||||
this.log.debug('Number of attempts to read the qrcode: ', attempts);
|
||||
this.log.log('Terminal qrcode:');
|
||||
// Log QR image in console without this.log to make it pretty
|
||||
console.log(asciiQR);
|
||||
};
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
getScreenshot(): Promise<Buffer | string> {
|
||||
if (this.status === WhatsappStatus.STARTING) {
|
||||
throw new UnprocessableEntityException(
|
||||
`The session is starting, please try again after few seconds`,
|
||||
);
|
||||
} else if (this.status === WhatsappStatus.SCAN_QR_CODE) {
|
||||
return Promise.resolve(this.qr.get());
|
||||
} else if (this.status === WhatsappStatus.WORKING) {
|
||||
return this.whatsapp.page.screenshot();
|
||||
} else {
|
||||
throw new UnprocessableEntityException(`Unknown status - ${this.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
async start() {
|
||||
try {
|
||||
this.whatsapp = await this.buildClient()
|
||||
} catch (error) {
|
||||
this.status = WhatsappStatus.FAILED
|
||||
this.log.error(error)
|
||||
this.qr.save("")
|
||||
return
|
||||
}
|
||||
|
||||
this.status = WhatsappStatus.WORKING
|
||||
this.events.emit(WAHAInternalEvent.engine_start)
|
||||
return this
|
||||
async checkNumberStatus(
|
||||
request: CheckNumberStatusQuery,
|
||||
): Promise<WANumberExistResult> {
|
||||
try {
|
||||
return await this.whatsapp.checkNumberStatus(
|
||||
this.ensureSuffix(request.phone),
|
||||
);
|
||||
} catch (error) {
|
||||
// Catch number doesn't exist error and return it as is
|
||||
if (error.status === 404 && !error.numberExists) {
|
||||
return error;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
sendContactVCard(request: MessageContactVcardRequest) {
|
||||
return this.whatsapp.sendContactVcard(
|
||||
request.chatId,
|
||||
request.contactsId,
|
||||
request.name,
|
||||
);
|
||||
}
|
||||
|
||||
stop() {
|
||||
return this.whatsapp.close()
|
||||
sendText(request: MessageTextRequest) {
|
||||
return this.whatsapp.sendText(
|
||||
this.ensureSuffix(request.chatId),
|
||||
request.text,
|
||||
);
|
||||
}
|
||||
|
||||
reply(request: MessageReplyRequest) {
|
||||
return this.whatsapp.reply(request.chatId, request.text, request.reply_to);
|
||||
}
|
||||
|
||||
sendFile(request: MessageFileRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
sendImage(request: MessageImageRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
async sendVoice(request) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
sendLinkPreview(request: MessageLinkPreviewRequest) {
|
||||
return this.whatsapp.sendLinkPreview(
|
||||
request.chatId,
|
||||
request.url,
|
||||
request.title,
|
||||
);
|
||||
}
|
||||
|
||||
sendLocation(request: MessageLocationRequest) {
|
||||
return this.whatsapp.sendLocation(
|
||||
request.chatId,
|
||||
String(request.latitude),
|
||||
String(request.longitude),
|
||||
request.title,
|
||||
);
|
||||
}
|
||||
|
||||
sendSeen(chat: ChatRequest) {
|
||||
return this.whatsapp.markMarkSeenMessage(chat.chatId);
|
||||
}
|
||||
|
||||
sendTextButtons(request: MessageTextButtonsRequest) {
|
||||
const buttons = request.buttons.map((button: Button) => {
|
||||
return {
|
||||
buttonId: button.id,
|
||||
buttonText: {
|
||||
displayText: button.text,
|
||||
},
|
||||
};
|
||||
});
|
||||
return this.whatsapp.sendButtons(
|
||||
this.ensureSuffix(request.chatId),
|
||||
request.title,
|
||||
request.footer,
|
||||
buttons,
|
||||
);
|
||||
}
|
||||
|
||||
startTyping(chat: ChatRequest) {
|
||||
return this.whatsapp.startTyping(chat.chatId, false);
|
||||
}
|
||||
|
||||
stopTyping(chat: ChatRequest) {
|
||||
return;
|
||||
// The method is not available yet in new venom-bot
|
||||
// return this.whatsapp.stopTyping(chat.chatId);
|
||||
}
|
||||
|
||||
async getMessages(query: GetMessageQuery) {
|
||||
const messages = await this.whatsapp.getAllMessagesInChat(
|
||||
query.chatId,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
// Go over messages, download media, and convert to right format.
|
||||
const result = [];
|
||||
for (const [count, message] of messages.entries()) {
|
||||
if (count > query.limit) {
|
||||
// Have enough in the list, stop processing
|
||||
break;
|
||||
}
|
||||
result.push(await this.processIncomingMessage(message));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
subscribe(event: WAEvents | string, handler: (message) => void) {
|
||||
if (event === WAEvents.MESSAGE) {
|
||||
return this.whatsapp.onMessage((message: Message) => this.processIncomingMessage(message).then(handler))
|
||||
} else if (event === WAEvents.MESSAGE_ANY) {
|
||||
return this.whatsapp.onAnyMessage((message: Message) => this.processIncomingMessage(message).then(handler))
|
||||
} else if (event === WAEvents.STATE_CHANGE) {
|
||||
return this.whatsapp.onStateChange(handler)
|
||||
} else if (event === WAEvents.MESSAGE_ACK) {
|
||||
return this.whatsapp.onAck(handler)
|
||||
} else if (event === WAEvents.GROUP_JOIN) {
|
||||
return this.whatsapp.onAddedToGroup(handler)
|
||||
} else {
|
||||
throw new NotImplementedByEngineError(`Engine does not support webhook event: ${event}`)
|
||||
}
|
||||
setReaction(request: MessageReactionRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
protected async downloadAndDecryptMedia(message: Message) {
|
||||
if (!message.isMMS || !message.isMedia) {
|
||||
return message;
|
||||
}
|
||||
// @ts-ignore
|
||||
message.mediaUrl = await this.storage.save(message.id, '', undefined);
|
||||
return message;
|
||||
}
|
||||
|
||||
private processIncomingMessage(message: Message) {
|
||||
return this.downloadAndDecryptMedia(message).then(this.toWAMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
getScreenshot(): Promise<Buffer | string> {
|
||||
if (this.status === WhatsappStatus.STARTING) {
|
||||
throw new UnprocessableEntityException(`The session is starting, please try again after few seconds`);
|
||||
} else if (this.status === WhatsappStatus.SCAN_QR_CODE) {
|
||||
return Promise.resolve(this.qr.get())
|
||||
} else if (this.status === WhatsappStatus.WORKING) {
|
||||
return this.whatsapp.page.screenshot()
|
||||
} else {
|
||||
throw new UnprocessableEntityException(`Unknown status - ${this.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
async checkNumberStatus(request: CheckNumberStatusQuery): Promise<WANumberExistResult> {
|
||||
try {
|
||||
return await this.whatsapp.checkNumberStatus(this.ensureSuffix(request.phone))
|
||||
} catch (error) {
|
||||
// Catch number doesn't exist error and return it as is
|
||||
if (error.status === 404 && !error.numberExists) {
|
||||
return error
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
sendContactVCard(request: MessageContactVcardRequest) {
|
||||
return this.whatsapp.sendContactVcard(request.chatId, request.contactsId, request.name)
|
||||
}
|
||||
|
||||
sendText(request: MessageTextRequest) {
|
||||
return this.whatsapp.sendText(this.ensureSuffix(request.chatId), request.text)
|
||||
}
|
||||
|
||||
reply(request: MessageReplyRequest) {
|
||||
return this.whatsapp.reply(request.chatId, request.text, request.reply_to)
|
||||
}
|
||||
|
||||
sendFile(request: MessageFileRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
sendImage(request: MessageImageRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
async sendVoice(request) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
sendLinkPreview(request: MessageLinkPreviewRequest) {
|
||||
return this.whatsapp.sendLinkPreview(request.chatId, request.url, request.title)
|
||||
}
|
||||
|
||||
sendLocation(request: MessageLocationRequest) {
|
||||
return this.whatsapp.sendLocation(request.chatId, String(request.latitude), String(request.longitude), request.title)
|
||||
}
|
||||
|
||||
sendSeen(chat: ChatRequest) {
|
||||
return this.whatsapp.sendSeen(chat.chatId)
|
||||
}
|
||||
|
||||
sendTextButtons(request: MessageTextButtonsRequest) {
|
||||
const buttons = request.buttons.map((button: Button) => {
|
||||
return {
|
||||
buttonId: button.id,
|
||||
buttonText: {
|
||||
displayText: button.text
|
||||
}
|
||||
}
|
||||
})
|
||||
return this.whatsapp.sendButtons(this.ensureSuffix(request.chatId), request.title, buttons, request.footer)
|
||||
}
|
||||
|
||||
startTyping(chat: ChatRequest) {
|
||||
return this.whatsapp.startTyping(chat.chatId)
|
||||
}
|
||||
|
||||
stopTyping(chat: ChatRequest) {
|
||||
return this.whatsapp.stopTyping(chat.chatId)
|
||||
}
|
||||
|
||||
async getMessages(query: GetMessageQuery) {
|
||||
const messages = await this.whatsapp.getAllMessagesInChat(query.chatId, true, false)
|
||||
// Go over messages, download media, and convert to right format.
|
||||
const result = []
|
||||
for (const [count, message] of messages.entries()) {
|
||||
if (count > query.limit) {
|
||||
// Have enough in the list, stop processing
|
||||
break
|
||||
}
|
||||
result.push(await this.processIncomingMessage(message))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
setReaction(request: MessageReactionRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
protected async downloadAndDecryptMedia(message: Message) {
|
||||
if (!message.isMMS || !message.isMedia) {
|
||||
return message
|
||||
}
|
||||
// @ts-ignore
|
||||
message.mediaUrl = await this.storage.save(message.id, "", undefined)
|
||||
return message
|
||||
}
|
||||
|
||||
private processIncomingMessage(message: Message) {
|
||||
return this.downloadAndDecryptMedia(message).then(this.toWAMessage)
|
||||
}
|
||||
|
||||
protected toWAMessage(message: Message): Promise<WAMessage> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve({
|
||||
id: message.id,
|
||||
timestamp: message.timestamp,
|
||||
from: message.from,
|
||||
fromMe: message.fromMe,
|
||||
to: message.to,
|
||||
body: message.body,
|
||||
// @ts-ignore
|
||||
hasMedia: Boolean(message.mediaUrl),
|
||||
// @ts-ignore
|
||||
mediaUrl: message.mediaUrl,
|
||||
// @ts-ignore
|
||||
ack: message.ack,
|
||||
location: undefined,
|
||||
vCards: undefined,
|
||||
_data: message,
|
||||
})
|
||||
}
|
||||
protected toWAMessage(message: Message): Promise<WAMessage> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve({
|
||||
id: message.id,
|
||||
timestamp: message.timestamp,
|
||||
from: message.from,
|
||||
fromMe: message.fromMe,
|
||||
to: message.to,
|
||||
body: message.body,
|
||||
// @ts-ignore
|
||||
hasMedia: Boolean(message.mediaUrl),
|
||||
// @ts-ignore
|
||||
mediaUrl: message.mediaUrl,
|
||||
// @ts-ignore
|
||||
ack: message.ack,
|
||||
location: undefined,
|
||||
vCards: undefined,
|
||||
_data: message,
|
||||
});
|
||||
}
|
||||
}
|
||||
+406
-339
@@ -1,349 +1,416 @@
|
||||
import {UnprocessableEntityException} from "@nestjs/common/exceptions/unprocessable-entity.exception";
|
||||
import {Buttons, Chat, Client, Contact, Events, GroupChat, Location, Message} from "whatsapp-web.js";
|
||||
import {Message as MessageInstance} from "whatsapp-web.js/src/structures"
|
||||
import {WAEvents, WhatsappStatus} from "../structures/enums.dto";
|
||||
import {WAHAInternalEvent, WhatsappSession} from "./abc/session.abc";
|
||||
import {WAMessage, WANumberExistResult} from "../structures/responses.dto";
|
||||
import { UnprocessableEntityException } from '@nestjs/common/exceptions/unprocessable-entity.exception';
|
||||
import {
|
||||
Button,
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest, SendSeenRequest
|
||||
} from "../structures/chatting.dto";
|
||||
import {AvailableInPlusVersion, NotImplementedByEngineError} from "./exceptions";
|
||||
import {ContactQuery, ContactRequest} from "../structures/contacts.dto";
|
||||
import {CreateGroupRequest, ParticipantsRequest} from "../structures/groups.dto";
|
||||
Buttons,
|
||||
Chat,
|
||||
Client,
|
||||
Contact,
|
||||
Events,
|
||||
GroupChat,
|
||||
Location,
|
||||
Message,
|
||||
} from 'whatsapp-web.js';
|
||||
import { Message as MessageInstance } from 'whatsapp-web.js/src/structures';
|
||||
import {
|
||||
WAEvents,
|
||||
WhatsappEngine,
|
||||
WhatsappStatus,
|
||||
} from '../structures/enums.dto';
|
||||
import { WAHAInternalEvent, WhatsappSession } from './abc/session.abc';
|
||||
import { WAMessage, WANumberExistResult } from '../structures/responses.dto';
|
||||
import {
|
||||
Button,
|
||||
ChatRequest,
|
||||
CheckNumberStatusQuery,
|
||||
GetMessageQuery,
|
||||
MessageContactVcardRequest,
|
||||
MessageFileRequest,
|
||||
MessageImageRequest,
|
||||
MessageLinkPreviewRequest,
|
||||
MessageLocationRequest,
|
||||
MessageReactionRequest,
|
||||
MessageReplyRequest,
|
||||
MessageTextButtonsRequest,
|
||||
MessageTextRequest,
|
||||
MessageVoiceRequest,
|
||||
SendSeenRequest,
|
||||
} from '../structures/chatting.dto';
|
||||
import {
|
||||
AvailableInPlusVersion,
|
||||
NotImplementedByEngineError,
|
||||
} from './exceptions';
|
||||
import { ContactQuery, ContactRequest } from '../structures/contacts.dto';
|
||||
import {
|
||||
CreateGroupRequest,
|
||||
ParticipantsRequest,
|
||||
} from '../structures/groups.dto';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const qrcode = require('qrcode-terminal');
|
||||
|
||||
|
||||
export class WhatsappSessionWebJSCore extends WhatsappSession {
|
||||
whatsapp: Client;
|
||||
engine = WhatsappEngine.NOWEB;
|
||||
|
||||
protected buildClient() {
|
||||
return new Client({
|
||||
puppeteer: {
|
||||
headless: true,
|
||||
executablePath: this.getBrowserExecutablePath(),
|
||||
args: this.getBrowserArgsForPuppeteer(),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async start() {
|
||||
this.whatsapp = this.buildClient()
|
||||
|
||||
this.whatsapp.initialize().catch(error => {
|
||||
this.status = WhatsappStatus.FAILED
|
||||
this.log.error(error)
|
||||
return
|
||||
});
|
||||
|
||||
// Connect events
|
||||
this.whatsapp.on(Events.QR_RECEIVED, (qr) => {
|
||||
qrcode.generate(qr, {small: true});
|
||||
this.status = WhatsappStatus.SCAN_QR_CODE
|
||||
});
|
||||
|
||||
this.whatsapp.on(Events.AUTHENTICATED, () => {
|
||||
this.status = WhatsappStatus.WORKING
|
||||
this.log.log(`Session '${this.name}' has been authenticated!`)
|
||||
});
|
||||
this.events.emit(WAHAInternalEvent.engine_start)
|
||||
return this
|
||||
}
|
||||
|
||||
stop() {
|
||||
return this.whatsapp.destroy()
|
||||
}
|
||||
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
async getScreenshot(): Promise<Buffer | string> {
|
||||
if (this.status === WhatsappStatus.FAILED) {
|
||||
throw new UnprocessableEntityException(`The session under FAILED status. Please try to restart it.`);
|
||||
}
|
||||
return await this.whatsapp.pupPage.screenshot()
|
||||
}
|
||||
|
||||
async checkNumberStatus(request: CheckNumberStatusQuery): Promise<WANumberExistResult> {
|
||||
const exist = await this.whatsapp.isRegisteredUser(this.ensureSuffix(request.phone))
|
||||
return {numberExists: exist}
|
||||
}
|
||||
|
||||
sendText(request: MessageTextRequest) {
|
||||
return this.whatsapp.sendMessage(this.ensureSuffix(request.chatId), request.text)
|
||||
}
|
||||
|
||||
sendTextButtons(request: MessageTextButtonsRequest) {
|
||||
const buttons = request.buttons.map((button: Button) => {
|
||||
return {
|
||||
id: button.id,
|
||||
body: button.text,
|
||||
}
|
||||
})
|
||||
const message = new Buttons("", buttons, request.title, request.footer)
|
||||
return this.whatsapp.sendMessage(this.ensureSuffix(request.chatId), message)
|
||||
}
|
||||
|
||||
sendContactVCard(request: MessageContactVcardRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
reply(request: MessageReplyRequest) {
|
||||
const options = {
|
||||
quotedMessageId: request.reply_to,
|
||||
};
|
||||
return this.whatsapp.sendMessage(request.chatId, request.text, options)
|
||||
}
|
||||
|
||||
sendImage(request: MessageImageRequest) {
|
||||
throw new AvailableInPlusVersion()
|
||||
}
|
||||
|
||||
sendFile(request: MessageFileRequest) {
|
||||
throw new AvailableInPlusVersion()
|
||||
}
|
||||
|
||||
sendVoice(request: MessageVoiceRequest) {
|
||||
throw new AvailableInPlusVersion()
|
||||
}
|
||||
|
||||
async sendLocation(request: MessageLocationRequest) {
|
||||
const location = new Location(
|
||||
request.latitude,
|
||||
request.longitude,
|
||||
request.title,
|
||||
)
|
||||
return this.whatsapp.sendMessage(request.chatId, location)
|
||||
}
|
||||
|
||||
sendLinkPreview(request: MessageLinkPreviewRequest) {
|
||||
throw new NotImplementedByEngineError()
|
||||
}
|
||||
|
||||
|
||||
async sendSeen(request: SendSeenRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId)
|
||||
await chat.sendSeen()
|
||||
}
|
||||
|
||||
async startTyping(request: ChatRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId)
|
||||
await chat.sendStateTyping()
|
||||
}
|
||||
|
||||
async stopTyping(request: ChatRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId)
|
||||
await chat.clearState()
|
||||
}
|
||||
|
||||
async getMessages(query: GetMessageQuery) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(this.ensureSuffix(query.chatId))
|
||||
const messages = await chat.fetchMessages({
|
||||
limit: query.limit,
|
||||
})
|
||||
// Go over messages, download media, and convert to right format.
|
||||
const result = []
|
||||
for (const message of messages) {
|
||||
result.push(await this.processIncomingMessage(message))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
async setReaction(request: MessageReactionRequest) {
|
||||
const messageId = this.deserializeId(request.messageId)
|
||||
// Recreate instance to react on it
|
||||
const message = new MessageInstance(this.whatsapp)
|
||||
message.id = messageId
|
||||
message._data = {id: messageId}
|
||||
|
||||
return message.react(request.reaction)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Contacts methods
|
||||
*/
|
||||
getContact(query: ContactQuery) {
|
||||
return this.whatsapp.getContactById(this.ensureSuffix(query.contactId)).then(this.toWAContact)
|
||||
}
|
||||
|
||||
getContacts() {
|
||||
return this.whatsapp.getContacts().then(contacts => contacts.map(this.toWAContact))
|
||||
}
|
||||
|
||||
public async getContactAbout(query: ContactQuery) {
|
||||
const contact = await this.whatsapp.getContactById(this.ensureSuffix(query.contactId))
|
||||
return {"about": await contact.getAbout()}
|
||||
}
|
||||
|
||||
public async getContactProfilePicture(query: ContactQuery) {
|
||||
const contact = await this.whatsapp.getContactById(this.ensureSuffix(query.contactId))
|
||||
return {"profilePictureURL": await contact.getProfilePicUrl()}
|
||||
}
|
||||
|
||||
public async blockContact(request: ContactRequest) {
|
||||
const contact = await this.whatsapp.getContactById(this.ensureSuffix(request.contactId))
|
||||
await contact.block()
|
||||
}
|
||||
|
||||
public async unblockContact(request: ContactRequest) {
|
||||
const contact = await this.whatsapp.getContactById(this.ensureSuffix(request.contactId))
|
||||
await contact.unblock()
|
||||
}
|
||||
|
||||
/**
|
||||
* Group methods
|
||||
*/
|
||||
public createGroup(request: CreateGroupRequest) {
|
||||
const participantIds = request.participants.map(participant => participant.id)
|
||||
return this.whatsapp.createGroup(request.name, participantIds)
|
||||
}
|
||||
|
||||
public getGroups() {
|
||||
return this.whatsapp.getChats().then(chats => chats.filter(chat => chat.isGroup))
|
||||
}
|
||||
|
||||
public getGroup(id) {
|
||||
return this.whatsapp.getChatById(id)
|
||||
}
|
||||
|
||||
public async deleteGroup(id) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
return groupChat.delete()
|
||||
}
|
||||
|
||||
public async leaveGroup(id) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
return groupChat.leave()
|
||||
}
|
||||
|
||||
public async setDescription(id, description) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
return groupChat.setDescription(description)
|
||||
}
|
||||
|
||||
public async setSubject(id, subject) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
return groupChat.setSubject(subject)
|
||||
}
|
||||
|
||||
public async getInviteCode(id): Promise<string> {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
return groupChat.getInviteCode()
|
||||
}
|
||||
|
||||
public async revokeInviteCode(id): Promise<string> {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
await groupChat.revokeInvite()
|
||||
return groupChat.getInviteCode()
|
||||
}
|
||||
|
||||
public async getParticipants(id) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
return groupChat.participants
|
||||
}
|
||||
|
||||
public async addParticipants(id, request: ParticipantsRequest) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
const participantIds = request.participants.map(participant => participant.id)
|
||||
return groupChat.addParticipants(participantIds)
|
||||
}
|
||||
|
||||
public async removeParticipants(id, request: ParticipantsRequest) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
const participantIds = request.participants.map(participant => participant.id)
|
||||
return groupChat.removeParticipants(participantIds)
|
||||
}
|
||||
|
||||
public async promoteParticipantsToAdmin(id, request: ParticipantsRequest) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
const participantIds = request.participants.map(participant => participant.id)
|
||||
return groupChat.promoteParticipants(participantIds)
|
||||
}
|
||||
|
||||
public async demoteParticipantsToUser(id, request: ParticipantsRequest) {
|
||||
const groupChat = await this.whatsapp.getChatById(id) as GroupChat
|
||||
const participantIds = request.participants.map(participant => participant.id)
|
||||
return groupChat.demoteParticipants(participantIds)
|
||||
}
|
||||
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
subscribe(event, handler) {
|
||||
if (event === WAEvents.MESSAGE) {
|
||||
this.whatsapp.on(Events.MESSAGE_RECEIVED, (message) => this.processIncomingMessage(message).then(handler))
|
||||
} else if (event === WAEvents.MESSAGE_ANY) {
|
||||
this.whatsapp.on(Events.MESSAGE_CREATE, (message) => this.processIncomingMessage(message).then(handler))
|
||||
} else if (event === WAEvents.STATE_CHANGE) {
|
||||
this.whatsapp.on(Events.STATE_CHANGED, handler)
|
||||
} else if (event === WAEvents.MESSAGE_ACK) {
|
||||
// We do not download media here
|
||||
this.whatsapp.on(Events.MESSAGE_ACK, (message) => this.toWAMessage(message).then(handler))
|
||||
} else if (event === WAEvents.GROUP_JOIN) {
|
||||
this.whatsapp.on(Events.GROUP_JOIN, handler)
|
||||
} else if (event === WAEvents.GROUP_LEAVE) {
|
||||
this.whatsapp.on(Events.GROUP_LEAVE, handler)
|
||||
} else {
|
||||
throw new NotImplementedByEngineError(`Engine does not support webhook event: ${event}`)
|
||||
}
|
||||
}
|
||||
|
||||
private processIncomingMessage(message: Message) {
|
||||
return this.downloadMedia(message).then(this.toWAMessage)
|
||||
}
|
||||
|
||||
protected toWAMessage(message: Message): Promise<WAMessage> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve({
|
||||
id: message.id._serialized,
|
||||
timestamp: message.timestamp,
|
||||
from: message.from,
|
||||
fromMe: message.fromMe,
|
||||
to: message.to,
|
||||
body: message.body,
|
||||
// @ts-ignore
|
||||
hasMedia: Boolean(message.mediaUrl),
|
||||
// @ts-ignore
|
||||
mediaUrl: message.mediaUrl,
|
||||
// @ts-ignore
|
||||
ack: message.ack,
|
||||
location: message.location,
|
||||
vCards: message.vCards,
|
||||
_data: message.rawData,
|
||||
})
|
||||
}
|
||||
|
||||
protected toWAContact(contact: Contact) {
|
||||
// @ts-ignore
|
||||
contact.id = contact.id._serialized
|
||||
return contact
|
||||
}
|
||||
|
||||
protected async downloadMedia(message: Message) {
|
||||
if (!message.hasMedia) {
|
||||
return message
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
message.mediaUrl = await this.storage.save(message.id._serialized, "", undefined)
|
||||
return message
|
||||
whatsapp: Client;
|
||||
|
||||
protected buildClient() {
|
||||
return new Client({
|
||||
puppeteer: {
|
||||
headless: true,
|
||||
executablePath: this.getBrowserExecutablePath(),
|
||||
args: this.getBrowserArgsForPuppeteer(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async start() {
|
||||
this.whatsapp = this.buildClient();
|
||||
|
||||
this.whatsapp.initialize().catch((error) => {
|
||||
this.status = WhatsappStatus.FAILED;
|
||||
this.log.error(error);
|
||||
return;
|
||||
});
|
||||
|
||||
// Connect events
|
||||
this.whatsapp.on(Events.QR_RECEIVED, (qr) => {
|
||||
qrcode.generate(qr, { small: true });
|
||||
this.status = WhatsappStatus.SCAN_QR_CODE;
|
||||
});
|
||||
|
||||
this.whatsapp.on(Events.AUTHENTICATED, () => {
|
||||
this.status = WhatsappStatus.WORKING;
|
||||
this.log.log(`Session '${this.name}' has been authenticated!`);
|
||||
});
|
||||
this.events.emit(WAHAInternalEvent.engine_start);
|
||||
return this;
|
||||
}
|
||||
|
||||
stop() {
|
||||
return this.whatsapp.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* START - Methods for API
|
||||
*/
|
||||
async getScreenshot(): Promise<Buffer | string> {
|
||||
if (this.status === WhatsappStatus.FAILED) {
|
||||
throw new UnprocessableEntityException(
|
||||
`The session under FAILED status. Please try to restart it.`,
|
||||
);
|
||||
}
|
||||
return await this.whatsapp.pupPage.screenshot();
|
||||
}
|
||||
|
||||
async checkNumberStatus(
|
||||
request: CheckNumberStatusQuery,
|
||||
): Promise<WANumberExistResult> {
|
||||
const exist = await this.whatsapp.isRegisteredUser(
|
||||
this.ensureSuffix(request.phone),
|
||||
);
|
||||
return { numberExists: exist };
|
||||
}
|
||||
|
||||
sendText(request: MessageTextRequest) {
|
||||
return this.whatsapp.sendMessage(
|
||||
this.ensureSuffix(request.chatId),
|
||||
request.text,
|
||||
);
|
||||
}
|
||||
|
||||
sendTextButtons(request: MessageTextButtonsRequest) {
|
||||
const buttons = request.buttons.map((button: Button) => {
|
||||
return {
|
||||
id: button.id,
|
||||
body: button.text,
|
||||
};
|
||||
});
|
||||
const message = new Buttons('', buttons, request.title, request.footer);
|
||||
return this.whatsapp.sendMessage(
|
||||
this.ensureSuffix(request.chatId),
|
||||
message,
|
||||
);
|
||||
}
|
||||
|
||||
sendContactVCard(request: MessageContactVcardRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
reply(request: MessageReplyRequest) {
|
||||
const options = {
|
||||
quotedMessageId: request.reply_to,
|
||||
};
|
||||
return this.whatsapp.sendMessage(request.chatId, request.text, options);
|
||||
}
|
||||
|
||||
sendImage(request: MessageImageRequest) {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
sendFile(request: MessageFileRequest) {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
sendVoice(request: MessageVoiceRequest) {
|
||||
throw new AvailableInPlusVersion();
|
||||
}
|
||||
|
||||
async sendLocation(request: MessageLocationRequest) {
|
||||
const location = new Location(
|
||||
request.latitude,
|
||||
request.longitude,
|
||||
request.title,
|
||||
);
|
||||
return this.whatsapp.sendMessage(request.chatId, location);
|
||||
}
|
||||
|
||||
sendLinkPreview(request: MessageLinkPreviewRequest) {
|
||||
throw new NotImplementedByEngineError();
|
||||
}
|
||||
|
||||
async sendSeen(request: SendSeenRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId);
|
||||
await chat.sendSeen();
|
||||
}
|
||||
|
||||
async startTyping(request: ChatRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId);
|
||||
await chat.sendStateTyping();
|
||||
}
|
||||
|
||||
async stopTyping(request: ChatRequest) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(request.chatId);
|
||||
await chat.clearState();
|
||||
}
|
||||
|
||||
async getMessages(query: GetMessageQuery) {
|
||||
const chat: Chat = await this.whatsapp.getChatById(
|
||||
this.ensureSuffix(query.chatId),
|
||||
);
|
||||
const messages = await chat.fetchMessages({
|
||||
limit: query.limit,
|
||||
});
|
||||
// Go over messages, download media, and convert to right format.
|
||||
const result = [];
|
||||
for (const message of messages) {
|
||||
result.push(await this.processIncomingMessage(message));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async setReaction(request: MessageReactionRequest) {
|
||||
const messageId = this.deserializeId(request.messageId);
|
||||
// Recreate instance to react on it
|
||||
const message = new MessageInstance(this.whatsapp);
|
||||
message.id = messageId;
|
||||
message._data = { id: messageId };
|
||||
|
||||
return message.react(request.reaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contacts methods
|
||||
*/
|
||||
getContact(query: ContactQuery) {
|
||||
return this.whatsapp
|
||||
.getContactById(this.ensureSuffix(query.contactId))
|
||||
.then(this.toWAContact);
|
||||
}
|
||||
|
||||
getContacts() {
|
||||
return this.whatsapp
|
||||
.getContacts()
|
||||
.then((contacts) => contacts.map(this.toWAContact));
|
||||
}
|
||||
|
||||
public async getContactAbout(query: ContactQuery) {
|
||||
const contact = await this.whatsapp.getContactById(
|
||||
this.ensureSuffix(query.contactId),
|
||||
);
|
||||
return { about: await contact.getAbout() };
|
||||
}
|
||||
|
||||
public async getContactProfilePicture(query: ContactQuery) {
|
||||
const contact = await this.whatsapp.getContactById(
|
||||
this.ensureSuffix(query.contactId),
|
||||
);
|
||||
return { profilePictureURL: await contact.getProfilePicUrl() };
|
||||
}
|
||||
|
||||
public async blockContact(request: ContactRequest) {
|
||||
const contact = await this.whatsapp.getContactById(
|
||||
this.ensureSuffix(request.contactId),
|
||||
);
|
||||
await contact.block();
|
||||
}
|
||||
|
||||
public async unblockContact(request: ContactRequest) {
|
||||
const contact = await this.whatsapp.getContactById(
|
||||
this.ensureSuffix(request.contactId),
|
||||
);
|
||||
await contact.unblock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Group methods
|
||||
*/
|
||||
public createGroup(request: CreateGroupRequest) {
|
||||
const participantIds = request.participants.map(
|
||||
(participant) => participant.id,
|
||||
);
|
||||
return this.whatsapp.createGroup(request.name, participantIds);
|
||||
}
|
||||
|
||||
public getGroups() {
|
||||
return this.whatsapp
|
||||
.getChats()
|
||||
.then((chats) => chats.filter((chat) => chat.isGroup));
|
||||
}
|
||||
|
||||
public getGroup(id) {
|
||||
return this.whatsapp.getChatById(id);
|
||||
}
|
||||
|
||||
public async deleteGroup(id) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
return groupChat.delete();
|
||||
}
|
||||
|
||||
public async leaveGroup(id) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
return groupChat.leave();
|
||||
}
|
||||
|
||||
public async setDescription(id, description) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
return groupChat.setDescription(description);
|
||||
}
|
||||
|
||||
public async setSubject(id, subject) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
return groupChat.setSubject(subject);
|
||||
}
|
||||
|
||||
public async getInviteCode(id): Promise<string> {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
return groupChat.getInviteCode();
|
||||
}
|
||||
|
||||
public async revokeInviteCode(id): Promise<string> {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
await groupChat.revokeInvite();
|
||||
return groupChat.getInviteCode();
|
||||
}
|
||||
|
||||
public async getParticipants(id) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
return groupChat.participants;
|
||||
}
|
||||
|
||||
public async addParticipants(id, request: ParticipantsRequest) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
const participantIds = request.participants.map(
|
||||
(participant) => participant.id,
|
||||
);
|
||||
return groupChat.addParticipants(participantIds);
|
||||
}
|
||||
|
||||
public async removeParticipants(id, request: ParticipantsRequest) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
const participantIds = request.participants.map(
|
||||
(participant) => participant.id,
|
||||
);
|
||||
return groupChat.removeParticipants(participantIds);
|
||||
}
|
||||
|
||||
public async promoteParticipantsToAdmin(id, request: ParticipantsRequest) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
const participantIds = request.participants.map(
|
||||
(participant) => participant.id,
|
||||
);
|
||||
return groupChat.promoteParticipants(participantIds);
|
||||
}
|
||||
|
||||
public async demoteParticipantsToUser(id, request: ParticipantsRequest) {
|
||||
const groupChat = (await this.whatsapp.getChatById(id)) as GroupChat;
|
||||
const participantIds = request.participants.map(
|
||||
(participant) => participant.id,
|
||||
);
|
||||
return groupChat.demoteParticipants(participantIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* END - Methods for API
|
||||
*/
|
||||
|
||||
subscribe(event, handler) {
|
||||
if (event === WAEvents.MESSAGE) {
|
||||
this.whatsapp.on(Events.MESSAGE_RECEIVED, (message) =>
|
||||
this.processIncomingMessage(message).then(handler),
|
||||
);
|
||||
} else if (event === WAEvents.MESSAGE_ANY) {
|
||||
this.whatsapp.on(Events.MESSAGE_CREATE, (message) =>
|
||||
this.processIncomingMessage(message).then(handler),
|
||||
);
|
||||
} else if (event === WAEvents.STATE_CHANGE) {
|
||||
this.whatsapp.on(Events.STATE_CHANGED, handler);
|
||||
} else if (event === WAEvents.MESSAGE_ACK) {
|
||||
// We do not download media here
|
||||
this.whatsapp.on(Events.MESSAGE_ACK, (message) =>
|
||||
this.toWAMessage(message).then(handler),
|
||||
);
|
||||
} else if (event === WAEvents.GROUP_JOIN) {
|
||||
this.whatsapp.on(Events.GROUP_JOIN, handler);
|
||||
} else if (event === WAEvents.GROUP_LEAVE) {
|
||||
this.whatsapp.on(Events.GROUP_LEAVE, handler);
|
||||
} else {
|
||||
throw new NotImplementedByEngineError(
|
||||
`Engine does not support webhook event: ${event}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private processIncomingMessage(message: Message) {
|
||||
return this.downloadMedia(message).then(this.toWAMessage);
|
||||
}
|
||||
|
||||
protected toWAMessage(message: Message): Promise<WAMessage> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve({
|
||||
id: message.id._serialized,
|
||||
timestamp: message.timestamp,
|
||||
from: message.from,
|
||||
fromMe: message.fromMe,
|
||||
to: message.to,
|
||||
body: message.body,
|
||||
// @ts-ignore
|
||||
hasMedia: Boolean(message.mediaUrl),
|
||||
// @ts-ignore
|
||||
mediaUrl: message.mediaUrl,
|
||||
// @ts-ignore
|
||||
ack: message.ack,
|
||||
location: message.location,
|
||||
vCards: message.vCards,
|
||||
_data: message.rawData,
|
||||
});
|
||||
}
|
||||
|
||||
protected toWAContact(contact: Contact) {
|
||||
// @ts-ignore
|
||||
contact.id = contact.id._serialized;
|
||||
return contact;
|
||||
}
|
||||
|
||||
protected async downloadMedia(message: Message) {
|
||||
if (!message.hasMedia) {
|
||||
return message;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
message.mediaUrl = await this.storage.save(
|
||||
message.id._serialized,
|
||||
'',
|
||||
undefined,
|
||||
);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,50 @@
|
||||
import {DOCS_URL} from "./exceptions";
|
||||
import {MediaStorage} from "./abc/storage.abc";
|
||||
import { DOCS_URL } from './exceptions';
|
||||
import { LocalSessionStorage, MediaStorage } from './abc/storage.abc';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
|
||||
export class MediaStorageCore implements MediaStorage {
|
||||
async save(messageId: string, mimetype: string, buffer: Buffer): Promise<string>{
|
||||
return Promise.resolve(`Media attachment's available only in WAHA Plus version. ${DOCS_URL}`)
|
||||
}
|
||||
async save(
|
||||
messageId: string,
|
||||
mimetype: string,
|
||||
buffer: Buffer,
|
||||
): Promise<string> {
|
||||
return Promise.resolve(
|
||||
`Media attachment's available only in WAHA Plus version. ${DOCS_URL}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class SessionStorageCore extends LocalSessionStorage {
|
||||
public sessionsFolder: string;
|
||||
|
||||
constructor(engine: string) {
|
||||
super(engine);
|
||||
this.sessionsFolder = path.join(os.tmpdir(), 'waha-');
|
||||
}
|
||||
|
||||
get engineFolder() {
|
||||
return path.join(this.sessionsFolder, this.engine);
|
||||
}
|
||||
|
||||
init() {
|
||||
fs.mkdirSync(this.engineFolder, { recursive: true });
|
||||
}
|
||||
|
||||
getFolderPath(name: string): string {
|
||||
return path.join(this.engineFolder, name);
|
||||
}
|
||||
|
||||
clean(sessionName: string) {
|
||||
const folder = this.getFolderPath(sessionName);
|
||||
fs.rmSync(folder, { recursive: true });
|
||||
}
|
||||
|
||||
getAll(): string[] {
|
||||
return fs
|
||||
.readdirSync(this.engineFolder, { withFileTypes: true })
|
||||
.filter((dirent) => dirent.isDirectory())
|
||||
.map((dirent) => dirent.name);
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,66 @@
|
||||
import {DocumentBuilder, SwaggerModule} from "@nestjs/swagger";
|
||||
import {INestApplication} from "@nestjs/common";
|
||||
import {VERSION} from "../version";
|
||||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { VERSION } from '../version';
|
||||
import { WhatsappConfigService } from '../config.service';
|
||||
|
||||
export class SwaggerModuleCore {
|
||||
configure(app: INestApplication) {
|
||||
this.setUpAuth(app)
|
||||
configure(app: INestApplication) {
|
||||
this.setUpAuth(app);
|
||||
const builder = new DocumentBuilder();
|
||||
|
||||
const options = new DocumentBuilder()
|
||||
.setTitle('WAHA - WhatsApp HTTP API')
|
||||
.setDescription('WhatsApp HTTP API that you can configure in a click!')
|
||||
.setExternalDoc("Documentation", "https://waha.devlike.pro/")
|
||||
.setVersion(VERSION.version)
|
||||
.addTag('sessions', 'Control WhatsApp sessions')
|
||||
.addTag('screenshot', 'Get screenshot of WhatsApp and show QR code')
|
||||
.addTag('chatting', 'Chat methods')
|
||||
.addTag(
|
||||
'contacts',
|
||||
`Contacts methods.<br>
|
||||
builder
|
||||
.setTitle('WAHA - WhatsApp HTTP API')
|
||||
.setDescription('WhatsApp HTTP API that you can configure in a click!')
|
||||
.setExternalDoc('Documentation', 'https://waha.devlike.pro/')
|
||||
.setVersion(VERSION.version)
|
||||
.addTag('sessions', 'Control WhatsApp sessions')
|
||||
.addTag('screenshot', 'Get screenshot of WhatsApp and show QR code')
|
||||
.addTag('chatting', 'Chat methods')
|
||||
.addTag(
|
||||
'contacts',
|
||||
`Contacts methods.<br>
|
||||
Use phone number (without +) or phone number and \`@c.us\` at the end as \`contactId\`.<br>
|
||||
'E.g: \`12312312310\` OR \`12312312310@c.us\`<br>`
|
||||
)
|
||||
.addTag(
|
||||
'groups',
|
||||
`Groups methods.<br>`
|
||||
)
|
||||
.addTag('other', 'Other methods')
|
||||
.addApiKey({
|
||||
type: 'apiKey',
|
||||
description: 'Your secret api key',
|
||||
name: 'X-Api-Key'
|
||||
}
|
||||
)
|
||||
.build();
|
||||
|
||||
const document = SwaggerModule.createDocument(app, options);
|
||||
SwaggerModule.setup('', app, document);
|
||||
'E.g: \`12312312310\` OR \`12312312310@c.us\`<br>`,
|
||||
)
|
||||
.addTag('groups', `Groups methods.<br>`)
|
||||
.addTag('other', 'Other methods')
|
||||
.addApiKey({
|
||||
type: 'apiKey',
|
||||
description: 'Your secret api key',
|
||||
name: 'X-Api-Key',
|
||||
});
|
||||
|
||||
const config = app.get(WhatsappConfigService);
|
||||
if (config.getSwaggerAdvancedConfigEnabled()) {
|
||||
builder.addServer('{protocol}://{host}:{port}/{baseUrl}', '', {
|
||||
protocol: {
|
||||
default: 'http',
|
||||
enum: ['http', 'https'],
|
||||
description: 'The protocol used to access the server.',
|
||||
},
|
||||
host: {
|
||||
default: config.hostname,
|
||||
description: 'The hostname or IP address of the server.',
|
||||
},
|
||||
port: {
|
||||
default: config.port,
|
||||
description:
|
||||
'The port number on which the server is listening for requests',
|
||||
},
|
||||
baseUrl: {
|
||||
default: '',
|
||||
description:
|
||||
'The base URL path for all API endpoints. This can be used to group related endpoints together under a common path.',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
protected setUpAuth(app: INestApplication) {
|
||||
return undefined
|
||||
}
|
||||
const options = builder.build();
|
||||
const document = SwaggerModule.createDocument(app, options);
|
||||
SwaggerModule.setup('', app, document);
|
||||
}
|
||||
|
||||
protected setUpAuth(app: INestApplication) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
+72
-65
@@ -1,76 +1,83 @@
|
||||
import {WAHAInternalEvent, WhatsappSession} from "./abc/session.abc";
|
||||
import {ConsoleLogger} from "@nestjs/common";
|
||||
import {WAEvents} from "../structures/enums.dto";
|
||||
import {WAWebhook} from "../structures/responses.dto";
|
||||
import {NotImplementedByEngineError} from "./exceptions";
|
||||
import {WebhookConductor} from "./abc/webhooks.abc";
|
||||
import { WAHAInternalEvent, WhatsappSession } from './abc/session.abc';
|
||||
import { ConsoleLogger } from '@nestjs/common';
|
||||
import { WAEvents } from '../structures/enums.dto';
|
||||
import { WAWebhook } from '../structures/responses.dto';
|
||||
import { NotImplementedByEngineError } from './exceptions';
|
||||
import { WebhookConductor } from './abc/webhooks.abc';
|
||||
import request = require('request');
|
||||
|
||||
|
||||
export class WebhookConductorCore implements WebhookConductor {
|
||||
constructor(protected log: ConsoleLogger, private readonly url, private readonly events: WAEvents[] | string[]) {
|
||||
this.url = url
|
||||
this.events = this.getSuitableEvents(events)
|
||||
this.log = log
|
||||
constructor(
|
||||
protected log: ConsoleLogger,
|
||||
private readonly url,
|
||||
private readonly events: WAEvents[] | string[],
|
||||
) {
|
||||
this.url = url;
|
||||
this.events = this.getSuitableEvents(events);
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
private getSuitableEvents(events: WAEvents[] | string[]) {
|
||||
const allEvents = Object.values(WAEvents);
|
||||
|
||||
// Enable all events if * in the events
|
||||
// @ts-ignore
|
||||
if (events.includes('*')) {
|
||||
return allEvents;
|
||||
}
|
||||
|
||||
private getSuitableEvents(events: WAEvents[] | string[]) {
|
||||
const allEvents = Object.values(WAEvents)
|
||||
// Get only known events, log and ignore others
|
||||
const rightEvents = [];
|
||||
for (const event of events) {
|
||||
// @ts-ignore
|
||||
if (!allEvents.includes(event)) {
|
||||
this.log.error(`Unknown event for webhook: '${event}'`);
|
||||
continue;
|
||||
}
|
||||
rightEvents.push(event);
|
||||
}
|
||||
return rightEvents;
|
||||
}
|
||||
|
||||
// Enable all events if * in the events
|
||||
// @ts-ignore
|
||||
if (events.includes("*")) {
|
||||
return allEvents
|
||||
public configure(session: WhatsappSession) {
|
||||
this.log.log('Configuring webhooks...');
|
||||
for (const event of this.events) {
|
||||
try {
|
||||
session.subscribe(event, (data: any) =>
|
||||
this.callWebhook(event, session, data, this.url),
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof NotImplementedByEngineError) {
|
||||
this.log.error(error);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Get only known events, log and ignore others
|
||||
const rightEvents = []
|
||||
for (const event of events) {
|
||||
// @ts-ignore
|
||||
if (!allEvents.includes(event)) {
|
||||
this.log.error(`Unknown event for webhook: '${event}'`)
|
||||
continue
|
||||
}
|
||||
rightEvents.push(event)
|
||||
}
|
||||
return rightEvents
|
||||
}
|
||||
this.log.log(`Event '${event}' is enabled for url: ${this.url}`);
|
||||
}
|
||||
this.log.log('Webhooks were configured.');
|
||||
}
|
||||
|
||||
public configure(session: WhatsappSession) {
|
||||
this.log.log('Configuring webhooks...')
|
||||
for (const event of this.events) {
|
||||
try {
|
||||
session.subscribe(event, (data: any) => this.callWebhook(event, session, data, this.url))
|
||||
} catch (error) {
|
||||
if (error instanceof NotImplementedByEngineError) {
|
||||
this.log.error(error)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
this.log.log(`Event '${event}' is enabled for url: ${this.url}`)
|
||||
}
|
||||
this.log.log('Webhooks were configured.')
|
||||
}
|
||||
public callWebhook(event, session: WhatsappSession, data: any, url) {
|
||||
const json: WAWebhook = {
|
||||
event: event,
|
||||
session: session.name,
|
||||
payload: data,
|
||||
engine: session.engine,
|
||||
};
|
||||
this.log.log(`Sending POST to ${url}...`);
|
||||
this.log.debug(`POST DATA: ${JSON.stringify(json)}`);
|
||||
this.post(json, url);
|
||||
}
|
||||
|
||||
public callWebhook(event, session: WhatsappSession, data: any, url) {
|
||||
const json: WAWebhook = {event: event, session: session.name, payload: data}
|
||||
this.log.log(`Sending POST to ${url}...`)
|
||||
this.log.debug(`POST DATA: ${JSON.stringify(json)}`)
|
||||
this.post(json, url)
|
||||
}
|
||||
|
||||
protected post(json, url) {
|
||||
request.post(
|
||||
url,
|
||||
{json: json},
|
||||
(error, res, body) => {
|
||||
if (error) {
|
||||
this.log.error(error)
|
||||
return
|
||||
}
|
||||
this.log.log(`POST request was sent with status code: ${res.statusCode}`)
|
||||
this.log.verbose(`Response: ${JSON.stringify(body)}`)
|
||||
})
|
||||
}
|
||||
protected post(json, url) {
|
||||
request.post(url, { json: json }, (error, res, body) => {
|
||||
if (error) {
|
||||
this.log.error(error);
|
||||
return;
|
||||
}
|
||||
this.log.log(`POST request was sent with status code: ${res.statusCode}`);
|
||||
this.log.verbose(`Response: ${JSON.stringify(body)}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export function parseBool(value: any): boolean {
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
if (value.toLowerCase() === 'true' || value.toLowerCase() === '1') {
|
||||
return true;
|
||||
}
|
||||
if (value.toLowerCase() === 'false' || value.toLowerCase() === '0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
console.error(
|
||||
'parseBool got an unexpected value:',
|
||||
value,
|
||||
'(accepted values : "true", "false")',
|
||||
);
|
||||
throw new Error(
|
||||
'Error: parseBool got unexpected value - use "true" or "false" values',
|
||||
);
|
||||
}
|
||||
+41
-37
@@ -1,49 +1,53 @@
|
||||
import {NestFactory} from '@nestjs/core';
|
||||
import {WhatsappConfigService} from "./config.service";
|
||||
import {AllExceptionsFilter} from "./api/exception.filter";
|
||||
import {getWAHAVersion, VERSION, WAHAVersion} from "./version";
|
||||
import {AppModuleCore} from "./core/app.module.core";
|
||||
import {SwaggerModuleCore} from "./core/swagger.module.core";
|
||||
import {json, urlencoded} from "express";
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { WhatsappConfigService } from './config.service';
|
||||
import { AllExceptionsFilter } from './api/exception.filter';
|
||||
import { getWAHAVersion, VERSION, WAHAVersion } from './version';
|
||||
import { AppModuleCore } from './core/app.module.core';
|
||||
import { SwaggerModuleCore } from './core/swagger.module.core';
|
||||
import { json, urlencoded } from 'express';
|
||||
|
||||
async function loadModules(): Promise<[typeof AppModuleCore, typeof SwaggerModuleCore]> {
|
||||
const version = getWAHAVersion()
|
||||
console.log(`WAHA (WhatsApp HTTP API) - Running ${version} version...`)
|
||||
async function loadModules(): Promise<
|
||||
[typeof AppModuleCore, typeof SwaggerModuleCore]
|
||||
> {
|
||||
const version = getWAHAVersion();
|
||||
console.log(`WAHA (WhatsApp HTTP API) - Running ${version} version...`);
|
||||
|
||||
if (version === WAHAVersion.CORE) {
|
||||
const {AppModuleCore} = await import("./core/app.module.core")
|
||||
const {SwaggerModuleCore} = await import("./core/swagger.module.core")
|
||||
return [AppModuleCore, SwaggerModuleCore]
|
||||
}
|
||||
// Ignore if it's core version - there's no plus module
|
||||
// @ts-ignore
|
||||
const {AppModulePlus} = await import("./plus/app.module.plus")
|
||||
// @ts-ignore
|
||||
const {SwaggerModulePlus} = await import("./plus/swagger.module.plus")
|
||||
return [AppModulePlus, SwaggerModulePlus]
|
||||
if (version === WAHAVersion.CORE) {
|
||||
const { AppModuleCore } = await import('./core/app.module.core');
|
||||
const { SwaggerModuleCore } = await import('./core/swagger.module.core');
|
||||
return [AppModuleCore, SwaggerModuleCore];
|
||||
}
|
||||
// Ignore if it's core version - there's no plus module
|
||||
// @ts-ignore
|
||||
const { AppModulePlus } = await import('./plus/app.module.plus');
|
||||
// @ts-ignore
|
||||
const { SwaggerModulePlus } = await import('./plus/swagger.module.plus');
|
||||
return [AppModulePlus, SwaggerModulePlus];
|
||||
}
|
||||
|
||||
async function bootstrap() {
|
||||
const [AppModule, SwaggerModule] = await loadModules()
|
||||
const app = await NestFactory.create(AppModule, {
|
||||
logger: process.env.DEBUG != undefined ? ['log', 'debug', 'error', 'verbose', 'warn'] :
|
||||
['log', 'error', 'warn'],
|
||||
});
|
||||
const [AppModule, SwaggerModule] = await loadModules();
|
||||
const app = await NestFactory.create(AppModule, {
|
||||
logger:
|
||||
process.env.DEBUG != undefined
|
||||
? ['log', 'debug', 'error', 'verbose', 'warn']
|
||||
: ['log', 'error', 'warn'],
|
||||
});
|
||||
|
||||
app.enableShutdownHooks();
|
||||
app.useGlobalFilters(new AllExceptionsFilter());
|
||||
app.enableShutdownHooks();
|
||||
app.useGlobalFilters(new AllExceptionsFilter());
|
||||
|
||||
// Allow to send big body - for images and attachments
|
||||
app.use(json({limit: '50mb'}));
|
||||
app.use(urlencoded({limit: '50mb'}));
|
||||
// Allow to send big body - for images and attachments
|
||||
app.use(json({ limit: '50mb' }));
|
||||
app.use(urlencoded({ limit: '50mb', extended: false }));
|
||||
|
||||
// Configure swagger
|
||||
const swagger = new SwaggerModule()
|
||||
swagger.configure(app)
|
||||
// Configure swagger
|
||||
const swagger = new SwaggerModule();
|
||||
swagger.configure(app);
|
||||
|
||||
const config = app.get(WhatsappConfigService);
|
||||
await app.listen(config.port);
|
||||
console.log(`WhatsApp HTTP API is running on: ${await app.getUrl()}`);
|
||||
const config = app.get(WhatsappConfigService);
|
||||
await app.listen(config.port);
|
||||
console.log(`WhatsApp HTTP API is running on: ${await app.getUrl()}`);
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
@@ -1,13 +1,13 @@
|
||||
import {IsNotEmpty} from "class-validator";
|
||||
import { IsNotEmpty } from 'class-validator';
|
||||
|
||||
export const WHATSAPP_DEFAULT_SESSION_NAME = "default"
|
||||
export const WHATSAPP_DEFAULT_SESSION_NAME = 'default';
|
||||
|
||||
/**
|
||||
* Queries
|
||||
*/
|
||||
export class SessionQuery {
|
||||
@IsNotEmpty()
|
||||
session: string = WHATSAPP_DEFAULT_SESSION_NAME;
|
||||
@IsNotEmpty()
|
||||
session: string = WHATSAPP_DEFAULT_SESSION_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -15,5 +15,5 @@ export class SessionQuery {
|
||||
*/
|
||||
|
||||
export class SessionBaseRequest {
|
||||
session = WHATSAPP_DEFAULT_SESSION_NAME
|
||||
session = WHATSAPP_DEFAULT_SESSION_NAME;
|
||||
}
|
||||
+135
-131
@@ -1,217 +1,221 @@
|
||||
import {IsNotEmpty, IsString, IsOptional, IsNumber} from "class-validator";
|
||||
import {ApiExtraModels, ApiProperty, getSchemaPath} from "@nestjs/swagger";
|
||||
import {SessionBaseRequest, SessionQuery} from "./base.dto";
|
||||
|
||||
import { IsNotEmpty, IsString, IsOptional, IsNumber } from 'class-validator';
|
||||
import { ApiExtraModels, ApiProperty, getSchemaPath } from '@nestjs/swagger';
|
||||
import { SessionBaseRequest, SessionQuery } from './base.dto';
|
||||
|
||||
/**
|
||||
* Queries
|
||||
*/
|
||||
export class CheckNumberStatusQuery extends SessionQuery {
|
||||
@IsString()
|
||||
phone: string
|
||||
@IsString()
|
||||
phone: string;
|
||||
}
|
||||
|
||||
export class MessageTextQuery extends SessionQuery {
|
||||
@IsString()
|
||||
phone: string
|
||||
@IsString()
|
||||
text: string
|
||||
@IsString()
|
||||
phone: string;
|
||||
@IsString()
|
||||
text: string;
|
||||
}
|
||||
|
||||
export class ChatQuery extends SessionQuery {
|
||||
@ApiProperty({
|
||||
example: '11111111111@c.us',
|
||||
})
|
||||
chatId: string
|
||||
@ApiProperty({
|
||||
example: '11111111111@c.us',
|
||||
})
|
||||
chatId: string;
|
||||
}
|
||||
|
||||
export class GetMessageQuery extends ChatQuery {
|
||||
@IsNumber()
|
||||
limit: number
|
||||
@IsNumber()
|
||||
limit: number;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requests
|
||||
*/
|
||||
export class ChatRequest extends SessionBaseRequest {
|
||||
@ApiProperty({
|
||||
example: '11111111111@c.us',
|
||||
})
|
||||
chatId: string
|
||||
@ApiProperty({
|
||||
example: '11111111111@c.us',
|
||||
})
|
||||
chatId: string;
|
||||
}
|
||||
|
||||
export class SendSeenRequest extends ChatRequest {
|
||||
@ApiProperty({
|
||||
example: 'false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
required: false,
|
||||
description: "NOWEB engine only - it's important to mark ALL messages as seen"
|
||||
})
|
||||
messageId?: string
|
||||
@ApiProperty({
|
||||
example: 'false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
required: false,
|
||||
description:
|
||||
"NOWEB engine only - it's important to mark ALL messages as seen",
|
||||
})
|
||||
messageId?: string;
|
||||
|
||||
@ApiProperty({
|
||||
example: '11111111111@c.us',
|
||||
required: false,
|
||||
description: "NOWEB engine only - the ID of the user that sent the message (undefined for individual chats)"
|
||||
})
|
||||
participant?: string
|
||||
@ApiProperty({
|
||||
example: '11111111111@c.us',
|
||||
required: false,
|
||||
description:
|
||||
'NOWEB engine only - the ID of the user that sent the message (undefined for individual chats)',
|
||||
})
|
||||
participant?: string;
|
||||
}
|
||||
|
||||
export class MessageRequest extends SessionBaseRequest {
|
||||
@ApiProperty({
|
||||
example: "false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA",
|
||||
})
|
||||
messageId: string
|
||||
@ApiProperty({
|
||||
example: 'false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
})
|
||||
messageId: string;
|
||||
}
|
||||
|
||||
export class MessageContactVcardRequest extends ChatRequest {
|
||||
contactsId: string;
|
||||
name: string
|
||||
contactsId: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class MessageTextRequest extends ChatRequest {
|
||||
text = "Hi there!"
|
||||
text = 'Hi there!';
|
||||
}
|
||||
|
||||
export class Button {
|
||||
id: string
|
||||
text: string
|
||||
id: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export class MessageTextButtonsRequest extends ChatRequest {
|
||||
title: string;
|
||||
footer?: string
|
||||
buttons?: Array<Button>;
|
||||
title: string;
|
||||
footer?: string;
|
||||
buttons?: Array<Button>;
|
||||
}
|
||||
|
||||
export class MessageReplyRequest extends ChatRequest {
|
||||
text = "Reply text"
|
||||
@ApiProperty({
|
||||
example: 'false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
})
|
||||
reply_to: string;
|
||||
text = 'Reply text';
|
||||
@ApiProperty({
|
||||
example: 'false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
})
|
||||
reply_to: string;
|
||||
}
|
||||
|
||||
export class MessageLocationRequest extends ChatRequest {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
title: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export class RemoteFile {
|
||||
@ApiProperty({
|
||||
description: "MIME type of the attachment.",
|
||||
example: 'image/jpeg',
|
||||
})
|
||||
mimetype: string
|
||||
@ApiProperty({
|
||||
description: 'MIME type of the attachment.',
|
||||
example: 'image/jpeg',
|
||||
})
|
||||
mimetype: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Document file name. Value can be null",
|
||||
example: 'filename.jpg',
|
||||
})
|
||||
filename?: string | null
|
||||
@ApiProperty({
|
||||
description: 'Document file name. Value can be null',
|
||||
example: 'filename.jpg',
|
||||
})
|
||||
filename?: string | null;
|
||||
|
||||
@ApiProperty({
|
||||
example: 'https://github.com/devlikeapro/whatsapp-http-api/raw/core/examples/dev.likeapro.jpg',
|
||||
})
|
||||
url: string
|
||||
@ApiProperty({
|
||||
example:
|
||||
'https://github.com/devlikeapro/whatsapp-http-api/raw/core/examples/dev.likeapro.jpg',
|
||||
})
|
||||
url: string;
|
||||
}
|
||||
|
||||
export class BinaryFile {
|
||||
@ApiProperty({
|
||||
description: "MIME type of the attachment.",
|
||||
example: 'image/jpeg',
|
||||
})
|
||||
mimetype: string
|
||||
@ApiProperty({
|
||||
description: 'MIME type of the attachment.',
|
||||
example: 'image/jpeg',
|
||||
})
|
||||
mimetype: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Document file name. Optional",
|
||||
example: 'filename.jpeg',
|
||||
})
|
||||
filename?: string | null
|
||||
@ApiProperty({
|
||||
description: 'Document file name. Optional',
|
||||
example: 'filename.jpeg',
|
||||
})
|
||||
filename?: string | null;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Base64-encoded data of the file",
|
||||
example: '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',
|
||||
})
|
||||
data: string
|
||||
@ApiProperty({
|
||||
description: 'Base64-encoded data of the file',
|
||||
example:
|
||||
'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',
|
||||
})
|
||||
data: string;
|
||||
}
|
||||
|
||||
@ApiExtraModels(BinaryFile, RemoteFile)
|
||||
class FileRequest extends ChatRequest {
|
||||
@ApiProperty({
|
||||
oneOf: [
|
||||
{$ref: getSchemaPath(BinaryFile)},
|
||||
{$ref: getSchemaPath(RemoteFile)},
|
||||
],
|
||||
})
|
||||
file: BinaryFile | RemoteFile
|
||||
@ApiProperty({
|
||||
oneOf: [
|
||||
{ $ref: getSchemaPath(BinaryFile) },
|
||||
{ $ref: getSchemaPath(RemoteFile) },
|
||||
],
|
||||
})
|
||||
file: BinaryFile | RemoteFile;
|
||||
}
|
||||
|
||||
export class MessageImageRequest extends FileRequest {
|
||||
caption: string;
|
||||
caption: string;
|
||||
}
|
||||
|
||||
export class MessageFileRequest extends FileRequest {
|
||||
caption: string;
|
||||
}
|
||||
|
||||
export class VoiceBinaryFile {
|
||||
@ApiProperty({
|
||||
description: "MIME type of the attachment.",
|
||||
})
|
||||
mimetype = "audio/ogg; codecs=opus"
|
||||
@ApiProperty({
|
||||
description: 'MIME type of the attachment.',
|
||||
})
|
||||
mimetype = 'audio/ogg; codecs=opus';
|
||||
|
||||
@ApiProperty({
|
||||
description: "Document file name. Optional",
|
||||
})
|
||||
filename = "voice-message.mp3"
|
||||
@ApiProperty({
|
||||
description: 'Document file name. Optional',
|
||||
})
|
||||
filename = 'voice-message.mp3';
|
||||
|
||||
@ApiProperty({
|
||||
description: "Base64-encoded data of the file",
|
||||
example: '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
Line truncated
|
||||
})
|
||||
data: string
|
||||
@ApiProperty({
|
||||
description: 'Base64-encoded data of the file',
|
||||
example:
|
||||
'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
Line truncated
|
||||
})
|
||||
data: string;
|
||||
}
|
||||
|
||||
export class VoiceRemoteFile {
|
||||
@ApiProperty({
|
||||
description: "MIME type of the attachment.",
|
||||
})
|
||||
mimetype = "audio/ogg; codecs=opus"
|
||||
@ApiProperty({
|
||||
description: 'MIME type of the attachment.',
|
||||
})
|
||||
mimetype = 'audio/ogg; codecs=opus';
|
||||
|
||||
@ApiProperty({
|
||||
description: "Document file name. Optional",
|
||||
})
|
||||
filename = "voice-message.mp3"
|
||||
|
||||
@ApiProperty({
|
||||
example: 'https://github.com/devlikeapro/whatsapp-http-api/raw/core/examples/dev.likeapro.mp3',
|
||||
})
|
||||
url: string
|
||||
@ApiProperty({
|
||||
description: 'Document file name. Optional',
|
||||
})
|
||||
filename = 'voice-message.mp3';
|
||||
|
||||
@ApiProperty({
|
||||
example:
|
||||
'https://github.com/devlikeapro/whatsapp-http-api/raw/core/examples/dev.likeapro.mp3',
|
||||
})
|
||||
url: string;
|
||||
}
|
||||
|
||||
@ApiExtraModels(VoiceBinaryFile, VoiceRemoteFile)
|
||||
export class MessageVoiceRequest extends ChatRequest {
|
||||
@ApiProperty({
|
||||
oneOf: [
|
||||
{$ref: getSchemaPath(VoiceBinaryFile)},
|
||||
{$ref: getSchemaPath(VoiceRemoteFile)},
|
||||
],
|
||||
})
|
||||
file: VoiceBinaryFile | VoiceRemoteFile
|
||||
@ApiProperty({
|
||||
oneOf: [
|
||||
{ $ref: getSchemaPath(VoiceBinaryFile) },
|
||||
{ $ref: getSchemaPath(VoiceRemoteFile) },
|
||||
],
|
||||
})
|
||||
file: VoiceBinaryFile | VoiceRemoteFile;
|
||||
}
|
||||
|
||||
export class MessageLinkPreviewRequest extends ChatRequest {
|
||||
url: string;
|
||||
title: string;
|
||||
url: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export class MessageReactionRequest extends MessageRequest {
|
||||
@ApiProperty({
|
||||
description: "Emoji to react with. Send an empty string to remove the reaction",
|
||||
example: '👍',
|
||||
})
|
||||
reaction: string
|
||||
@ApiProperty({
|
||||
description:
|
||||
'Emoji to react with. Send an empty string to remove the reaction',
|
||||
example: '👍',
|
||||
})
|
||||
reaction: string;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
import {IsString} from "class-validator";
|
||||
import {SessionBaseRequest, SessionQuery} from "./base.dto";
|
||||
|
||||
import { IsString } from 'class-validator';
|
||||
import { SessionBaseRequest, SessionQuery } from './base.dto';
|
||||
|
||||
/**
|
||||
* Queries
|
||||
*/
|
||||
|
||||
export class ContactQuery extends SessionQuery {
|
||||
@IsString()
|
||||
contactId: string
|
||||
@IsString()
|
||||
contactId: string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requests
|
||||
*/
|
||||
|
||||
export class ContactRequest extends SessionBaseRequest {
|
||||
@IsString()
|
||||
contactId: string
|
||||
@IsString()
|
||||
contactId: string;
|
||||
}
|
||||
+14
-13
@@ -1,23 +1,24 @@
|
||||
export const SECOND = 1000;
|
||||
|
||||
export enum WAEvents {
|
||||
MESSAGE = "message",
|
||||
MESSAGE_ANY = "message.any",
|
||||
MESSAGE_ACK = "message.ack",
|
||||
STATE_CHANGE = "state.change",
|
||||
GROUP_JOIN = "group.join",
|
||||
GROUP_LEAVE = "group.leave",
|
||||
MESSAGE = 'message',
|
||||
MESSAGE_ANY = 'message.any',
|
||||
MESSAGE_ACK = 'message.ack',
|
||||
STATE_CHANGE = 'state.change',
|
||||
GROUP_JOIN = 'group.join',
|
||||
GROUP_LEAVE = 'group.leave',
|
||||
}
|
||||
|
||||
export enum WhatsappStatus {
|
||||
STARTING = "STARTING",
|
||||
SCAN_QR_CODE = "SCAN_QR_CODE",
|
||||
WORKING = "WORKING",
|
||||
FAILED = "FAILED",
|
||||
STOPPED = 'STOPPED',
|
||||
STARTING = 'STARTING',
|
||||
SCAN_QR_CODE = 'SCAN_QR_CODE',
|
||||
WORKING = 'WORKING',
|
||||
FAILED = 'FAILED',
|
||||
}
|
||||
|
||||
export enum WhatsappEngine {
|
||||
VENOM = "VENOM",
|
||||
WEBJS = "WEBJS",
|
||||
NOWEB = "NOWEB",
|
||||
VENOM = 'VENOM',
|
||||
WEBJS = 'WEBJS',
|
||||
NOWEB = 'NOWEB',
|
||||
}
|
||||
@@ -1,40 +1,39 @@
|
||||
import {IsArray, IsString} from "class-validator";
|
||||
import { IsArray, IsString } from 'class-validator';
|
||||
|
||||
/**
|
||||
* Structures
|
||||
*/
|
||||
export class Participant {
|
||||
@IsString()
|
||||
id: string
|
||||
@IsString()
|
||||
id: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Requests
|
||||
*/
|
||||
|
||||
export class ParticipantsRequest {
|
||||
@IsArray()
|
||||
participants: Array<Participant>
|
||||
@IsArray()
|
||||
participants: Array<Participant>;
|
||||
}
|
||||
|
||||
export class DescriptionRequest {
|
||||
@IsString()
|
||||
description: string
|
||||
@IsString()
|
||||
description: string;
|
||||
}
|
||||
export class SubjectRequest {
|
||||
@IsString()
|
||||
subject: string
|
||||
@IsString()
|
||||
subject: string;
|
||||
}
|
||||
|
||||
export class CreateGroupRequest {
|
||||
@IsString()
|
||||
name: string
|
||||
@IsString()
|
||||
name: string;
|
||||
|
||||
@IsArray()
|
||||
participants: Array<Participant>
|
||||
@IsArray()
|
||||
participants: Array<Participant>;
|
||||
}
|
||||
+109
-105
@@ -1,144 +1,148 @@
|
||||
import {ApiProperty} from "@nestjs/swagger";
|
||||
import {WAEvents} from "./enums.dto";
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { WAEvents, WhatsappEngine } from './enums.dto';
|
||||
|
||||
export class WANumberExistResult {
|
||||
numberExists: boolean
|
||||
numberExists: boolean;
|
||||
}
|
||||
|
||||
|
||||
export class WAGroupNotification {
|
||||
@ApiProperty({
|
||||
description: "ID that represents the groupNotification",
|
||||
})
|
||||
id: any
|
||||
@ApiProperty({
|
||||
description: 'ID that represents the groupNotification',
|
||||
})
|
||||
id: any;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Unix timestamp for when the groupNotification was created",
|
||||
})
|
||||
timestamp: number
|
||||
@ApiProperty({
|
||||
description: 'Unix timestamp for when the groupNotification was created',
|
||||
})
|
||||
timestamp: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: "ID for the Chat that this groupNotification was sent for",
|
||||
})
|
||||
chatId: string
|
||||
@ApiProperty({
|
||||
description: 'ID for the Chat that this groupNotification was sent for',
|
||||
})
|
||||
chatId: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'ContactId for the user that produced the GroupNotification',
|
||||
})
|
||||
author: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "ContactId for the user that produced the GroupNotification",
|
||||
})
|
||||
author: string
|
||||
@ApiProperty({
|
||||
description: 'Extra content',
|
||||
})
|
||||
body: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Extra content",
|
||||
})
|
||||
body: string
|
||||
|
||||
@ApiProperty({
|
||||
description: "Contact IDs for the users that were affected by this GroupNotification",
|
||||
})
|
||||
recipientIds: string[]
|
||||
@ApiProperty({
|
||||
description:
|
||||
'Contact IDs for the users that were affected by this GroupNotification',
|
||||
})
|
||||
recipientIds: string[];
|
||||
}
|
||||
|
||||
export enum WAMessageAck {
|
||||
ACK_ERROR = -1,
|
||||
ACK_PENDING = 0,
|
||||
ACK_SERVER = 1,
|
||||
ACK_DEVICE = 2,
|
||||
ACK_READ = 3,
|
||||
ACK_PLAYED = 4,
|
||||
ACK_ERROR = -1,
|
||||
ACK_PENDING = 0,
|
||||
ACK_SERVER = 1,
|
||||
ACK_DEVICE = 2,
|
||||
ACK_READ = 3,
|
||||
ACK_PLAYED = 4,
|
||||
}
|
||||
|
||||
export class WALocation {
|
||||
description?: string | null
|
||||
latitude: string
|
||||
longitude: string
|
||||
description?: string | null;
|
||||
latitude: string;
|
||||
longitude: string;
|
||||
}
|
||||
|
||||
|
||||
export class WAMessage {
|
||||
@ApiProperty({
|
||||
description: "Message ID",
|
||||
example: "false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA"
|
||||
})
|
||||
id: string
|
||||
@ApiProperty({
|
||||
description: 'Message ID',
|
||||
example: 'false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA',
|
||||
})
|
||||
id: string;
|
||||
|
||||
/** */
|
||||
@ApiProperty({
|
||||
description: "Unix timestamp for when the message was created",
|
||||
example: 1666943582
|
||||
})
|
||||
timestamp: number
|
||||
/** */
|
||||
@ApiProperty({
|
||||
description: 'Unix timestamp for when the message was created',
|
||||
example: 1666943582,
|
||||
})
|
||||
timestamp: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: "ID for the Chat that this message was sent to, except if the message was sent by the current user "
|
||||
})
|
||||
from: string
|
||||
@ApiProperty({
|
||||
description:
|
||||
'ID for the Chat that this message was sent to, except if the message was sent by the current user ',
|
||||
})
|
||||
from: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Indicates if the message was sent by the current user"
|
||||
})
|
||||
fromMe: boolean
|
||||
@ApiProperty({
|
||||
description: 'Indicates if the message was sent by the current user',
|
||||
})
|
||||
fromMe: boolean;
|
||||
|
||||
@ApiProperty({
|
||||
description: `
|
||||
@ApiProperty({
|
||||
description: `
|
||||
* 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.
|
||||
`
|
||||
})
|
||||
to: string
|
||||
`,
|
||||
})
|
||||
to: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "For groups - participant who sent the message"
|
||||
})
|
||||
participant: string
|
||||
@ApiProperty({
|
||||
description: 'For groups - participant who sent the message',
|
||||
})
|
||||
participant: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Message content"
|
||||
})
|
||||
body: string
|
||||
@ApiProperty({
|
||||
description: 'Message content',
|
||||
})
|
||||
body: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Indicates if the message has media available for download"
|
||||
})
|
||||
hasMedia: boolean
|
||||
@ApiProperty({
|
||||
description: 'Indicates if the message has media available for download',
|
||||
})
|
||||
hasMedia: boolean;
|
||||
|
||||
@ApiProperty({
|
||||
description: "The URL for the media in the message if any",
|
||||
example: "http://localhost:3000/api/files/false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA.oga"
|
||||
})
|
||||
mediaUrl: string
|
||||
@ApiProperty({
|
||||
description: 'The URL for the media in the message if any',
|
||||
example:
|
||||
'http://localhost:3000/api/files/false_11111111111@c.us_AAAAAAAAAAAAAAAAAAAA.oga',
|
||||
})
|
||||
mediaUrl: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "ACK status for the message"
|
||||
})
|
||||
ack: WAMessageAck
|
||||
@ApiProperty({
|
||||
description: 'ACK status for the message',
|
||||
})
|
||||
ack: WAMessageAck;
|
||||
|
||||
@ApiProperty({
|
||||
description: "If the message was sent to a group, this field will contain the user that sent the message."
|
||||
})
|
||||
author?: string;
|
||||
@ApiProperty({
|
||||
description:
|
||||
'If the message was sent to a group, this field will contain the user that sent the message.',
|
||||
})
|
||||
author?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: "Location information contained in the message, if the message is type \"location\""
|
||||
})
|
||||
location?: WALocation
|
||||
@ApiProperty({
|
||||
description:
|
||||
'Location information contained in the message, if the message is type "location"',
|
||||
})
|
||||
location?: WALocation;
|
||||
|
||||
@ApiProperty({
|
||||
description: "List of vCards contained in the message."
|
||||
})
|
||||
vCards?: string[]
|
||||
@ApiProperty({
|
||||
description: 'List of vCards contained in the message.',
|
||||
})
|
||||
vCards?: string[];
|
||||
|
||||
/** Returns message in a raw format */
|
||||
@ApiProperty({
|
||||
description: "Message in a raw format that we get from WhatsApp. May be changed anytime, use it with caution! It depends a lot on the underlying backend."
|
||||
})
|
||||
_data?: any
|
||||
/** Returns message in a raw format */
|
||||
@ApiProperty({
|
||||
description:
|
||||
'Message in a raw format that we get from WhatsApp. May be changed anytime, use it with caution! It depends a lot on the underlying backend.',
|
||||
})
|
||||
_data?: any;
|
||||
}
|
||||
|
||||
export class WAWebhook {
|
||||
event: WAEvents
|
||||
session: string
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
payload: WAMessage | WAGroupNotification | object
|
||||
event: WAEvents;
|
||||
session: string;
|
||||
engine: WhatsappEngine;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
payload: WAMessage | WAGroupNotification | object;
|
||||
}
|
||||
@@ -1,14 +1,40 @@
|
||||
import {WhatsappStatus} from "./enums.dto";
|
||||
import { WhatsappStatus } from './enums.dto';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
/**
|
||||
* Queries
|
||||
*/
|
||||
export class ListSessionsQuery {
|
||||
@ApiProperty({
|
||||
example: false,
|
||||
required: false,
|
||||
description:
|
||||
'Return all sessions, including those that are in the STOPPED state.',
|
||||
})
|
||||
all: boolean;
|
||||
}
|
||||
/**
|
||||
* Requests
|
||||
*/
|
||||
export class SessionStartRequest {
|
||||
name = "default"
|
||||
name = 'default';
|
||||
}
|
||||
|
||||
export class SessionStopRequest {
|
||||
name = "default"
|
||||
name = 'default';
|
||||
@ApiProperty({
|
||||
example: false,
|
||||
required: false,
|
||||
description: 'Stop and logout from the session.',
|
||||
})
|
||||
logout = false;
|
||||
}
|
||||
|
||||
export class SessionLogoutRequest {
|
||||
name = 'default';
|
||||
}
|
||||
|
||||
export class SessionDTO {
|
||||
name = "default"
|
||||
status: WhatsappStatus
|
||||
name = 'default';
|
||||
status: WhatsappStatus;
|
||||
}
|
||||
+19
-19
@@ -1,34 +1,34 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
import {getBrowserExecutablePath} from "./core/abc/session.abc";
|
||||
import { getBrowserExecutablePath } from './core/abc/session.abc';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const fs = require('fs')
|
||||
const fs = require('fs');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const path = require('path');
|
||||
|
||||
export enum WAHAVersion {
|
||||
PLUS = "PLUS",
|
||||
CORE = "CORE",
|
||||
PLUS = 'PLUS',
|
||||
CORE = 'CORE',
|
||||
}
|
||||
|
||||
export function getWAHAVersion(): WAHAVersion {
|
||||
// force core version if env variables set
|
||||
const waha_version = process.env.WAHA_VERSION;
|
||||
if (waha_version && waha_version === WAHAVersion.CORE) {
|
||||
return WAHAVersion.CORE
|
||||
}
|
||||
// force core version if env variables set
|
||||
const waha_version = process.env.WAHA_VERSION;
|
||||
if (waha_version && waha_version === WAHAVersion.CORE) {
|
||||
return WAHAVersion.CORE;
|
||||
}
|
||||
|
||||
// Check the plus directory exists
|
||||
const plusExists = fs.existsSync(`${__dirname}/plus`)
|
||||
if (plusExists) {
|
||||
return WAHAVersion.PLUS
|
||||
}
|
||||
// Check the plus directory exists
|
||||
const plusExists = fs.existsSync(`${__dirname}/plus`);
|
||||
if (plusExists) {
|
||||
return WAHAVersion.PLUS;
|
||||
}
|
||||
|
||||
return WAHAVersion.CORE
|
||||
return WAHAVersion.CORE;
|
||||
}
|
||||
|
||||
export const VERSION = {
|
||||
version: "2023.5.3",
|
||||
tier: getWAHAVersion(),
|
||||
browser: getBrowserExecutablePath()
|
||||
}
|
||||
version: '2023.6.1',
|
||||
tier: getWAHAVersion(),
|
||||
browser: getBrowserExecutablePath(),
|
||||
};
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
|
||||
"@adiwajshing/baileys@file:../WhiskeySockets-Baileys":
|
||||
version "5.0.0"
|
||||
version "6.0.1"
|
||||
dependencies:
|
||||
"@hapi/boom" "^9.1.3"
|
||||
axios "^1.3.3"
|
||||
@@ -927,6 +927,26 @@
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
|
||||
|
||||
"@puppeteer/browsers@1.3.0":
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.3.0.tgz#5ad26540ff54e8b8fca8ab50d2da9c60360a21b9"
|
||||
integrity sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==
|
||||
dependencies:
|
||||
debug "4.3.4"
|
||||
extract-zip "2.0.1"
|
||||
http-proxy-agent "5.0.0"
|
||||
https-proxy-agent "5.0.1"
|
||||
progress "2.0.3"
|
||||
proxy-from-env "1.1.0"
|
||||
tar-fs "2.1.1"
|
||||
unbzip2-stream "1.4.3"
|
||||
yargs "17.7.1"
|
||||
|
||||
"@sindresorhus/is@^0.14.0":
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
|
||||
integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
|
||||
|
||||
"@sinonjs/commons@^1.7.0":
|
||||
version "1.8.6"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9"
|
||||
@@ -941,6 +961,13 @@
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.0"
|
||||
|
||||
"@szmarczak/http-timer@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
|
||||
integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==
|
||||
dependencies:
|
||||
defer-to-connect "^1.0.1"
|
||||
|
||||
"@tokenizer/token@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276"
|
||||
@@ -951,6 +978,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
||||
|
||||
"@tootallnate/once@2":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
|
||||
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
|
||||
|
||||
"@tsconfig/node10@^1.0.7":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
|
||||
@@ -1141,6 +1173,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
||||
|
||||
"@types/lodash@^4.14.194":
|
||||
version "4.14.194"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.194.tgz#b71eb6f7a0ff11bff59fc987134a093029258a76"
|
||||
integrity sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==
|
||||
|
||||
"@types/long@^4.0.0", "@types/long@^4.0.1":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
|
||||
@@ -1156,10 +1193,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
|
||||
integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
|
||||
|
||||
"@types/node@*", "@types/node@^18.14.2":
|
||||
version "18.14.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.2.tgz#c076ed1d7b6095078ad3cf21dfeea951842778b1"
|
||||
integrity sha512-1uEQxww3DaghA0RxqHx0O0ppVlo43pJhepY51OxuQIKHpjbnYLA7vcdwioNPzIqmC2u3I/dmylcqjlh0e7AyUA==
|
||||
"@types/node@*":
|
||||
version "20.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.1.tgz#de559d4b33be9a808fd43372ccee822c70f39704"
|
||||
integrity sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg==
|
||||
|
||||
"@types/node@>=13.7.0":
|
||||
version "18.15.5"
|
||||
@@ -1171,6 +1208,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b"
|
||||
integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==
|
||||
|
||||
"@types/node@^18.14.2":
|
||||
version "18.14.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.2.tgz#c076ed1d7b6095078ad3cf21dfeea951842778b1"
|
||||
integrity sha512-1uEQxww3DaghA0RxqHx0O0ppVlo43pJhepY51OxuQIKHpjbnYLA7vcdwioNPzIqmC2u3I/dmylcqjlh0e7AyUA==
|
||||
|
||||
"@types/normalize-package-data@^2.4.0":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
|
||||
@@ -1277,15 +1319,15 @@
|
||||
semver "^7.3.2"
|
||||
tsutils "^3.17.1"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^5.44.0":
|
||||
version "5.56.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.56.0.tgz#e4fbb4d6dd8dab3e733485c1a44a02189ae75364"
|
||||
integrity sha512-ZNW37Ccl3oMZkzxrYDUX4o7cnuPgU+YrcaYXzsRtLB16I1FR5SHMqga3zGsaSliZADCWo2v8qHWqAYIj8nWCCg==
|
||||
"@typescript-eslint/eslint-plugin@^5.48.2":
|
||||
version "5.59.6"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.6.tgz#a350faef1baa1e961698240f922d8de1761a9e2b"
|
||||
integrity sha512-sXtOgJNEuRU5RLwPUb1jxtToZbgvq3M6FPpY4QENxoOggK+UpTxUBpj6tD8+Qh2g46Pi9We87E+eHnUw8YcGsw==
|
||||
dependencies:
|
||||
"@eslint-community/regexpp" "^4.4.0"
|
||||
"@typescript-eslint/scope-manager" "5.56.0"
|
||||
"@typescript-eslint/type-utils" "5.56.0"
|
||||
"@typescript-eslint/utils" "5.56.0"
|
||||
"@typescript-eslint/scope-manager" "5.59.6"
|
||||
"@typescript-eslint/type-utils" "5.59.6"
|
||||
"@typescript-eslint/utils" "5.59.6"
|
||||
debug "^4.3.4"
|
||||
grapheme-splitter "^1.0.4"
|
||||
ignore "^5.2.0"
|
||||
@@ -1333,21 +1375,21 @@
|
||||
"@typescript-eslint/types" "5.53.0"
|
||||
"@typescript-eslint/visitor-keys" "5.53.0"
|
||||
|
||||
"@typescript-eslint/scope-manager@5.56.0":
|
||||
version "5.56.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.56.0.tgz#62b4055088903b5254fa20403010e1c16d6ab725"
|
||||
integrity sha512-jGYKyt+iBakD0SA5Ww8vFqGpoV2asSjwt60Gl6YcO8ksQ8s2HlUEyHBMSa38bdLopYqGf7EYQMUIGdT/Luw+sw==
|
||||
"@typescript-eslint/scope-manager@5.59.6":
|
||||
version "5.59.6"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.6.tgz#d43a3687aa4433868527cfe797eb267c6be35f19"
|
||||
integrity sha512-gLbY3Le9Dxcb8KdpF0+SJr6EQ+hFGYFl6tVY8VxLPFDfUZC7BHFw+Vq7bM5lE9DwWPfx4vMWWTLGXgpc0mAYyQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "5.56.0"
|
||||
"@typescript-eslint/visitor-keys" "5.56.0"
|
||||
"@typescript-eslint/types" "5.59.6"
|
||||
"@typescript-eslint/visitor-keys" "5.59.6"
|
||||
|
||||
"@typescript-eslint/type-utils@5.56.0":
|
||||
version "5.56.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.56.0.tgz#e6f004a072f09c42e263dc50e98c70b41a509685"
|
||||
integrity sha512-8WxgOgJjWRy6m4xg9KoSHPzBNZeQbGlQOH7l2QEhQID/+YseaFxg5J/DLwWSsi9Axj4e/cCiKx7PVzOq38tY4A==
|
||||
"@typescript-eslint/type-utils@5.59.6":
|
||||
version "5.59.6"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.6.tgz#37c51d2ae36127d8b81f32a0a4d2efae19277c48"
|
||||
integrity sha512-A4tms2Mp5yNvLDlySF+kAThV9VTBPCvGf0Rp8nl/eoDX9Okun8byTKoj3fJ52IJitjWOk0fKPNQhXEB++eNozQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree" "5.56.0"
|
||||
"@typescript-eslint/utils" "5.56.0"
|
||||
"@typescript-eslint/typescript-estree" "5.59.6"
|
||||
"@typescript-eslint/utils" "5.59.6"
|
||||
debug "^4.3.4"
|
||||
tsutils "^3.21.0"
|
||||
|
||||
@@ -1361,10 +1403,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.53.0.tgz#f79eca62b97e518ee124086a21a24f3be267026f"
|
||||
integrity sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A==
|
||||
|
||||
"@typescript-eslint/types@5.56.0":
|
||||
version "5.56.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.56.0.tgz#b03f0bfd6fa2afff4e67c5795930aff398cbd834"
|
||||
integrity sha512-JyAzbTJcIyhuUhogmiu+t79AkdnqgPUEsxMTMc/dCZczGMJQh1MK2wgrju++yMN6AWroVAy2jxyPcPr3SWCq5w==
|
||||
"@typescript-eslint/types@5.59.6":
|
||||
version "5.59.6"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.6.tgz#5a6557a772af044afe890d77c6a07e8c23c2460b"
|
||||
integrity sha512-tH5lBXZI7T2MOUgOWFdVNUILsI02shyQvfzG9EJkoONWugCG77NDDa1EeDGw7oJ5IvsTAAGVV8I3Tk2PNu9QfA==
|
||||
|
||||
"@typescript-eslint/typescript-estree@3.9.1":
|
||||
version "3.9.1"
|
||||
@@ -1393,30 +1435,30 @@
|
||||
semver "^7.3.7"
|
||||
tsutils "^3.21.0"
|
||||
|
||||
"@typescript-eslint/typescript-estree@5.56.0":
|
||||
version "5.56.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.56.0.tgz#48342aa2344649a03321e74cab9ccecb9af086c3"
|
||||
integrity sha512-41CH/GncsLXOJi0jb74SnC7jVPWeVJ0pxQj8bOjH1h2O26jXN3YHKDT1ejkVz5YeTEQPeLCCRY0U2r68tfNOcg==
|
||||
"@typescript-eslint/typescript-estree@5.59.6":
|
||||
version "5.59.6"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.6.tgz#2fb80522687bd3825504925ea7e1b8de7bb6251b"
|
||||
integrity sha512-vW6JP3lMAs/Tq4KjdI/RiHaaJSO7IUsbkz17it/Rl9Q+WkQ77EOuOnlbaU8kKfVIOJxMhnRiBG+olE7f3M16DA==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "5.56.0"
|
||||
"@typescript-eslint/visitor-keys" "5.56.0"
|
||||
"@typescript-eslint/types" "5.59.6"
|
||||
"@typescript-eslint/visitor-keys" "5.59.6"
|
||||
debug "^4.3.4"
|
||||
globby "^11.1.0"
|
||||
is-glob "^4.0.3"
|
||||
semver "^7.3.7"
|
||||
tsutils "^3.21.0"
|
||||
|
||||
"@typescript-eslint/utils@5.56.0":
|
||||
version "5.56.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.56.0.tgz#db64705409b9a15546053fb4deb2888b37df1f41"
|
||||
integrity sha512-XhZDVdLnUJNtbzaJeDSCIYaM+Tgr59gZGbFuELgF7m0IY03PlciidS7UQNKLE0+WpUTn1GlycEr6Ivb/afjbhA==
|
||||
"@typescript-eslint/utils@5.59.6":
|
||||
version "5.59.6"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.6.tgz#82960fe23788113fc3b1f9d4663d6773b7907839"
|
||||
integrity sha512-vzaaD6EXbTS29cVH0JjXBdzMt6VBlv+hE31XktDRMX1j3462wZCJa7VzO2AxXEXcIl8GQqZPcOPuW/Z1tZVogg==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.2.0"
|
||||
"@types/json-schema" "^7.0.9"
|
||||
"@types/semver" "^7.3.12"
|
||||
"@typescript-eslint/scope-manager" "5.56.0"
|
||||
"@typescript-eslint/types" "5.56.0"
|
||||
"@typescript-eslint/typescript-estree" "5.56.0"
|
||||
"@typescript-eslint/scope-manager" "5.59.6"
|
||||
"@typescript-eslint/types" "5.59.6"
|
||||
"@typescript-eslint/typescript-estree" "5.59.6"
|
||||
eslint-scope "^5.1.1"
|
||||
semver "^7.3.7"
|
||||
|
||||
@@ -1435,12 +1477,12 @@
|
||||
"@typescript-eslint/types" "5.53.0"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@typescript-eslint/visitor-keys@5.56.0":
|
||||
version "5.56.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.56.0.tgz#f19eb297d972417eb13cb69b35b3213e13cc214f"
|
||||
integrity sha512-1mFdED7u5bZpX6Xxf5N9U2c18sb+8EvU3tyOIj6LQZ5OOvnmj8BVeNNP603OFPm5KkS1a7IvCIcwrdHXaEMG/Q==
|
||||
"@typescript-eslint/visitor-keys@5.59.6":
|
||||
version "5.59.6"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.6.tgz#673fccabf28943847d0c8e9e8d008e3ada7be6bb"
|
||||
integrity sha512-zEfbFLzB9ETcEJ4HZEEsCR9HHeNku5/Qw1jSS5McYJv5BR+ftYXwFFAH5Al+xkGaZEqowMwl7uoJjQb1YSPF8Q==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "5.56.0"
|
||||
"@typescript-eslint/types" "5.59.6"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@webassemblyjs/ast@1.11.1":
|
||||
@@ -1564,10 +1606,10 @@
|
||||
"@webassemblyjs/ast" "1.11.1"
|
||||
"@xtuc/long" "4.2.2"
|
||||
|
||||
"@wppconnect/wa-js@^2.16.2":
|
||||
version "2.22.2"
|
||||
resolved "https://registry.yarnpkg.com/@wppconnect/wa-js/-/wa-js-2.22.2.tgz#c0eb1c7c3bfc55bbcafc27359d782925e9301d30"
|
||||
integrity sha512-WhkQZUg/u7drmst4Kpl1juw7AD2kj+i/eyY0tbbPtBfBjqO4LJfTLpta06clgxr7Oj1Cm/I+Jv9lSZKQva5lqw==
|
||||
"@wppconnect/wa-js@^2.19.1":
|
||||
version "2.24.1"
|
||||
resolved "https://registry.yarnpkg.com/@wppconnect/wa-js/-/wa-js-2.24.1.tgz#7a6453d4d46772d3a58f9e9fd7727c105d53ad0d"
|
||||
integrity sha512-SFn8tld9A30SufD/2Wrwj9heMjOE4jid53vALBia/4G1c0xPhlYazRl8Xb42gVgzssI2G70P8DOv9mbhb0/O+w==
|
||||
|
||||
"@xtuc/ieee754@^1.2.0":
|
||||
version "1.2.0"
|
||||
@@ -2276,6 +2318,19 @@ cache-base@^1.0.1:
|
||||
union-value "^1.0.0"
|
||||
unset-value "^1.0.0"
|
||||
|
||||
cacheable-request@^6.0.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912"
|
||||
integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==
|
||||
dependencies:
|
||||
clone-response "^1.0.2"
|
||||
get-stream "^5.1.0"
|
||||
http-cache-semantics "^4.0.0"
|
||||
keyv "^3.0.0"
|
||||
lowercase-keys "^2.0.0"
|
||||
normalize-url "^4.1.0"
|
||||
responselike "^1.0.2"
|
||||
|
||||
cachedir@2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8"
|
||||
@@ -2441,6 +2496,13 @@ chrome-trace-event@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
|
||||
integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
|
||||
|
||||
chromium-bidi@0.4.9:
|
||||
version "0.4.9"
|
||||
resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.4.9.tgz#a1c6d7497e2b8ae3d639fd69dacb25025fa0a696"
|
||||
integrity sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==
|
||||
dependencies:
|
||||
mitt "3.0.0"
|
||||
|
||||
ci-info@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
|
||||
@@ -2523,6 +2585,15 @@ cliui@^6.0.0:
|
||||
strip-ansi "^6.0.0"
|
||||
wrap-ansi "^6.2.0"
|
||||
|
||||
cliui@^8.0.1:
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
|
||||
integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
|
||||
dependencies:
|
||||
string-width "^4.2.0"
|
||||
strip-ansi "^6.0.1"
|
||||
wrap-ansi "^7.0.0"
|
||||
|
||||
clone-deep@^0.2.4:
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.2.4.tgz#4e73dd09e9fb971cc38670c5dced9c1896481cc6"
|
||||
@@ -2534,6 +2605,13 @@ clone-deep@^0.2.4:
|
||||
lazy-cache "^1.0.3"
|
||||
shallow-clone "^0.1.2"
|
||||
|
||||
clone-response@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3"
|
||||
integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==
|
||||
dependencies:
|
||||
mimic-response "^1.0.0"
|
||||
|
||||
clone@2.x:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
|
||||
@@ -2635,7 +2713,7 @@ commander@^2.20.0:
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
|
||||
commitizen@^4.0.3, commitizen@^4.2.5:
|
||||
commitizen@^4.0.3, commitizen@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/commitizen/-/commitizen-4.3.0.tgz#0d056c542a2d2b1f9b9aba981aa32575b2849924"
|
||||
integrity sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw==
|
||||
@@ -2763,6 +2841,16 @@ cosmiconfig-typescript-loader@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.3.0.tgz#c4259ce474c9df0f32274ed162c0447c951ef073"
|
||||
integrity sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==
|
||||
|
||||
cosmiconfig@8.1.3:
|
||||
version "8.1.3"
|
||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.1.3.tgz#0e614a118fcc2d9e5afc2f87d53cd09931015689"
|
||||
integrity sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==
|
||||
dependencies:
|
||||
import-fresh "^3.2.1"
|
||||
js-yaml "^4.1.0"
|
||||
parse-json "^5.0.0"
|
||||
path-type "^4.0.0"
|
||||
|
||||
cosmiconfig@^7.0.1:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
|
||||
@@ -2940,6 +3028,13 @@ decode-uri-component@^0.2.0:
|
||||
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
|
||||
integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
|
||||
|
||||
decompress-response@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
|
||||
integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==
|
||||
dependencies:
|
||||
mimic-response "^1.0.0"
|
||||
|
||||
decompress-response@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
|
||||
@@ -2974,6 +3069,11 @@ defaults@^1.0.3:
|
||||
dependencies:
|
||||
clone "^1.0.2"
|
||||
|
||||
defer-to-connect@^1.0.1:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
|
||||
integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
|
||||
|
||||
define-properties@^1.1.3, define-properties@^1.1.4:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5"
|
||||
@@ -3053,10 +3153,10 @@ detect-newline@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
|
||||
integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
|
||||
|
||||
devtools-protocol@0.0.1001819:
|
||||
version "0.0.1001819"
|
||||
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1001819.tgz#0a98f44cefdb02cc684f3d5e6bd898a1690231d9"
|
||||
integrity sha512-G6OsIFnv/rDyxSqBa2lDLR6thp9oJioLsb2Gl+LbQlyoA9/OBAkrTU9jiCcQ8Pnh7z4d6slDiLaogR5hzgJLmQ==
|
||||
devtools-protocol@0.0.1120988:
|
||||
version "0.0.1120988"
|
||||
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz#8fe49088919ae3b8df7235774633763f1f925066"
|
||||
integrity sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==
|
||||
|
||||
devtools-protocol@0.0.981744:
|
||||
version "0.0.981744"
|
||||
@@ -3387,6 +3487,11 @@ escodegen@^2.0.0:
|
||||
optionalDependencies:
|
||||
source-map "~0.6.1"
|
||||
|
||||
eslint-config-eslint@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-eslint/-/eslint-config-eslint-7.0.0.tgz#8161cd98f584df04a64322440b05875dd9cbbbd8"
|
||||
integrity sha512-gxUttladfTQaJKmSh9jbrN4Qba27yYBVwp0YsaOqjEWtOZYtc+MOgoWFh2x4Ewxjqr8sZZS1yTguXgoktzXOvQ==
|
||||
|
||||
eslint-config-prettier@^6.10.0:
|
||||
version "6.15.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz#7f93f6cb7d45a92f1537a70ecc06366e1ac6fed9"
|
||||
@@ -3498,6 +3603,11 @@ eslint@7.7.0:
|
||||
text-table "^0.2.0"
|
||||
v8-compile-cache "^2.0.3"
|
||||
|
||||
esm@^3.2.25:
|
||||
version "3.2.25"
|
||||
resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
|
||||
integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
|
||||
|
||||
espree@^7.2.0:
|
||||
version "7.3.1"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6"
|
||||
@@ -4070,7 +4180,7 @@ fs.realpath@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||
|
||||
fsevents@^2.1.2, fsevents@^2.2.1, fsevents@~2.3.2:
|
||||
fsevents@^2.1.2, fsevents@~2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||
@@ -4120,7 +4230,7 @@ gensync@^1.0.0-beta.2:
|
||||
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
||||
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
|
||||
|
||||
get-caller-file@^2.0.1:
|
||||
get-caller-file@^2.0.1, get-caller-file@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
||||
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
||||
@@ -4149,7 +4259,7 @@ get-stream@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
|
||||
integrity sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==
|
||||
|
||||
get-stream@^4.0.0:
|
||||
get-stream@^4.0.0, get-stream@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
|
||||
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
|
||||
@@ -4299,7 +4409,29 @@ got@^6.7.1:
|
||||
unzip-response "^2.0.1"
|
||||
url-parse-lax "^1.0.0"
|
||||
|
||||
graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
|
||||
got@^9.6.0:
|
||||
version "9.6.0"
|
||||
resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
|
||||
integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==
|
||||
dependencies:
|
||||
"@sindresorhus/is" "^0.14.0"
|
||||
"@szmarczak/http-timer" "^1.1.2"
|
||||
cacheable-request "^6.0.0"
|
||||
decompress-response "^3.3.0"
|
||||
duplexer3 "^0.1.4"
|
||||
get-stream "^4.1.0"
|
||||
lowercase-keys "^1.0.1"
|
||||
mimic-response "^1.0.1"
|
||||
p-cancelable "^1.0.0"
|
||||
to-readable-stream "^1.0.0"
|
||||
url-parse-lax "^3.0.0"
|
||||
|
||||
graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2:
|
||||
version "4.2.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
||||
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||
|
||||
graceful-fs@^4.2.4, graceful-fs@^4.2.9:
|
||||
version "4.2.10"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
|
||||
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
|
||||
@@ -4438,6 +4570,11 @@ htmlparser2@^8.0.1:
|
||||
domutils "^3.0.1"
|
||||
entities "^4.4.0"
|
||||
|
||||
http-cache-semantics@^4.0.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
|
||||
integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
|
||||
|
||||
http-errors@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
|
||||
@@ -4449,6 +4586,15 @@ http-errors@2.0.0:
|
||||
statuses "2.0.1"
|
||||
toidentifier "1.0.1"
|
||||
|
||||
http-proxy-agent@5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43"
|
||||
integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==
|
||||
dependencies:
|
||||
"@tootallnate/once" "2"
|
||||
agent-base "6"
|
||||
debug "4"
|
||||
|
||||
http-proxy-agent@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a"
|
||||
@@ -5507,6 +5653,11 @@ jsesc@^2.5.1:
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
|
||||
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
|
||||
|
||||
json-buffer@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
|
||||
integrity sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==
|
||||
|
||||
json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
|
||||
@@ -5578,6 +5729,13 @@ jsqr@^1.3.1:
|
||||
resolved "https://registry.yarnpkg.com/jsqr/-/jsqr-1.4.0.tgz#8efb8d0a7cc6863cb6d95116b9069123ce9eb2d1"
|
||||
integrity sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A==
|
||||
|
||||
keyv@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
|
||||
integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==
|
||||
dependencies:
|
||||
json-buffer "3.0.0"
|
||||
|
||||
kind-of@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5"
|
||||
@@ -5626,6 +5784,13 @@ latest-lib@^0.2.1:
|
||||
dependencies:
|
||||
got "^6.7.1"
|
||||
|
||||
latest-version@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face"
|
||||
integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==
|
||||
dependencies:
|
||||
package-json "^6.3.0"
|
||||
|
||||
lazy-cache@^0.2.3:
|
||||
version "0.2.7"
|
||||
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65"
|
||||
@@ -5841,11 +6006,16 @@ longest@^2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/longest/-/longest-2.0.1.tgz#781e183296aa94f6d4d916dc335d0d17aefa23f8"
|
||||
integrity sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==
|
||||
|
||||
lowercase-keys@^1.0.0:
|
||||
lowercase-keys@^1.0.0, lowercase-keys@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
|
||||
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
|
||||
|
||||
lowercase-keys@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
|
||||
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
|
||||
|
||||
lru-cache@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
||||
@@ -6038,6 +6208,11 @@ mimic-fn@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
||||
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
|
||||
|
||||
mimic-response@^1.0.0, mimic-response@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
|
||||
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
|
||||
|
||||
mimic-response@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
|
||||
@@ -6074,6 +6249,11 @@ minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6:
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
|
||||
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
|
||||
|
||||
mitt@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.0.tgz#69ef9bd5c80ff6f57473e8d89326d01c414be0bd"
|
||||
integrity sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==
|
||||
|
||||
mixin-deep@^1.2.0:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
|
||||
@@ -6243,13 +6423,20 @@ node-fetch@2.6.7:
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-fetch@^2.6.1, node-fetch@^2.6.5:
|
||||
node-fetch@^2.6.1:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6"
|
||||
integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-fetch@^2.6.5:
|
||||
version "2.6.11"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25"
|
||||
integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-int64@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
|
||||
@@ -6273,9 +6460,9 @@ node-releases@^2.0.8:
|
||||
integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==
|
||||
|
||||
node-webpmux@^3.1.0:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/node-webpmux/-/node-webpmux-3.1.5.tgz#b2aab8ab8277e81638d670e035bb6369036c7250"
|
||||
integrity sha512-yfZBMbISp425P8TGKEh2vrOafRBOatwQqiDYDQrEddBYork6gpKPXHbqSU3bOmoIc2fEJ8p+IXiqa1OP+mZPhg==
|
||||
version "3.1.7"
|
||||
resolved "https://registry.yarnpkg.com/node-webpmux/-/node-webpmux-3.1.7.tgz#7dc96bdf7daed96311f0f5a4dba2664633002593"
|
||||
integrity sha512-ySkL4lBCto86OyQ0blAGzylWSECcn5I0lM3bYEhe75T8Zxt/BFUMHa8ktUguR7zwXNdS/Hms31VfSsYKN1383g==
|
||||
|
||||
normalize-package-data@^2.5.0:
|
||||
version "2.5.0"
|
||||
@@ -6299,6 +6486,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
||||
|
||||
normalize-url@^4.1.0:
|
||||
version "4.5.1"
|
||||
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a"
|
||||
integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==
|
||||
|
||||
npm-run-path@^2.0.0:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
|
||||
@@ -6487,6 +6679,11 @@ os-tmpdir@~1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||
integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==
|
||||
|
||||
p-cancelable@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"
|
||||
integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==
|
||||
|
||||
p-each-series@^2.1.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a"
|
||||
@@ -6523,6 +6720,16 @@ p-try@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
|
||||
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
|
||||
|
||||
package-json@^6.3.0:
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0"
|
||||
integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==
|
||||
dependencies:
|
||||
got "^9.6.0"
|
||||
registry-auth-token "^4.0.0"
|
||||
registry-url "^5.0.0"
|
||||
semver "^6.2.0"
|
||||
|
||||
parent-module@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
|
||||
@@ -6757,6 +6964,11 @@ prepend-http@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
|
||||
integrity sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==
|
||||
|
||||
prepend-http@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
|
||||
integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==
|
||||
|
||||
prettier@^1.19.1:
|
||||
version "1.19.1"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
|
||||
@@ -6884,48 +7096,60 @@ punycode@^2.1.0, punycode@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
|
||||
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
|
||||
|
||||
puppeteer-extra-plugin-stealth@^2.11.1:
|
||||
version "2.11.1"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer-extra-plugin-stealth/-/puppeteer-extra-plugin-stealth-2.11.1.tgz#7d56a27a986cb5eb69dca3c65695ad6444f4e822"
|
||||
integrity sha512-n0wdC0Ilc9tk5L6FWLyd0P2gT8b2fp+2NuB+KB0oTSw3wXaZ0D6WNakjJsayJ4waGzIJFCUHkmK9zgx5NKMoFw==
|
||||
puppeteer-core@20.2.1:
|
||||
version "20.2.1"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-20.2.1.tgz#e920e06e76ef2d1a1d98ea847611a8d662d3cd97"
|
||||
integrity sha512-HmNMcL+g9ght0nCzS5BmEvom2IVhp1/xhlQ9O+fmihQx0EYwYUqgCQhs8Hbv7IapiqKhahKCC8PKfCNTXXsKbQ==
|
||||
dependencies:
|
||||
"@puppeteer/browsers" "1.3.0"
|
||||
chromium-bidi "0.4.9"
|
||||
cross-fetch "3.1.5"
|
||||
debug "4.3.4"
|
||||
devtools-protocol "0.0.1120988"
|
||||
ws "8.13.0"
|
||||
|
||||
puppeteer-extra-plugin-stealth@^2.11.2:
|
||||
version "2.11.2"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer-extra-plugin-stealth/-/puppeteer-extra-plugin-stealth-2.11.2.tgz#bd3f5a1781cac8a98c983d148086585a84fcc8f1"
|
||||
integrity sha512-bUemM5XmTj9i2ZerBzsk2AN5is0wHMNE6K0hXBzBXOzP5m5G3Wl0RHhiqKeHToe/uIH8AoZiGhc1tCkLZQPKTQ==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
puppeteer-extra-plugin "^3.2.2"
|
||||
puppeteer-extra-plugin-user-preferences "^2.4.0"
|
||||
puppeteer-extra-plugin "^3.2.3"
|
||||
puppeteer-extra-plugin-user-preferences "^2.4.1"
|
||||
|
||||
puppeteer-extra-plugin-user-data-dir@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer-extra-plugin-user-data-dir/-/puppeteer-extra-plugin-user-data-dir-2.4.0.tgz#20e87582482b61e497abd96fec452f63bd2d9123"
|
||||
integrity sha512-qrhYPTGIqzL2hpeJ5DXjf8xMy5rt1UvcqSgpGTTOUOjIMz1ROWnKHjBoE9fNBJ4+ToRZbP8MzIDXWlEk/e1zJA==
|
||||
puppeteer-extra-plugin-user-data-dir@^2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer-extra-plugin-user-data-dir/-/puppeteer-extra-plugin-user-data-dir-2.4.1.tgz#4ea9d56d20455672a54fe086309a102a5126411c"
|
||||
integrity sha512-kH1GnCcqEDoBXO7epAse4TBPJh9tEpVEK/vkedKfjOVOhZAvLkHGc9swMs5ChrJbRnf8Hdpug6TJlEuimXNQ+g==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
fs-extra "^10.0.0"
|
||||
puppeteer-extra-plugin "^3.2.2"
|
||||
puppeteer-extra-plugin "^3.2.3"
|
||||
rimraf "^3.0.2"
|
||||
|
||||
puppeteer-extra-plugin-user-preferences@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer-extra-plugin-user-preferences/-/puppeteer-extra-plugin-user-preferences-2.4.0.tgz#8b75bc39c3de9913e236ae1d982a24711d84ba6f"
|
||||
integrity sha512-4XxMhMkJ+qqLsPY9ULF90qS9Bj1Qrwwgp1TY9zTdp1dJuy7QSgYE7xlyamq3cKrRuzg3QUOqygJo52sVeXSg5A==
|
||||
puppeteer-extra-plugin-user-preferences@^2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer-extra-plugin-user-preferences/-/puppeteer-extra-plugin-user-preferences-2.4.1.tgz#db8ec63c04a6a10a8f8997e15fdffdf13272161d"
|
||||
integrity sha512-i1oAZxRbc1bk8MZufKCruCEC3CCafO9RKMkkodZltI4OqibLFXF3tj6HZ4LZ9C5vCXZjYcDWazgtY69mnmrQ9A==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
deepmerge "^4.2.2"
|
||||
puppeteer-extra-plugin "^3.2.2"
|
||||
puppeteer-extra-plugin-user-data-dir "^2.4.0"
|
||||
puppeteer-extra-plugin "^3.2.3"
|
||||
puppeteer-extra-plugin-user-data-dir "^2.4.1"
|
||||
|
||||
puppeteer-extra-plugin@^3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer-extra-plugin/-/puppeteer-extra-plugin-3.2.2.tgz#3c02c0a10f8eadf32e7debb7ee24105a53afc17b"
|
||||
integrity sha512-0uatQxzuVn8yegbrEwSk03wvwpMB5jNs7uTTnermylLZzoT+1rmAQaJXwlS3+vADUbw6ELNgNEHC7Skm0RqHbQ==
|
||||
puppeteer-extra-plugin@^3.2.3:
|
||||
version "3.2.3"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer-extra-plugin/-/puppeteer-extra-plugin-3.2.3.tgz#50c9f0749c005bbc7b8b208bcd00a9d46a15b585"
|
||||
integrity sha512-6RNy0e6pH8vaS3akPIKGg28xcryKscczt4wIl0ePciZENGE2yoaQJNd17UiEbdmh5/6WW6dPcfRWT9lxBwCi2Q==
|
||||
dependencies:
|
||||
"@types/debug" "^4.1.0"
|
||||
debug "^4.1.1"
|
||||
merge-deep "^3.0.1"
|
||||
|
||||
puppeteer-extra@^3.2.3:
|
||||
version "3.3.4"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer-extra/-/puppeteer-extra-3.3.4.tgz#e0ecf021783d1112b6b0db20546d5022e632ed55"
|
||||
integrity sha512-fN5pHvSMJ8d1o7Z8wLLTQOUBpORD2BcFn+KDs7QnkGZs9SV69hcUcce67vX4L4bNSEG3A0P6Osrv+vWNhhdm8w==
|
||||
puppeteer-extra@^3.3.6:
|
||||
version "3.3.6"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer-extra/-/puppeteer-extra-3.3.6.tgz#fc16ff396aae52664842da9a557ea8fa51eaa8b7"
|
||||
integrity sha512-rsLBE/6mMxAjlLd06LuGacrukP2bqbzKCLzV1vrhHFavqQE/taQ2UXv3H5P0Ls7nsrASa+6x3bDbXHpqMwq+7A==
|
||||
dependencies:
|
||||
"@types/debug" "^4.1.0"
|
||||
debug "^4.1.1"
|
||||
@@ -6949,23 +7173,14 @@ puppeteer@^13.0.0:
|
||||
unbzip2-stream "1.4.3"
|
||||
ws "8.5.0"
|
||||
|
||||
puppeteer@^14.4.1:
|
||||
version "14.4.1"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-14.4.1.tgz#6c7437a65f7ba98ef8ad7c2b0f1cf808e91617bb"
|
||||
integrity sha512-+H0Gm84aXUvSLdSiDROtLlOofftClgw2TdceMvvCU9UvMryappoeS3+eOLfKvoy4sm8B8MWnYmPhWxVFudAOFQ==
|
||||
puppeteer@^20.0.0:
|
||||
version "20.2.1"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-20.2.1.tgz#e68d92731a5edae90620ad6209292f1c377eef3b"
|
||||
integrity sha512-XWHlNCJf1u+i5AzakXj1PlNOTYcFcAwAunQj/urFKzKaZ7WTChlAo710W+TlEE2SJKshEZTwilMDDkVvwadLTQ==
|
||||
dependencies:
|
||||
cross-fetch "3.1.5"
|
||||
debug "4.3.4"
|
||||
devtools-protocol "0.0.1001819"
|
||||
extract-zip "2.0.1"
|
||||
https-proxy-agent "5.0.1"
|
||||
pkg-dir "4.2.0"
|
||||
progress "2.0.3"
|
||||
proxy-from-env "1.1.0"
|
||||
rimraf "3.0.2"
|
||||
tar-fs "2.1.1"
|
||||
unbzip2-stream "1.4.3"
|
||||
ws "8.7.0"
|
||||
"@puppeteer/browsers" "1.3.0"
|
||||
cosmiconfig "8.1.3"
|
||||
puppeteer-core "20.2.1"
|
||||
|
||||
qrcode-terminal@^0.12.0:
|
||||
version "0.12.0"
|
||||
@@ -7036,7 +7251,7 @@ raw-body@2.5.1:
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
rc@^1.2.7:
|
||||
rc@1.2.8, rc@^1.2.7, rc@^1.2.8:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
|
||||
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
|
||||
@@ -7089,9 +7304,9 @@ readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.1.tgz#f9f9b5f536920253b3d26e7660e7da4ccff9bb62"
|
||||
integrity sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==
|
||||
version "3.6.2"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
|
||||
integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
|
||||
dependencies:
|
||||
inherits "^2.0.3"
|
||||
string_decoder "^1.1.1"
|
||||
@@ -7105,9 +7320,9 @@ readable-web-to-node-stream@^3.0.0:
|
||||
readable-stream "^3.6.0"
|
||||
|
||||
readdir-glob@^1.0.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.2.tgz#b185789b8e6a43491635b6953295c5c5e3fd224c"
|
||||
integrity sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584"
|
||||
integrity sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==
|
||||
dependencies:
|
||||
minimatch "^5.1.0"
|
||||
|
||||
@@ -7157,6 +7372,20 @@ regexpp@^3.0.0, regexpp@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
|
||||
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
|
||||
|
||||
registry-auth-token@^4.0.0:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.2.tgz#f02d49c3668884612ca031419491a13539e21fac"
|
||||
integrity sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==
|
||||
dependencies:
|
||||
rc "1.2.8"
|
||||
|
||||
registry-url@^5.0.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009"
|
||||
integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==
|
||||
dependencies:
|
||||
rc "^1.2.8"
|
||||
|
||||
remove-trailing-separator@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
|
||||
@@ -7273,6 +7502,13 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.18.1, resolve@^1.22.1:
|
||||
path-parse "^1.0.7"
|
||||
supports-preserve-symlinks-flag "^1.0.0"
|
||||
|
||||
responselike@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
|
||||
integrity sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==
|
||||
dependencies:
|
||||
lowercase-keys "^1.0.0"
|
||||
|
||||
restore-cursor@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
|
||||
@@ -7447,7 +7683,7 @@ semver@7.x, semver@^7.2.1, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7:
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@^6.0.0, semver@^6.3.0:
|
||||
semver@^6.0.0, semver@^6.2.0, semver@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
@@ -7846,7 +8082,7 @@ string-width@^3.0.0:
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^5.1.0"
|
||||
|
||||
string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2:
|
||||
string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
@@ -8166,6 +8402,11 @@ to-object-path@^0.3.0:
|
||||
dependencies:
|
||||
kind-of "^3.0.2"
|
||||
|
||||
to-readable-stream@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771"
|
||||
integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==
|
||||
|
||||
to-regex-range@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
|
||||
@@ -8517,9 +8758,9 @@ unzip-response@^2.0.1:
|
||||
integrity sha512-N0XH6lqDtFH84JxptQoZYmloF4nzrQqqrAymNj+/gW60AO2AZgOcf4O/nUXJcYfyQkqvMo9lSupBZmmgvuVXlw==
|
||||
|
||||
unzipper@^0.10.11:
|
||||
version "0.10.11"
|
||||
resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.11.tgz#0b4991446472cbdb92ee7403909f26c2419c782e"
|
||||
integrity sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==
|
||||
version "0.10.14"
|
||||
resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.14.tgz#d2b33c977714da0fbc0f82774ad35470a7c962b1"
|
||||
integrity sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==
|
||||
dependencies:
|
||||
big-integer "^1.6.17"
|
||||
binary "~0.3.0"
|
||||
@@ -8559,6 +8800,13 @@ url-parse-lax@^1.0.0:
|
||||
dependencies:
|
||||
prepend-http "^1.0.1"
|
||||
|
||||
url-parse-lax@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c"
|
||||
integrity sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==
|
||||
dependencies:
|
||||
prepend-http "^2.0.0"
|
||||
|
||||
url-parse@^1.5.3:
|
||||
version "1.5.10"
|
||||
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1"
|
||||
@@ -8647,33 +8895,37 @@ vary@^1, vary@~1.1.2:
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
||||
|
||||
venom-bot@^4.3.7:
|
||||
version "4.3.7"
|
||||
resolved "https://registry.yarnpkg.com/venom-bot/-/venom-bot-4.3.7.tgz#1d1f7a92a21bc2a63e9cafb4b6b5d1944c0354e8"
|
||||
integrity sha512-mWCp6rpABiO6D+IgHeGvwzO/+HqsVu7YZg5buQLQW5GnadzbLhIh56h3JloCumaubbiDQDo5+Eu/sDnqp1hMnQ==
|
||||
venom-bot@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/venom-bot/-/venom-bot-5.0.1.tgz#6a30b0bca5a86d9469c89d958c42fc015046a4b0"
|
||||
integrity sha512-asuEJh5scm9e/lgqhcI7UfqppOO7OJTvr1Tsr+n2jJyFWB9Bg3UHYelbeZn57oGWv+kupdbnOkV/cSc7IPhr7A==
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin" "^5.44.0"
|
||||
"@typescript-eslint/eslint-plugin" "^5.48.2"
|
||||
"@typescript-eslint/parser" "^5.44.0"
|
||||
"@wppconnect/wa-js" "^2.16.2"
|
||||
"@wppconnect/wa-js" "^2.19.1"
|
||||
atob "^2.1.2"
|
||||
axios "^1.2.0"
|
||||
boxen "^5.1.1"
|
||||
catch-exit "^1.1.0"
|
||||
chalk "^4.0.0"
|
||||
chrome-launcher "^0.15.1"
|
||||
commitizen "^4.2.5"
|
||||
commitizen "^4.3.0"
|
||||
compressorjs "^1.1.1"
|
||||
cz-conventional-changelog "^3.3.0"
|
||||
dotenv "^16.0.1"
|
||||
eslint-config-eslint "^7.0.0"
|
||||
esm "^3.2.25"
|
||||
eventemitter2 "^6.4.7"
|
||||
futoin-hkdf "^1.5.1"
|
||||
i "^0.3.7"
|
||||
latest-lib "^0.2.1"
|
||||
latest-version "^5.1.0"
|
||||
mime-types "^2.1.35"
|
||||
ora "^6.1.2"
|
||||
puppeteer "^14.4.1"
|
||||
puppeteer-extra "^3.2.3"
|
||||
puppeteer-extra-plugin-stealth "^2.11.1"
|
||||
puppeteer "^20.0.0"
|
||||
puppeteer-extra "^3.3.6"
|
||||
puppeteer-extra-plugin-stealth "^2.11.2"
|
||||
qrcode "^1.5.1"
|
||||
qrcode-terminal "^0.12.0"
|
||||
sanitize-filename "^1.6.3"
|
||||
sharp "^0.30.7"
|
||||
@@ -8684,8 +8936,6 @@ venom-bot@^4.3.7:
|
||||
winston "^3.8.0"
|
||||
ws "^8.8.0"
|
||||
yoo-hoo "^1.2.0"
|
||||
optionalDependencies:
|
||||
fsevents "^2.2.1"
|
||||
|
||||
verror@1.10.0:
|
||||
version "1.10.0"
|
||||
@@ -8798,8 +9048,8 @@ webpack@5.75.0:
|
||||
webpack-sources "^3.2.3"
|
||||
|
||||
"whatsapp-web.js@https://github.com/pedroslopez/whatsapp-web.js":
|
||||
version "1.19.5"
|
||||
resolved "https://github.com/pedroslopez/whatsapp-web.js#d8fd4579143624384004c1f966bb1d92f0a69036"
|
||||
version "1.20.0"
|
||||
resolved "https://github.com/pedroslopez/whatsapp-web.js#915763a8d04c37c2ddcb93faa512cfe208f1798e"
|
||||
dependencies:
|
||||
"@pedroslopez/moduleraid" "^5.0.2"
|
||||
fluent-ffmpeg "^2.1.2"
|
||||
@@ -8974,26 +9224,21 @@ write@1.0.3:
|
||||
dependencies:
|
||||
mkdirp "^0.5.1"
|
||||
|
||||
ws@8.13.0, ws@^8.0.0:
|
||||
version "8.13.0"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0"
|
||||
integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==
|
||||
|
||||
ws@8.5.0:
|
||||
version "8.5.0"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
|
||||
integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==
|
||||
|
||||
ws@8.7.0:
|
||||
version "8.7.0"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.7.0.tgz#eaf9d874b433aa00c0e0d8752532444875db3957"
|
||||
integrity sha512-c2gsP0PRwcLFzUiA8Mkr37/MI7ilIlHQxaEAtd0uNMbVMoy8puJyafRlm0bV9MbGSabUPeLrRRaqIBcFcA2Pqg==
|
||||
|
||||
ws@^7.4.6:
|
||||
version "7.5.9"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"
|
||||
integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==
|
||||
|
||||
ws@^8.0.0:
|
||||
version "8.13.0"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0"
|
||||
integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==
|
||||
|
||||
ws@^8.8.0:
|
||||
version "8.12.1"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.1.tgz#c51e583d79140b5e42e39be48c934131942d4a8f"
|
||||
@@ -9019,6 +9264,11 @@ y18n@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
|
||||
integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==
|
||||
|
||||
y18n@^5.0.5:
|
||||
version "5.0.8"
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
|
||||
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
|
||||
|
||||
yallist@^3.0.2:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||
@@ -9042,11 +9292,24 @@ yargs-parser@18.x, yargs-parser@^18.1.2:
|
||||
camelcase "^5.0.0"
|
||||
decamelize "^1.2.0"
|
||||
|
||||
yargs-parser@21.1.1:
|
||||
yargs-parser@21.1.1, yargs-parser@^21.1.1:
|
||||
version "21.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
|
||||
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
|
||||
|
||||
yargs@17.7.1:
|
||||
version "17.7.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967"
|
||||
integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==
|
||||
dependencies:
|
||||
cliui "^8.0.1"
|
||||
escalade "^3.1.1"
|
||||
get-caller-file "^2.0.5"
|
||||
require-directory "^2.1.1"
|
||||
string-width "^4.2.3"
|
||||
y18n "^5.0.5"
|
||||
yargs-parser "^21.1.1"
|
||||
|
||||
yargs@^15.3.1, yargs@^15.4.1:
|
||||
version "15.4.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
|
||||
|
||||
Reference in new issue
Block a user